/***************************************************************************
    File                 : CanvasPicker.cpp
    Project              : SciDAVis
    --------------------------------------------------------------------
    Copyright            : (C) 2006,2007 by Ion Vasilief,
                           Tilman Benkert, Knut Franke
    Email (use @ for *)  : ion_vasilief*yahoo.fr, thzs*gmx.net
                           knut.franke*gmx.de
    Description          : Canvas picker

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  This program is free software; you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation; either version 2 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 *   Boston, MA  02110-1301  USA                                           *
 *                                                                         *
 ***************************************************************************/
#include "CanvasPicker.h"
#include "ImageMarker.h"
#include "Legend.h"
#include "ArrowMarker.h"

#include <QVector>
#include <QMouseEvent>

#include <qwt_text_label.h>
#include <qwt_plot_canvas.h>

CanvasPicker::CanvasPicker(Graph *graph) : QObject(graph)
{
    pointSelected = false;
    d_editing_marker = 0;

    plotWidget = graph->plotWidget();

    QwtPlotCanvas *canvas = plotWidget->canvas();
    canvas->installEventFilter(this);
}

bool CanvasPicker::eventFilter(QObject *object, QEvent *e)
{
    QVector<int> images = plot()->imageMarkerKeys();
    QVector<int> texts = plot()->textMarkerKeys();
    QVector<int> lines = plot()->lineMarkerKeys();

    if (object != (QObject *)plot()->plotWidget()->canvas())
        return false;

    switch (e->type()) {
    case QEvent::MouseButtonPress: {
        emit selectPlot();

        const QMouseEvent *me = (const QMouseEvent *)e;

        if (me->button() == Qt::LeftButton && (plot()->drawLineActive())) {
            startLinePoint = me->pos();
            return true;
        }

        if (me->button() == Qt::LeftButton && plot()->drawTextActive()) {
            drawTextMarker(me->pos());
            return true;
        }

        if (!plot()->zoomOn() && selectMarker(me)) {
            if (me->button() == Qt::RightButton)
                emit showMarkerPopupMenu();
            return true;
        }

        if (d_editing_marker) {
            d_editing_marker->setEditable(false);
            d_editing_marker = 0;
        }

        if (plot()->markerSelected())
            plot()->deselectMarker();

        return !(me->modifiers() & Qt::ShiftModifier);
    } break;

    case QEvent::MouseButtonDblClick: {
        if (d_editing_marker) {
            return d_editing_marker->eventFilter(plotWidget->canvas(), e);
        } else if (plot()->selectedMarkerKey() >= 0) {
            if (texts.contains(plot()->selectedMarkerKey())) {
                emit viewTextDialog();
                return true;
            } else if (lines.contains(plot()->selectedMarkerKey())) {
                emit viewLineDialog();
                return true;
            } else if (images.contains(plot()->selectedMarkerKey())) {
                emit viewImageDialog();
                return true;
            }
        } else if (plot()->isPiePlot()) {
            emit showPlotDialog(plot()->curveKey(0));
            return true;
        } else {
            const QMouseEvent *me = (const QMouseEvent *)e;
            int dist, point;
            int curveKey = plotWidget->closestCurve(me->pos().x(), me->pos().y(), dist, point);
            if (dist < 10)
                emit showPlotDialog(curveKey);
            else
                emit showPlotDialog(-1);
            return true;
        }
    } break;

    case QEvent::MouseMove: {
        const QMouseEvent *me = (const QMouseEvent *)e;
        if (me->buttons() != Qt::LeftButton)
            return true;

        QPoint pos = me->pos();

        if (plot()->drawLineActive()) {
            drawLineMarker(pos, plot()->drawArrow());
            return true;
        }

        return false;
    } break;

    case QEvent::MouseButtonRelease: {
        const QMouseEvent *me = (const QMouseEvent *)e;
        Graph *g = plot();

        if (g->drawLineActive()) {
            ArrowMarker mrk;
            mrk.attach(g->plotWidget());
            mrk.setStartPoint(startLinePoint);
            mrk.setEndPoint(QPoint(me->x(), me->y()));
            mrk.setColor(g->arrowDefaultColor());
            mrk.setWidth(g->arrowDefaultWidth());
            mrk.setStyle(g->arrowLineDefaultStyle());
            mrk.setHeadLength(g->arrowHeadDefaultLength());
            mrk.setHeadAngle(g->arrowHeadDefaultAngle());
            mrk.fillArrowHead(g->arrowHeadDefaultFill());
            mrk.drawEndArrow(g->drawArrow());
            mrk.drawStartArrow(false);

            g->addArrow(&mrk);
            g->drawLine(false);
            mrk.detach();
            plotWidget->replot();

            return true;
        }
        return false;
    } break;

    case QEvent::KeyPress: {
        int key = ((const QKeyEvent *)e)->key();

        long selectedMarker = plot()->selectedMarkerKey();
        if (texts.contains(selectedMarker) && (key == Qt::Key_Enter || key == Qt::Key_Return)) {
            emit viewTextDialog();
            return true;
        }
        if (lines.contains(selectedMarker) && (key == Qt::Key_Enter || key == Qt::Key_Return)) {
            emit viewLineDialog();
            return true;
        }
        if (images.contains(selectedMarker) && (key == Qt::Key_Enter || key == Qt::Key_Return)) {
            emit viewImageDialog();
            return true;
        }
    } break;

    default:
        break;
    }
    return QObject::eventFilter(object, e);
}

