/***************************** 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 "MvQPlaceMark.h"

#include <QApplication>
#include <QDebug>
#include <QImage>
#include <QMouseEvent>
#include <QPainter>
#include <QStyle>

#include "MvQMagnifier.h"
#include "MvQPlotView.h"
#include "MgQPlotScene.h"
#include "MgQLayoutItem.h"

#include <assert.h>


#define METVIEW_MULTIPAGE

#if 0

MvQPlaceMarkNode::MvQPlaceMarkNode(Type type) :
    type_(type),
    visible_(true),
    outOfPlot_(false),
    parent_(0)
{
    if (type_ == FolderType) {
        QIcon icon(QApplication::style()->standardIcon(QStyle::SP_DirIcon));
        pix_ = icon.pixmap(22);
    }
    else {
        pix_ = QPixmap(QString::fromUtf8(":/uPlot/blue_dot"));
    }
}

void MvQPlaceMarkNode::setVisible(bool status)
{
    visible_ = status;
    foreach (MvQPlaceMarkNode* cn, children_) {
        cn->setVisible(status);
    }
}

void MvQPlaceMarkNode::setOutOfPlot(bool status)
{
    outOfPlot_ = status;
}

void MvQPlaceMarkNode::setCoordinates(QPointF& pt)
{
    coordinates_ = pt;
}

QIcon MvQPlaceMarkNode::icon()
{
    /*if(type_== FolderType)
	{
		return QIcon(QApplication::style()->standardIcon(QStyle::SP_DirIcon));
	}
	else
	{
		return QIcon(QPixmap(QString::fromUtf8(":/uPlot/blue_dot")));
	}*/
    return QIcon();
}

void MvQPlaceMarkNode::removeChild(MvQPlaceMarkNode* node)
{
    children_.removeOne(node);
}

void MvQPlaceMarkNode::removeChild(int i)
{
    if (i < 0 || i >= children_.count())
        return;

    children_.removeAt(i);
}

//==========================================
//
//  MvQPlaceMarkTree
//
//==========================================

void MvQPlaceMarkTree::moveNode(MvQPlaceMarkNode* node, MvQPlaceMarkNode* parent)
{
    if (!node || !parent)
        return;

    node->parent()->removeChild(node);
    parent->addChild(node);
}

//==========================================
//
//  MvQPlaceMarkItem
//
//==========================================

MvQPlaceMarkItem::MvQPlaceMarkItem(MvQPlaceMarkNode* pm, MgQPlotScene* scene, MvQPlotView* view, QGraphicsItem* parent) :
    MvQPlotItem(scene, view, parent)
{
    pm_ = pm;

    //if(!pm_)
    //	return;

    currentAction_ = NoAction;
    dataLayout_    = 0;

    if (pm_)
        pix_ = QPixmap::fromImage(pm_->pixmap().toImage().mirrored(false, true));
    //pix_=QPixmap::fromImage(img.mirrored(false,true));

    anchor_ = CentreAnchor;

    if (anchor_ == BottomCentreAnchor)
        boundingRect_ = QRectF(-pix_.width() / 2., 0, pix_.width(), pix_.height());
    else
        boundingRect_ = QRectF(-pix_.width() / 2., -pix_.height() / 2., pix_.width(), pix_.height());


    outOfPlot_   = true;
    highlighted_ = false;
}

MvQPlaceMarkItem::~MvQPlaceMarkItem()
{
}

QRectF MvQPlaceMarkItem::boundingRect() const
{
    return boundingRect_;
}

void MvQPlaceMarkItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*o*/, QWidget* /*w*/)
{
    if (outOfPlot_)
        return;

    float sx = painter->transform().m11();
    float sy = painter->transform().m22();

    //bool clipping=(painter->clipRegion().isEmpty())?false:true;
    //QRect clipRect=painter->clipRegion().boundingRect();

    if (1) {
        QTransform tr = painter->transform();
        tr.scale(1 / sx, 1 / sy);
        painter->setTransform(tr);
    }

    if (highlighted_) {
        painter->setPen(QColor(255, 0, 0, 190));
        painter->setBrush(QColor(255, 0, 0, 190));
        painter->drawRect(boundingRect_);
    }


    if (pm_)
        painter->drawPixmap(boundingRect_, pix_, pix_.rect());

    //painter->setPen(QColor(255,255,255));
    //painter->drawPoint(0,0);

    //painter->translate(QPointF(5,5));
    /*painter->scale(1.,-1.);
	painter->setPen(Qt::white);
	painter->setBrush(Qt::white);
	painter->drawText(QPointF(0,0),text_);*/
}

