#include <QtGui>
#include "edtimeline.h"


QEDTimelineTrackDisplay::QEDTimelineTrackDisplay(QWidget *parent) : QWidget(parent)
{
    track = NULL;
    time = offs = 0;
    scale = 1.0f;
    
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
}


QSize QEDTimelineTrackDisplay::minimumSizeHint() const
{
    return QSize(100, 60);
}


QSize QEDTimelineTrackDisplay::sizeHint() const
{
    return QSize(600, 60);
}


void QEDTimelineTrackDisplay::setTrack(DMTimelineTrack *mtrack)
{
    track = mtrack;
}


float QEDTimelineTrackDisplay::getTimeScale(float value)
{
    return value * scale;
}


float QEDTimelineTrackDisplay::getTimeFromCoord(float value)
{
    return value * scale * 1000.0f;
}


void QEDTimelineTrackDisplay::setTime(const float mtime)
{
    if (time != mtime && mtime >= 0)
    {
        time = mtime;
        emit timeChanged(time);
    }
}


void QEDTimelineTrackDisplay::setOffset(const float moffs)
{
    if (offs != moffs && moffs >= 0)
    {
        offs = moffs;
        emit offsetChanged(offs);
    }
}


void QEDTimelineTrackDisplay::setScale(const float mscale)
{
    if (mscale > 0.05)
        scale = mscale;
}


void QEDTimelineTrackDisplay::setSelection(const float mstart, const float mend)
{
    if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0)
    {
        selectionValid = true;
        if (mend > mstart)
        {
            selectionStart    = mstart;
            selectionDuration = mend - mstart + 1;
        }
        else
        {
            selectionStart    = mend;
            selectionDuration = mstart - mend + 1;
        }
        emit selectionChanged(selectionStart, selectionDuration);
    }
}


void QEDTimelineTrackDisplay::clearSelection()
{
    selectionValid    = false;
    selectionStart    = 0;
    selectionDuration = 0;
    emit selectionChanged(selectionStart, selectionDuration);
}


bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration)
{
    if (selectionValid)
    {
        *mstart = selectionStart;
        *mduration = selectionDuration;
    }
    return selectionValid;
}


QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsAt(const int time)
{
    QList<DMTimelineEvent *> list;

    for (int event = 0; event < track->nevents; event++)
    {
        DMTimelineEvent *ev = track->events[event];
        if (time >= ev->start && time <= ev->start + ev->duration)
            list.append(ev);
    }

    return list;
}



QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsForRange(const int start, const int duration)
{
    QList<DMTimelineEvent *> list;

    for (int event = 0; event < track->nevents; event++)
    {
        DMTimelineEvent *ev = track->events[event];
    }

    return list;
}


void QEDTimelineTrackDisplay::paintEvent(QPaintEvent *)
{
    if (track == NULL)
        return;

    QColor eventColor(150, 150, 150, 128);
    QColor invalidEventColor(250, 150, 150, 128);
    QColor eventBorder(200, 250, 200, 200);
    QColor eventParam(200, 150, 100);
    QColor eventText(255, 255, 255);
    QColor markerColor(255,255,255);
    QColor selectionColor(0,255,0, 150);
    QColor selectionEnd(0,255,0, 200);

    QFont fantti;
    fantti.setFamily("Arial");
    fantti.setPointSizeF(8.0f);
    fantti.setStyleHint(QFont::SansSerif);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);


    painter.save();
    painter.scale(scale, 1);

    float wd = getTimeScale(width());
    for (int event = 0; event < track->nevents; event++)
    {
        DMTimelineEvent *ev = track->events[event];

        float x0 = getTimeScale(ev->start - offs),
              x1 = getTimeScale(ev->start + ev->duration - offs);

        if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0))
        {
            painter.setFont(fantti);
            painter.setBrush(ev->effect != NULL ? eventColor : invalidEventColor);
            painter.setPen(eventBorder);
            x0 = ev->start - offs;
            x1 = ev->duration;
            painter.fillRect(x0, 0, x1, height(), eventColor);

            QPainterPath path;
            path.addText(QPointF(x0 + 2, 10), fantti, ev->effect != NULL ? QString(ev->effect->name) : "INVALID");

            painter.save();
            painter.translate(1,1);
            painter.setPen(Qt::black);
            painter.setBrush(Qt::black);
            painter.drawPath(path);
            painter.restore();

            painter.setPen(eventText);
            painter.setBrush(eventText);
            painter.drawPath(path);
        }

    }

    painter.restore();

    if (selectionValid)
    {
        float x0 = getTimeScale(selectionStart - offs),
              x1 = getTimeScale(selectionStart + selectionDuration - offs);

        if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0))
        {
            painter.setBrush(selectionColor);
            painter.setPen(selectionEnd);
            x0 = selectionStart - offs;
            x1 = selectionDuration;
            painter.fillRect(x0, 0, x1, height(), eventColor);
            
            painter.drawLine(x0, 0, x0, height());
            painter.drawLine(x1, 0, x1, height());
        }
    }


    if (time >= offs * scale && time - offs <= width() * scale)
    {
        int xc = time - offs;
        painter.save();
        painter.scale(scale, 1);
        painter.setPen(markerColor);
        painter.drawLine(xc, 0, xc, height());
        painter.restore();
    }
}


void QEDTimelineTrackDisplay::mousePressEvent(QMouseEvent *ev)
{
    switch (ev->button())
    {
        case Qt::LeftButton:
            if (parent->getActiveTrack() != this)
                emit trackActivated(this);

            selectionPoint = ev->pos();
            selectionOffs = offs / scale;
            selecting = false;
            break;

        case Qt::RightButton:
            dragPoint = ev->pos();
            dragOffs = offs / scale;
            dragging = false;
            break;

        default:
            break;
    }
}