void CanvasPicker::disableEditing()
{
    if (d_editing_marker) {
        d_editing_marker->setEditable(false);
        d_editing_marker = 0;
    }
}

void CanvasPicker::drawTextMarker(const QPoint &point)
{
    Legend mrkT(plotWidget);
    mrkT.setOrigin(point);
    mrkT.setFrameStyle(plot()->textMarkerDefaultFrame());
    mrkT.setFont(plot()->defaultTextMarkerFont());
    mrkT.setTextColor(plot()->textMarkerDefaultColor());
    mrkT.setBackgroundColor(plot()->textMarkerDefaultBackground());
    mrkT.setText(tr("enter your text here"));
    plot()->insertTextMarker(&mrkT);
    plot()->drawText(false);
    emit drawTextOff();
}

void CanvasPicker::drawLineMarker(const QPoint &point, bool endArrow)
{
    plot()->plotWidget()->canvas()->repaint();
    ArrowMarker mrk;
    mrk.attach(plotWidget);

    int clw = plotWidget->canvas()->lineWidth();
    mrk.setStartPoint(QPoint(startLinePoint.x() + clw, startLinePoint.y() + clw));
    mrk.setEndPoint(QPoint(point.x() + clw, point.y() + clw));
    mrk.setWidth(1);
    mrk.setStyle(Qt::SolidLine);
    mrk.drawEndArrow(endArrow);
    mrk.drawStartArrow(false);

    if (plot()->drawLineActive())
        mrk.setColor(Qt::black);
    else
        mrk.setColor(Qt::red);

    plotWidget->replot();
    mrk.detach();
}

bool CanvasPicker::selectMarker(const QMouseEvent *e)
{
    const QPoint point = e->pos();
    foreach (long i, plot()->textMarkerKeys()) {
        Legend *m = (Legend *)plotWidget->marker(i);
        if (!m)
            return false;
        if (m->rect().contains(point)) {
            if (d_editing_marker) {
                d_editing_marker->setEditable(false);
                d_editing_marker = 0;
            }
            plot()->setSelectedMarker(i, e->modifiers() & Qt::ShiftModifier);
            return true;
        }
    }
    foreach (long i, plot()->imageMarkerKeys()) {
        ImageMarker *m = (ImageMarker *)plotWidget->marker(i);
        if (!m)
            return false;
        if (m->rect().contains(point)) {
            if (d_editing_marker) {
                d_editing_marker->setEditable(false);
                d_editing_marker = 0;
            }
            plot()->setSelectedMarker(i, e->modifiers() & Qt::ShiftModifier);
            return true;
        }
    }
    foreach (long i, plot()->lineMarkerKeys()) {
        ArrowMarker *mrkL = (ArrowMarker *)plotWidget->marker(i);
        if (!mrkL)
            return false;
        int d = mrkL->width()
                + (int)floor(mrkL->headLength() * tan(M_PI * mrkL->headAngle() / 180.0) + 0.5);
        double dist = mrkL->dist(point.x(), point.y());
        if (dist <= d) {
            if (d_editing_marker) {
                d_editing_marker->setEditable(false);
                d_editing_marker = 0;
            }
            if (e->modifiers() & Qt::ShiftModifier) {
                plot()->setSelectedMarker(i, true);
                return true;
            } else if (e->button() == Qt::RightButton) {
                mrkL->setEditable(false);
                plot()->setSelectedMarker(i, false);
                return true;
            }
            plot()->deselectMarker();
            mrkL->setEditable(true);
            d_editing_marker = mrkL;
            return true;
        }
    }
    return false;
}