void MvQPlaceMarkItem::setPixmapColour(QColor col)
{
    QImage img = pm_->pixmap().toImage().mirrored(false, true);
    QPainter painter(&img);
    //painter.setBrush(QColor(255,0,0,190,140));
    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
    painter.fillRect(img.rect(), col);
    pix_ = QPixmap::fromImage(img);
    update();
}

void MvQPlaceMarkItem::setScenePosition(QPointF& scPos)
{
    setPos(scPos);
    dataLayout_ = plotScene_->projectorItem(QGraphicsObject::pos());
    QPointF cr;

    if (dataLayout_) {
        dataLayout_->mapFromSceneToGeoCoords(scPos, cr);
        if (pm_)
            pm_->setCoordinates(cr);
        outOfPlot_ = false;
    }
    else {
        outOfPlot_ = true;
    }
    updateLayerData();
    emit itemUpdated();
}

/*void MvQPlaceMarkItem::setCoordinates(QPointF &co)
{
	coordinates_=co;

	QPointF scPos;
	dataLayout_=plotScene_->projectorItem(QGraphicsObject::pos());

	if(dataLayout_)
	{
		dataLayout_->mapFromGeoToSceneCoords(coordinates_,scPos);
		setPos(scPos);
		outOfPlot_=false;
	}
	else
	{
		outOfPlot_=true;
	}
	updateLayerData();
	emit itemUpdated();	
}
*/

void MvQPlaceMarkItem::setHighlighted(bool flag)
{
    if (highlighted_ == flag)
        return;

    highlighted_ = flag;
    update();
}

void MvQPlaceMarkItem::mousePressEventFromView(QMouseEvent* event)
{
    if (!activated_ || !acceptMouseEvents_ || outOfPlot_)
        return;

    if (event->buttons() & Qt::LeftButton && outOfPlot_ == false) {
        QPointF lPos = mapFromScene(plotView_->mapToScene(event->pos()));
        if (!boundingRect_.contains(lPos)) {
            currentAction_ = NoAction;
            dragPos_       = QPointF();
            return;
        }

        dragPos_    = plotView_->mapToScene(event->pos());
        dataLayout_ = plotScene_->projectorItem(QGraphicsObject::pos());

        if (dataLayout_) {
            currentAction_ = MoveAction;
            //setCursor(QCursor(Qt::SizeAllCursor));
        }
        else {
            currentAction_ = NoAction;
            dragPos_       = QPointF();
        }
    }
}

void MvQPlaceMarkItem::mouseMoveEventFromView(QMouseEvent* event)
{
    if (!activated_ || !acceptMouseEvents_ || outOfPlot_)
        return;

    if (currentAction_ == MoveAction) {
        QPointF posM   = plotView_->mapToScene(event->pos());
        QPointF dp     = posM - dragPos_;
        QPointF newPos = QGraphicsObject::pos() + dp;

        if (dataLayout_->contains(dataLayout_->mapFromScene(newPos))) {
            QPointF cr;
            dataLayout_->mapFromSceneToGeoCoords(newPos, cr);
            if (pm_)
                pm_->setCoordinates(cr);

            prepareGeometryChange();

            setPos(newPos);
            dragPos_ = posM;
            update();
            updateLayerData();

            emit itemUpdated();
        }
    }
}

void MvQPlaceMarkItem::mouseReleaseEventFromView(QMouseEvent* /*event*/)
{
    if (!activated_ || !acceptMouseEvents_ || outOfPlot_)
        return;

    if (currentAction_ == MoveAction) {
        //Scene position
        /*QPointF posM = plotView_->mapToScene(event->pos());
		zoomLayout_->mapFromSceneToGeoCoords(posM,coordinates_);*/

        currentAction_ = NoAction;
        dataLayout_    = 0;
        dragPos_       = QPointF();

        /*emit areaIsDefined(
			corners[0].x(), corners[0].y(),
			corners[1].x(), corners[1].y());*/

        //unsetCursor();
    }
}


void MvQPlaceMarkItem::updateLayerData()
{
    /*	if(outOfPlot_)
	{
		
		pm_->clearLayerData();
		return;
	}
	
	QList<QPointF> posL;
	posL << pm_->coordinates();

	QList<QStringList> layerData;
	foreach(QPointF pp,posL)
	{
		layerData << QStringList();
	}
#ifndef METVIEW_MULTIPAGE 
	plotScene_->collectLayerDataForCurrentStep(posL,layerData);
#endif
	pm_->setLayerData(layerData);
	*/
}

void MvQPlaceMarkItem::updateVisibility()
{
    /*if(pm_->isOutOfPlot()== false)
		setVisible(pm_->isVisible());*/
}