void QEDTimelineTrackDisplay::mouseMoveEvent(QMouseEvent *ev)
{
    if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selectionPoint.x())
    {
        selecting = true;
        setSelection(selectionOffs, offs + (ev->pos().x() - selectionPoint.x()) / scale);
    }
    if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x())
    {
        dragging = true;
        setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale);
    }
}


void QEDTimelineTrackDisplay::mouseReleaseEvent(QMouseEvent *ev)
{
    if (ev->button() == Qt::LeftButton)
    {
        if (selecting)
        {
            selecting = false;
            setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale);
        }
    }
    else
    if (ev->button() == Qt::RightButton && !dragging)
    {
        setTime(offs + getTimeFromCoord(ev->pos().x()));
    }
}


QEDTimelineTrackView::QEDTimelineTrackView(QWidget *parent) : QWidget(parent)
{
    QHBoxLayout *mainLayout = new QHBoxLayout(this);
    mainLayout->setMargin(0);
    track = new QEDTimelineTrackDisplay(this);

    QFrame *infoLayoutContainer = new QFrame(this);
    infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
    infoLayoutContainer->setLineWidth(2);
    infoLayoutContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
    infoLayoutContainer->setFixedWidth(200);

    QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer);
    infoLayout->setMargin(0);
    infoName = new QLineEdit();
    infoName->setFrame(false);
    infoName->setMaxLength(DT_MAX_NAME_LENGTH);
    infoName->setStyleSheet("QLineEdit { background-color: black; color: white; padding: 2px; }");
    connect(infoName, SIGNAL(textEdited(const QString&)), this, SLOT(slotTrackNameChanged(const QString&)));
    infoLayout->addWidget(infoName);


    enabledCheck = new QCheckBox("Enabled");
    infoLayout->addWidget(enabledCheck);
    connect(enabledCheck, SIGNAL(toggled(bool)), this, SLOT(slotTrackEnabledChanged(bool)));
    
    infoData = new QLabel();
    infoData->setStyleSheet("QLabel { padding: 2px; }");
    infoLayout->addWidget(infoData);

    mainLayout->addWidget(infoLayoutContainer);
    mainLayout->addWidget(track);
}


void QEDTimelineTrackView::update()
{
    if (track != NULL && track->track)
    {
        infoName->setText(QString(track->track->name));
        enabledCheck->setChecked(track->track->enabled);
        infoData->setText(QString("<b>%1</b> events").arg(track->track->nevents));
    }
    else
    {
        infoName->setText("");
        infoData->setText("-");
        enabledCheck->setChecked(false);
    }

    QWidget::update();
}


void QEDTimelineTrackView::setTrack(DMTimelineTrack *mtrack)
{
    track->setTrack(mtrack);
    update();
}


void QEDTimelineTrackView::slotTrackEnabledChanged(bool value)
{
    track->track->enabled = value;
    emit trackChanged();
}


void QEDTimelineTrackView::slotTrackNameChanged(const QString & text)
{
    QByteArray ba = text.toUtf8();
    track->track->name = dm_strdup(ba.constData());
    emit trackChanged();
}



QEDTimelineView::QEDTimelineView(QWidget *parent) : QWidget(parent)
{
    layout = new QVBoxLayout(this);
    tl = NULL;
}


void QEDTimelineView::setTimeline(EDTimelineObject *mtl)
{
    tl = mtl;

    delete layout;
    layout = new QVBoxLayout(this);
    layout->setMargin(0);
    
    tracks.clear();

    if (tl != NULL && tl->tl != NULL)
    {
        for (int track = 0; track < tl->tl->ntracks; track++)
        {
            QEDTimelineTrackView *vtr = new QEDTimelineTrackView(this);
            vtr->setTrack(tl->tl->tracks[track]);
            tracks.append(vtr);
            layout->addWidget(vtr);
            connect(vtr, SIGNAL(trackChanged()), this, SLOT(slotTimelineChanged()));
            connect(vtr, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float)));
            connect(vtr, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float)));
            connect(vtr, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float)));
        }
    }
    update();
}


void QEDTimelineView::slotTimelineChanged()
{
    if (tl != NULL)
    {
        tl->touch();
        emit timelineChanged();
    }
}


void QEDTimelineView::setTime(const int mtime)
{
    if (tl != NULL && tl->tl != NULL)
    {
        QList<QEDTimelineTrackView *>::iterator track;
        for (track = tracks.begin(); track != tracks.end(); track++)
        {
            (*track)->track->setTime(mtime);
        }
        update();
    }
}


void QEDTimelineView::setOffset(const int moffs)
{
    if (tl != NULL && tl->tl != NULL)
    {
        QList<QEDTimelineTrackView *>::iterator track;
        for (track = tracks.begin(); track != tracks.end(); track++)
        {
            (*track)->track->setOffset(moffs);
        }
        update();
    }
}


void QEDTimelineView::setScale(const float mscale)
{
    if (tl != NULL && tl->tl != NULL)
    {
        QList<QEDTimelineTrackView *>::iterator track;
        for (track = tracks.begin(); track != tracks.end(); track++)
        {
            (*track)->track->setScale(mscale);
        }
        update();
    }
}


QList<DMTimelineEvent *> QEDTimelineView::getEventsAt(const int time)
{
    if (tl != NULL && tl->tl != NULL &&
        activeTrack >= 0 && activeTrack < tl->tl->ntracks)
    {
        return tracks[activeTrack]->tl->getEventsAt(time);
    }
    else
        return QList<DMTimelineEvent *>();
}


QList<DMTimelineEvent *> QEDTimelineView::getEventsForRange(const int start, const int duration)
{
}

