/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQPlotView.h"

#include <QContextMenuEvent>
#include <QDebug>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QScrollBar>

#include "MvKeyProfile.h"

#include "MgQLayoutItem.h"
#include "MgQPlotScene.h"
#include "MgQRootItem.h"
#include "MvQAreaSelection.h"
#include "MvQLineSelection.h"
#include "MvQCursorData.h"
#include "MvQMagnifier.h"
#include "MvQPlaceMark.h"
#include "MvQPlaceMarkWidget.h"
#include "MvQPointSelection.h"
#include "MvQZoom.h"
#include "uPlotBase.h"

#define METVIEW_MULTIPAGE

MvQPlotView::MvQPlotView(QGraphicsScene* scene, QWidget* parent) :
    QGraphicsView(scene, parent)
{
    zoom_                    = 0;
    magnifier_               = 0;
    cursorData_              = 0;
    cursorDataProbe_         = 0;
    area_                    = 0;
    line_                    = 0;
    point_                   = 0;
    placeMark_               = 0;
    dataProbe_               = 0;
    placeMarkIsBeingCreated_ = false;
    sceneIsBeingSelected_    = false;

    plotScene_ = static_cast<MgQPlotScene*>(scene);

    resetTransform();
    //translate(0,height);
    scale(1., -1);

    setAcceptDrops(true);
}

MvQPlotView::~MvQPlotView()
{
}

void MvQPlotView::slotSetEnableZoom(bool flag)
{
    if (zoom_ && flag == zoom_->activated())
        return;

    if (flag == false) {
        if (!zoom_)
            return;
        else {
            zoom_->setActivated(false);
            unsetCursor();
        }
    }
    else {
        if (!zoom_) {
            zoom_ = new MvQZoom(plotScene_, this, 0);
            //zoom_->setVisible(true);
            zoom_->setZValue(2.5);
            plotScene_->addItem(zoom_);

            connect(zoom_, SIGNAL(zoomRectangleIsDefined(const string&, const string&)),
                    this, SIGNAL(zoomRectangleIsDefined(const string&, const string&)));

            connect(zoom_, SIGNAL(mousePressInSceneItem(MgQSceneItem*)),
                    this, SIGNAL(zoomActionStarted(MgQSceneItem*)));
        }

        zoom_->setActivated(true);
        emit magnifierIsEnabledProgramatically(false);
        emit inputSIsEnabledProgramatically(false);
        setCursor(QCursor(Qt::CrossCursor));
    }
}

void MvQPlotView::slotSetEnableMagnifier(bool flag)
{
    if (magnifier_ && flag == magnifier_->activated())
        return;

    if (flag == false) {
        if (!magnifier_)
            return;
        else {
            magnifier_->setActivated(false);
            //magnifier_->operationEnd();
        }
    }
    else {
        emit zoomIsEnabledProgramatically(false);
        if (!magnifier_) {
            magnifier_ = new MvQMagnifier(plotScene_, this, 0);
            //zoom_->setVisible(true);
            magnifier_->setZValue(1.5);
            plotScene_->addItem(magnifier_);

            connect(magnifier_, SIGNAL(factorChanged()),
                    this, SLOT(slotMagnifierChanged()));

            connect(magnifier_, SIGNAL(positionChanged()),
                    this, SLOT(slotMagnifierChanged()));
        }

        magnifier_->setActivated(true);
        //magnifier_->operationBegin();
    }

    slotMagnifierChanged();
}

void MvQPlotView::slotMagnifierChanged()
{
    if (!magnifier_)
        return;

    //Update dataprobe
    if (dataProbe_ && dataProbe_->activated()) {
        dataProbe_->setMagnifier(magnifier_);
    }
}