void MvQPlaceMarkItem::reset()
{
#ifndef METVIEW_MULTIPAGE
    if ((dataLayout_ = plotScene_->projectorItem()) == 0) {
        //clearLine();
        return;
    }
#else
    return;
#endif

    QPointF gp0 = pm_->coordinates();
    QPointF sp0;


    //This should be called for the real placeMarks
    //pix_=QPixmap::fromImage(pm_->pixmap().toImage().mirrored(false,true));

    QRectF br;
    if (anchor_ == BottomCentreAnchor)
        br = QRectF(-pix_.width() / 2., 0, pix_.width(), pix_.height());
    else
        br = QRectF(-pix_.width() / 2., -pix_.height() / 2., pix_.width(), pix_.height());

    //QRectF br=QRectF(-pix_.width()/2.,0,pix_.width(),pix_.height());


    if (dataLayout_->containsGeoCoords(gp0)) {
        dataLayout_->mapFromGeoToSceneCoords(gp0, sp0);
        outOfPlot_ = false;
        if (isVisible()) {
            prepareGeometryChange();
            setPos(sp0);
            boundingRect_ = br;
            update();
        }
        else if (pm_->isVisible()) {
            setPos(sp0);
            boundingRect_ = br;
            setVisible(true);
        }
        else {
            boundingRect_ = br;
            setPos(sp0);
        }
        pm_->setOutOfPlot(false);
    }
    else {
        outOfPlot_ = true;
        if (isVisible()) {
            setVisible(false);
        }
        boundingRect_ = br;
        pm_->setOutOfPlot(true);
    }
}

#endif

//==========================================
//
//  MvQPlaceMark  --  A.K.A. dataProbe
//
//==========================================

MvQPlaceMark::MvQPlaceMark(MgQPlotScene* scene, MvQPlotView* view, QGraphicsItem* parent) :
    MvQPlotItem(scene, view, parent),
    magnifier_(nullptr)
{
    currentAction_ = NoAction;
    dataLayout_    = nullptr;
    coordinates_   = QPointF(0., 0.);

    //pix_=QPixmap::fromImage(pm_->pixmap().toImage().mirrored(false,true));
    //pix_=QPixmap::fromImage(img.mirrored(false,true));
    pix_ = QPixmap(QString::fromUtf8(":/uPlot/data_probe.svg"));

    anchor_ = CentreAnchor;

    if (anchor_ == BottomCentreAnchor)
        boundingRect_ = QRectF(-pix_.width() / 2., 0, pix_.width(), pix_.height());
    else
        boundingRect_ = QRectF(-pix_.width() / 2., -pix_.height() / 2., pix_.width(), pix_.height());

    outOfPlot_   = true;
    highlighted_ = false;
}

MvQPlaceMark::~MvQPlaceMark() = default;

QRectF MvQPlaceMark::boundingRect() const
{
    return boundingRect_;
}

void MvQPlaceMark::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*o*/, QWidget* /*w*/)
{
    //if(outOfPlot_)
    //	return;

    float sx = painter->transform().m11();
    float sy = painter->transform().m22();

    //bool clipping=(painter->clipRegion().isEmpty())?false:true;

    //qDebug() << "clip" << painter->clipRegion();
    //qDebug() << "scaling" << sx;

    //QRect clipRect=painter->clipRegion().boundingRect();

    if (1) {
        QTransform tr = painter->transform();
        tr.scale(1 / sx, 1 / sy);
        painter->setTransform(tr);
    }

    if (highlighted_) {
        painter->setPen(QColor(255, 0, 0, 190));
        painter->setBrush(QColor(255, 0, 0, 190));
        painter->drawRect(boundingRect_);
    }

    painter->drawPixmap(boundingRect_, pix_, pix_.rect());

    //painter->setPen(QColor(255,255,255));
    //painter->drawPoint(0,0);

    //painter->translate(QPointF(5,5));
    /*painter->scale(1.,-1.);
	painter->setPen(Qt::white);
	painter->setBrush(Qt::white);
	painter->drawText(QPointF(0,0),text_);*/
}

void MvQPlaceMark::setPixmapColour(QColor /*col*/)
{
    /*QImage img=pm_->pixmap().toImage().mirrored(false,true);
	QPainter painter(&img);
	//painter.setBrush(QColor(255,0,0,190,140));	
	painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
     	painter.fillRect(img.rect(),col);
	pix_=QPixmap::fromImage(img);
	update();*/
}

void MvQPlaceMark::setScenePosition(QPointF /*scPos*/)
{
}

void MvQPlaceMark::updateScenePosition()
{
    setCoordinates(coordinates_);
}

void MvQPlaceMark::setCoordinates(QPointF co)
{
    if (!activated_)
        return;

    coordinates_ = co;

    if (!dataLayout_) {
        outOfPlot_ = true;
        setVisible(false);
        return;
    }

    if (dataLayout_->containsGeoCoords(coordinates_)) {
        QPointF scPos;

        dataLayout_->mapFromGeoToSceneCoords(coordinates_, scPos);

        if (magnifier_ && magnifier_->activated()) {
            scPos = checkScenePosInMagnifier(scPos);
        }
        else {
            setVisible(true);
        }

        setPos(scPos);
        outOfPlot_ = false;
    }
    else {
        outOfPlot_ = true;
        setVisible(false);
    }
}