void MvQPlotView::slotSetEnableCursorData(bool flag)
{
    if (cursorData_ && flag == cursorData_->activated())
        return;

    if (flag == false) {
        if (!cursorData_)
            return;
        else {
            cursorData_->setActivated(false);
        }
    }
    else {
        if (!cursorData_) {
            cursorData_ = new MvQCursorData(plotScene_, this, 0);
            cursorData_->setVisible(true);
            cursorData_->setZValue(2.);
            plotScene_->addItem(cursorData_);

            connect(cursorData_, SIGNAL(positionChanged(QPointF, QList<ValuesCollector>)),
                    this, SIGNAL(cursorDataChanged(QPointF, QList<ValuesCollector>)));

            /*cursorDataProbe_=new MvQPlaceMark(plotScene_,this,0);
			cursorDataProbe_->setZValue(1.8);
			cursorDataProbe_->setActivated(false);
			
			connect(cursorData_,SIGNAL(probeEnabled(bool)),
				this,SLOT(slotEnableCursorDataProbe(bool)));
		
			plotScene_->addItem(cursorDataProbe_);	*/
        }

        cursorData_->setActivated(true);
    }
}

void MvQPlotView::slotEnableCursorDataProbe(bool /*b*/)
{
    //cursorDataProbe_->setActivated(b);
}

void MvQPlotView::slotSetEnableAreaSelection(bool flag)
{
    if (area_ && flag == area_->activated())
        return;

    if (flag == false) {
        if (!area_)
            return;
        else {
            area_->setActivated(false);
        }
    }
    else {
        if (!area_) {
            area_ = new MvQAreaSelection(plotScene_, this, 0);
            area_->setParentItem(plotScene_->annotationRootItem());
            area_->setZValue(2.);

            connect(area_, SIGNAL(areaIsDefined(double, double, double, double)),
                    this, SIGNAL(areaIsDefined(double, double, double, double)));

            connect(area_, SIGNAL(areaIsUndefined()),
                    this, SIGNAL(areaIsUndefined()));
        }

        area_->setActivated(true);
        emit magnifierIsEnabledProgramatically(false);
        emit zoomIsEnabledProgramatically(false);
    }
}
void MvQPlotView::slotChangeArea(double blLat, double blLon, double trLat, double trLon)
{
    if (!area_ || !area_->activated())
        return;

    area_->setArea(blLat, blLon, trLat, trLon);
}

void MvQPlotView::slotClearArea()
{
    if (!area_ || !area_->activated())
        return;

    area_->clearArea();
}

void MvQPlotView::slotSelectAllArea()
{
    if (!area_ || !area_->activated())
        return;

    area_->selectAllArea();
}

void MvQPlotView::slotSetEnableLineSelection(bool flag)
{
    if (line_ && flag == line_->activated())
        return;

    if (flag == false) {
        if (!line_)
            return;
        else {
            line_->setActivated(false);
        }
    }
    else {
        if (!line_) {
            line_ = new MvQLineSelection(plotScene_, this, 0);
            line_->setParentItem(plotScene_->annotationRootItem());
            line_->setZValue(2.);

            connect(line_, SIGNAL(lineIsDefined(double, double, double, double)),
                    this, SIGNAL(lineIsDefined(double, double, double, double)));

            connect(line_, SIGNAL(lineIsUndefined()),
                    this, SIGNAL(lineIsUndefined()));
        }

        line_->setActivated(true);
        emit magnifierIsEnabledProgramatically(false);
        emit zoomIsEnabledProgramatically(false);
    }
}
void MvQPlotView::slotChangeLine(double lat1, double lon1, double lat2, double lon2)
{
    if (!line_ || !line_->activated())
        return;

    line_->setLine(lat1, lon1, lat2, lon2);
}

void MvQPlotView::slotClearLine()
{
    if (!line_ || !line_->activated())
        return;

    line_->clearLine();
}
void MvQPlotView::slotChangeLineDirection()
{
    if (!line_ || !line_->activated())
        return;

    line_->changeDirection();
}

void MvQPlotView::slotSetEnablePointSelection(bool flag)
{
    if (point_ && flag == point_->activated())
        return;

    if (flag == false) {
        if (!point_)
            return;
        else {
            point_->setActivated(false);
        }
    }
    else {
        if (!point_) {
            point_ = new MvQPointSelection(plotScene_, this, 0);
            point_->setParentItem(plotScene_->annotationRootItem());
            point_->setZValue(2.);

            connect(point_, SIGNAL(pointIsDefined(double, double)),
                    this, SIGNAL(pointIsDefined(double, double)));

            connect(point_, SIGNAL(pointIsUndefined()),
                    this, SIGNAL(pointIsUndefined()));
        }

        point_->setActivated(true);
        emit magnifierIsEnabledProgramatically(false);
        emit zoomIsEnabledProgramatically(false);
    }
}
void MvQPlotView::slotChangePoint(double lat, double lon)
{
    if (!point_ || !point_->activated())
        return;

    point_->setPoint(lat, lon);
}

void MvQPlotView::slotClearPoint()
{
    if (!point_ || !point_->activated())
        return;

    point_->clearPoint();
}


void MvQPlotView::slotSelectScene()
{
    sceneIsBeingSelected_ = true;
    setCursor(Qt::PointingHandCursor);
}

void MvQPlotView::setDataProbe(MvQPlaceMark* p)
{
    dataProbe_ = p;
}

void MvQPlotView::slotCreatePlaceMark()
{
    placeMarkIsBeingCreated_ = true;
}

void MvQPlotView::setPlaceMark(MvQPlaceMarkWidget* p)
{
    placeMark_ = p;
}

/*void MvQPlotView::updatePlaceMarks()
{
	QList<MvQPlaceMarkNode*> vis=placeMark_->visibleNodes();

	foreach(MvQPlaceMarkNode)


	QMapIterator<MvQPlaceMarkNode*,MvQPlaceMark*> it(pmItem_);
	while (it.hasNext()) 
	{
     		it.next();
		if(!it.key()->isVisible())
		{
			pmItem[it.key()]=0;
			delete it.value();
		}
	}
	
	if()


}*/


void MvQPlotView::slotFrameProfileChanged(MvKeyProfile* prof)
{
#ifdef METVIEW_EXPERIMENTAL

    QPixmap defaultPixmap(QString::fromUtf8(":/uPlot/gunsight.svg"));

    int cnt = 0;
    for (int i = 0; i < static_cast<int>(prof->size()); i++) {
        QString s     = QString::fromStdString(prof->at(i)->name());
        QString sname = QString::fromStdString(prof->at(i)->shortName());

        if (s.startsWith("MV_Value")) {
            float xf = QString::fromStdString(prof->at(i)->metaData("x_coord")).toFloat();
            float yf = QString::fromStdString(prof->at(i)->metaData("y_coord")).toFloat();
#ifndef METVIEW_MULTIPAGE
            MgQLayoutItem* layout = plotScene_->projectorItem();
#else
            MgQLayoutItem* layout = 0;
#endif
            if (layout) {
                MvQPlaceMarkNode* pm = 0;
                if (cnt >= pointData_.count()) {
                    pm = new MvQPlaceMarkNode();
                }
                else {
                    pm = pointData_[cnt]->placeMark();
                }

                pm->setName(sname);
                QPointF pp(xf, yf);
                pm->setCoordinates(pp);
                pm->setPixmap(defaultPixmap);

                MvQPlaceMarkItem* item = 0;
                if (cnt >= pointData_.count()) {
                    item = new MvQPlaceMarkItem(pm, plotScene_, this, 0);
                    item->setParentItem(plotScene_->annotationRootItem());
                    item->setFlag(QGraphicsItem::ItemIgnoresTransformations);
                    item->setZValue(1.8);
                    item->setActivated(true);

                    plotScene_->addItem(item);
                }
                else {
                    item = pointData_[cnt];
                }

                item->setPixmapColour(QColor(QString::fromStdString(prof->at(i)->metaData("colour"))));
                item->reset();

                if (cnt >= pointData_.count()) {
                    pointData_ << item;
                }
            }
            cnt++;
        }
    }
#endif
}