void MvQPlaceMark::setHighlighted(bool flag)
{
    if (highlighted_ == flag)
        return;

    highlighted_ = flag;
    update();
}

void MvQPlaceMark::setActivated(bool b)
{
    if (activated_ == b)
        return;

    activated_ = b;
    if (!activated_) {
        setVisible(false);
    }
    else {
        if (!dataLayout_) {
            setVisible(false);
        }
        else {
            setVisible(true);
        }
    }
}

void MvQPlaceMark::mousePressEventFromView(QMouseEvent* event)
{
    if (!activated_ || !acceptMouseEvents_ || !dataLayout_)
        return;

    if (event->buttons() & Qt::LeftButton) {
        QPointF lPos = mapFromScene(plotView_->mapToScene(event->pos()));
        if (!boundingRect_.contains(lPos)) {
            currentAction_ = NoAction;
            dragPos_       = QPointF();
            return;
        }

        dragPos_       = plotView_->mapToScene(event->pos());
        currentAction_ = MoveAction;
    }
}

void MvQPlaceMark::mouseMoveEventFromView(QMouseEvent* event)
{
    if (!activated_ || !acceptMouseEvents_ || !dataLayout_)
        return;

    if (currentAction_ == MoveAction) {
        QPointF posM   = plotView_->mapToScene(event->pos());
        QPointF dp     = posM - dragPos_;
        QPointF newPos = QGraphicsObject::pos() + dp;

        QPointF realPos = newPos;
        if (magnifier_ && magnifier_->activated()) {
            realPos = checkMagnifiedPosInMagnifier(realPos);
        }
        else {
            setVisible(true);
        }

        QPointF cr;
        if (dataLayout_->contains(dataLayout_->mapFromScene(realPos))) {
            outOfPlot_ = false;
            dataLayout_->mapFromSceneToGeoCoords(realPos, cr);
        }
        else {
            outOfPlot_ = true;
        }
        setPos(newPos);
        dragPos_ = posM;
        //update();

        emit beingMoved(cr);
    }
}

void MvQPlaceMark::mouseReleaseEventFromView(QMouseEvent* /*event*/)
{
    if (!activated_ || !acceptMouseEvents_)
        return;

    if (currentAction_ == MoveAction) {
        QPointF newPos  = QGraphicsObject::pos();
        QPointF realPos = newPos;

        if (magnifier_ && magnifier_->activated()) {
            realPos = checkMagnifiedPosInMagnifier(realPos);
        }

        if (dataLayout_->contains(dataLayout_->mapFromScene(realPos))) {
            dataLayout_->mapFromSceneToGeoCoords(realPos, coordinates_);
            outOfPlot_ = false;
        }
        else {
            outOfPlot_ = true;
        }

        emit pointSelected(coordinates_);

        currentAction_ = NoAction;

        dragPos_ = QPointF();
    }
}

void MvQPlaceMark::updateVisibility()
{
    /*if(pm_->isOutOfPlot()== false)
		setVisible(pm_->isVisible());*/
}

void MvQPlaceMark::reset(MgQLayoutItem* dataLayout)
{
    dataLayout_ = dataLayout;
    setCoordinates(coordinates_);
}

void MvQPlaceMark::setMagnifier(MvQMagnifier* m)
{
    magnifier_ = m;
    setCoordinates(coordinates_);
}


QPointF MvQPlaceMark::checkScenePosInMagnifier(const QPointF& scPos)
{
    //qDebug() << "magpos" << magnifier_->identifyScenePoint(scPos);

    QPointF pos = scPos;
    if (magnifier_ && magnifier_->activated()) {
        switch (magnifier_->identifyScenePoint(scPos)) {
            case MvQMagnifier::OuterScenePoint:
                setVisible(true);
                break;

            case MvQMagnifier::InnerScenePoint:
                pos = magnifier_->sceneToMagnifiedPos(scPos);
                setVisible(true);
                break;

            case MvQMagnifier::CoveredScenePoint:
                setVisible(false);
                break;

            default:
                break;
        }
    }

    return pos;
}

QPointF MvQPlaceMark::checkMagnifiedPosInMagnifier(const QPointF& magPos)
{
    //qDebug() << "magpos" << magnifier_->identifyScenePoint(scPos);

    QPointF pos = magPos;
    if (magnifier_ && magnifier_->activated()) {
        if (magnifier_->checkPointInMagnifier(magPos)) {
            pos = magnifier_->magnifiedToScenePos(magPos);
        }
    }

    return pos;
}