void MvQPlotView::resetBegin()
{
    if (zoom_)
        zoom_->prepareForReset();
    if (magnifier_)
        magnifier_->prepareForReset();
    if (cursorData_)
        cursorData_->prepareForReset();
    if (area_)
        area_->prepareForReset();
    if (line_)
        line_->prepareForReset();
    if (point_)
        point_->prepareForReset();
    if (placeMark_)
        placeMark_->prepareForReset();
    if (dataProbe_)
        dataProbe_->prepareForReset();
}

void MvQPlotView::resetEnd()
{
    if (zoom_)
        zoom_->reset();
    if (magnifier_)
        magnifier_->reset();
    if (cursorData_)
        cursorData_->reset();
    if (area_)
        area_->reset();
    if (line_)
        line_->reset();
    if (point_)
        point_->reset();
    if (placeMark_)
        placeMark_->reset();
    if (dataProbe_)
        dataProbe_->reset();
}

void MvQPlotView::mousePressEvent(QMouseEvent* event)
{
    if (sceneIsBeingSelected_) {
        unsetCursor();

        sceneIsBeingSelected_ = false;
        QPointF sPos          = mapToScene(event->pos());
        emit sceneSelected(sPos);
        return;
    }


    if (placeMarkIsBeingCreated_) {
        placeMarkIsBeingCreated_ = false;
        QPointF sPos             = mapToScene(event->pos());
        placeMark_->createPlaceMark(sPos);
        unsetCursor();
        return;
    }

    MvQMagnifier::MagnifierAction magnifierAction = MvQMagnifier::NoAction;

    //Zoom and magnifier are exclusive!

    //First comes the zoom if it is active
    if (zoom_ && zoom_->activated()) {
        zoom_->mousePressEventFromView(event);
        return;
    }

    //Then we check if the dataProbe is selected
    if (dataProbe_ && dataProbe_->activated()) {
        //		QPointF pos = mapToScene(event->pos());
        dataProbe_->mousePressEventFromView(event);
        if (dataProbe_->currentAction() != MvQPlaceMark::NoAction) {
            return;
        }
    }

    //If there is no zoom and the dataProbe is not selected tries the magnifier
    if (magnifier_ && magnifier_->activated()) {
        magnifier_->mousePressEventFromView(event);
        magnifierAction = magnifier_->magnifierAction();
    }

    //We continuew with the ...

    //area selection
    if (area_ && area_->activated()) {
        area_->mousePressEventFromView(event);
    }
    //line selection
    else if (line_ && line_->activated()) {
        line_->mousePressEventFromView(event);
    }
    //point selection
    else if (point_ && point_->activated()) {
        point_->mousePressEventFromView(event);
    }
    //placemarks
    else if (placeMark_) {
        foreach (MvQPlaceMarkItem* m, placeMark_->placeMarks()) {
            m->mousePressEventFromView(event);
            if (m->currentAction() == MvQPlaceMarkItem::MoveAction) {
                break;
            }
        }
    }

    //Cursor data can be active both for zoom and magnifier.
    //If the mousepress event triggered some actions in the magnifier
    //then we ignore this event for the cursor data.
    if (cursorData_ && cursorData_->activated() &&
        magnifierAction == MvQMagnifier::NoAction &&
        (!zoom_ || zoom_->activated() == false)) {
        cursorData_->mousePressEventFromView(event);
    }
    else {
        QGraphicsView::mousePressEvent(event);
    }
}

void MvQPlotView::mouseMoveEvent(QMouseEvent* event)
{
    if (cursorData_ && cursorData_->activated()) {
        QPointF pos = mapToScene(event->pos());

        //If the cursor is inside tha magnifier cursor data has to
        //be notified know about the magnifier geometry.
        if (magnifier_ && magnifier_->activated() &&
            magnifier_->checkPointInMagnifier(pos)) {
            cursorData_->setMagnifierInfo(true, magnifier_->pos(), magnifier_->zoomFactor());
        }
        else {
            cursorData_->setMagnifierInfo(false);
        }

        cursorData_->mouseMoveEventFromView(event);
    }

    if (dataProbe_ && dataProbe_->activated() && dataProbe_->currentAction() == MvQPlaceMark::MoveAction) {
        //		QPointF pos = mapToScene(event->pos());
        dataProbe_->mouseMoveEventFromView(event);
        return;
    }

    if (zoom_ && zoom_->activated()) {
        zoom_->mouseMoveEventFromView(event);
    }
    else if (area_ && area_->activated()) {
        area_->mouseMoveEventFromView(event);
    }
    else if (line_ && line_->activated()) {
        line_->mouseMoveEventFromView(event);
    }
    else if (point_ && point_->activated()) {
        point_->mouseMoveEventFromView(event);
    }
    else if (magnifier_ && magnifier_->activated()) {
        magnifier_->mouseMoveEventFromView(event);
    }
    //else if(dataProbe_ && dataProbe_->activated())
    //{
    //	dataProbe_->mouseMoveEventFromView(event);
    //}
    else if (placeMark_) {
        foreach (MvQPlaceMarkItem* m, placeMark_->placeMarks()) {
            m->mouseMoveEventFromView(event);
            if (m->currentAction() == MvQPlaceMarkItem::MoveAction) {
                break;
            }
        }
    }
    else {
        QGraphicsView::mouseMoveEvent(event);
    }

    return;
}

void MvQPlotView::mouseReleaseEvent(QMouseEvent* event)
{
    bool zoomStatus = true;

    if (zoom_ && zoom_->activated()) {
        zoom_->mouseReleaseEventFromView(event);
        zoomStatus = zoom_->zoomWasPerformedAfterMouseRelease();
    }
    else if (area_ && area_->activated()) {
        area_->mouseReleaseEventFromView(event);
    }
    else if (line_ && line_->activated()) {
        line_->mouseReleaseEventFromView(event);
    }
    else if (point_ && point_->activated()) {
        point_->mouseReleaseEventFromView(event);
    }
    else if (dataProbe_ && dataProbe_->activated()) {
        dataProbe_->mouseReleaseEventFromView(event);
    }
    else if (placeMark_) {
        foreach (MvQPlaceMarkItem* m, placeMark_->placeMarks()) {
            m->mouseReleaseEventFromView(event);
        }
    }

    if (cursorData_ && cursorData_->activated()) {
        cursorData_->setZoomWasPerformedAfterMouseRelease(zoomStatus);
        cursorData_->mouseReleaseEventFromView(event);
    }
    if (magnifier_ && magnifier_->activated()) {
        magnifier_->mouseReleaseEventFromView(event);
    }
    else {
        QGraphicsView::mouseReleaseEvent(event);
    }

    return;
}

void MvQPlotView::DrawRectangle(double /*north*/, double /*west*/, double /*south*/, double /*east*/)
{
}

//===========================
// Drop from the new Desktop
//===========================

void MvQPlotView::dragEnterEvent(QDragEnterEvent* event)
{
    if ((event->proposedAction() == Qt::CopyAction ||
         event->proposedAction() == Qt::MoveAction)) {
        event->accept();
    }
}

void MvQPlotView::dragMoveEvent(QDragMoveEvent* event)
{
    if ((event->proposedAction() == Qt::CopyAction ||
         event->proposedAction() == Qt::MoveAction)) {
        event->accept();
    }
}

void MvQPlotView::dropEvent(QDropEvent* event)
{
    MvQDrop drop(event);

    if (drop.hasData()) {
        QPoint scrollOffset(horizontalScrollBar()->value(), verticalScrollBar()->value());
        emit iconDropped(drop, event->pos() + scrollOffset);

        event->accept();
        return;
    }

    event->ignore();
}

void MvQPlotView::contextMenuEvent(QContextMenuEvent* event)
{
    emit contextMenuEventHappened(event->globalPos(), mapToScene(event->pos()));
}

void MvQPlotView::resizeEvent(QResizeEvent* event)
{
    QGraphicsView::resizeEvent(event);
    emit resizeEventHappened(event->size());
}


void MvQPlotView::setMvPlotSize(double /*width*/, double /*height*/)
{
    //resetTransform();
    //translate(0,height);
    //scale(1.,-1);

    //setSceneRect(0,0,width*2,height*2);
}
