/*
 * Copyright (C) 2015-2022 Département de l'Instruction Publique (DIP-SEM)
 *
 * Copyright (C) 2013 Open Education Foundation
 *
 * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
 * l'Education Numérique en Afrique (GIP ENA)
 *
 * This file is part of OpenBoard.
 *
 * OpenBoard 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, version 3 of the License,
 * with a specific linking exception for the OpenSSL project's
 * "OpenSSL" library (or with modified versions of it that use the
 * same license as the "OpenSSL" library).
 *
 * OpenBoard 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 OpenBoard. If not, see <http://www.gnu.org/licenses/>.
 */



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

#include "core/UBApplication.h"
#include "board/UBBoardController.h"
#include "domain/UBGraphicsScene.h"
#include "board/UBBoardView.h"

#include "core/memcheck.h"


UBMagnifier::UBMagnifier(QWidget *parent, bool isInteractive)
    : QWidget(parent, parent ? Qt::Widget : Qt::Tool | (Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint))
    , mShouldMoveWidget(false)
    , mShouldResizeWidget(false)
    , borderPen(Qt::darkGray)
    , gView(0)
    , mView(0)
{
    isCusrsorAlreadyStored = false;
    setMouseTracking(true);

    //--------------------------------------------------//

    QPixmap pix(":/images/cursors/resize.png");
    QTransform tr;
    tr.rotate(45);
    mResizeCursor  = QCursor(pix.transformed(tr, Qt::SmoothTransformation), pix.width() / 2,  pix.height() / 2);

    //--------------------------------------------------//

    params.sizePercentFromScene = 20;
    m_isInteractive = isInteractive;
    sClosePixmap = new QPixmap(":/images/close.svg");
    sIncreasePixmap = new QPixmap(":/images/increase.svg");
    sDecreasePixmap = new QPixmap(":/images/decrease.svg");
    mResizeItem = new QPixmap(":/images/resize.svg");
    sChangeModePixmap = new QPixmap();

    qDebug() << "sClosePixmap" << sClosePixmap->size() << endl
             << "sIncreasePixmap" << sIncreasePixmap->size() << endl
             << "sDecreasePixmap" << sDecreasePixmap->size() << endl
             << "mResizeItem" << mResizeItem->size() << endl;


    setDrawingMode(UBSettings::settings()->magnifierDrawingMode->get().toInt());

    if (parent)
    {
        setAttribute(Qt::WA_NoMousePropagation);
    }
    else
    {
        // standalone window
        // !!!! Should be included into Windows after QT recompilation
#ifndef Q_OS_WIN
//        setAttribute(Qt::WA_TranslucentBackground);
        setAttribute(Qt::WA_MacAlwaysShowToolWindow);
#endif
#ifdef Q_OS_OSX
        setAttribute(Qt::WA_MacAlwaysShowToolWindow);
        setAttribute(Qt::WA_MacNoShadow);
#endif
    }

    connect(&mRefreshTimer, SIGNAL(timeout()), this, SLOT(slot_refresh()));
}

UBMagnifier::~UBMagnifier()
{
    if(sClosePixmap)
    {
        delete sClosePixmap;
        sClosePixmap = NULL;
    }

    if(sIncreasePixmap)
    {
        delete sIncreasePixmap;
        sIncreasePixmap = NULL;
    }

    if(sDecreasePixmap)
    {
        delete sDecreasePixmap;
        sDecreasePixmap = NULL;
    }

    if (sChangeModePixmap)
    {
        delete sChangeModePixmap;
        sChangeModePixmap = NULL;
    }
}

void UBMagnifier::setSize(qreal percentFromScene)
{
    if(gView == NULL || mView == NULL) return;

    // calculate object size
    params.sizePercentFromScene = percentFromScene;
    QSize sceneSize = mView->size();
    qreal size = params.sizePercentFromScene * sceneSize.width() / 100;

    QRect currGeom = geometry();
    if (circular == mDrawingMode)
    {
        if(currGeom.width() == currGeom.height())
        {
            QPoint newPos = mView->mapFromGlobal(updPointMove);
            setGeometry(newPos.x() - size / 2, newPos.y() - size / 2, size, size);
        }
        else
            setGeometry(0, 0, size, size);
    }
    else if (rectangular == mDrawingMode)
    {
        QPoint newPos = mView->mapFromGlobal(updPointMove);
        setGeometry(newPos.x() - size / 2, newPos.y() - size / 2 / 3, size, size/3);
    }

    calculateButtonsPositions();
    createMask();

}

void UBMagnifier::createMask()
{
    if(gView == NULL || mView == NULL) return;

    // calculate object size
    QSize sceneSize = mView->size();
    qreal isize = params.sizePercentFromScene * sceneSize.width() / 100;

    QImage mask_img(width(), height(), QImage::Format_Mono);
    mask_img.fill(0xff);
    QPainter mask_ptr(&mask_img);
    mask_ptr.setBrush( QBrush( QColor(0, 0, 0) ) );

    if (circular == mDrawingMode)
        mask_ptr.drawEllipse(QPointF(isize/2, isize/2), isize / 2 - sClosePixmap->width(), isize / 2 - sClosePixmap->width());
    else if (rectangular == mDrawingMode)
        mask_ptr.drawRoundedRect(QRect(sClosePixmap->width(), sClosePixmap->width(), size().width() - 2*sClosePixmap->width(), size().height() - 2*sClosePixmap->width()), sClosePixmap->width()/2, sClosePixmap->width()/2);

    bmpMask = QBitmap::fromImage(mask_img);

    pMap = QPixmap(width(), height());
    pMap.fill(Qt::transparent);
    pMap.setMask(bmpMask);
}

void UBMagnifier::setZoom(qreal zoom)
{
    params.zoom = zoom;
}


void UBMagnifier::calculateButtonsPositions()
{
    qDebug() << "current widget size is " << size();

    m_iButtonInterval = 5;
    mResizeItemButtonRect = QRect(size().width() - 1.5*mResizeItem->width() - m_iButtonInterval, size().height() - 1.5*mResizeItem->height() - m_iButtonInterval, mResizeItem->width(), mResizeItem->height());
    sClosePixmapButtonRect = QRect(mResizeItemButtonRect.x() - sChangeModePixmap->width() - 3*m_iButtonInterval, size().height() - sChangeModePixmap->height(), sChangeModePixmap->width(), sChangeModePixmap->height());
    sChangeModePixmapButtonRect = QRect(sClosePixmapButtonRect.x() - sChangeModePixmap->width() - m_iButtonInterval, size().height() - sChangeModePixmap->height(), sChangeModePixmap->width(), sChangeModePixmap->height());
    sDecreasePixmapButtonRect = QRect(sChangeModePixmapButtonRect.x() - sChangeModePixmap->width() - m_iButtonInterval, size().height() - sDecreasePixmap->height(), sDecreasePixmap->width(), sDecreasePixmap->height());
    sIncreasePixmapButtonRect = QRect(sDecreasePixmapButtonRect.x() - sChangeModePixmap->width() - m_iButtonInterval, size().height() - sIncreasePixmap->height(), sIncreasePixmap->width(), sIncreasePixmap->height());

    qDebug() << "mResizeItemButtonRect" << mResizeItemButtonRect << endl
             << "sClosePixmapButtonRect" << sClosePixmapButtonRect << endl
             << "sChangeModePixmapButtonRect" << sChangeModePixmapButtonRect << endl
             << "sDecreasePixmapButtonRect" << sDecreasePixmapButtonRect << endl
             << "sIncreasePixmapButtonRect" << sIncreasePixmapButtonRect << endl;
}

void UBMagnifier::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);

    if (m_isInteractive)
    {
        painter.setBrush(QColor(127, 127, 127, 127));
        painter.drawRoundedRect(QRectF(size().width() / 2, size().height() / 2, ( size().width() - sClosePixmap->width() ) / 2, ( size().height() - sClosePixmap->width() ) / 2), 15, 15);
    }

    painter.setBrush(QColor(190, 190, 190, 255));
    if (circular == mDrawingMode)
    {
        painter.drawEllipse(QPoint(size().width() / 2, size().height() / 2), ( size().width() - sClosePixmap->width() ) / 2, ( size().height() -  sClosePixmap->height() ) / 2);
    }
    else if (rectangular == mDrawingMode)
    {
        QRect r = QRect(sClosePixmap->width()/2, sClosePixmap->width()/2, size().width()- sClosePixmap->width(), size().height() - sClosePixmap->width());
        painter.drawRoundedRect(r, sClosePixmap->width()/2, sClosePixmap->width()/2);
    }

    painter.drawPixmap(0, 0, pMap);

    if (m_isInteractive)
    {
        painter.setBrush(QColor(190, 190, 190, 255));
        painter.drawPixmap(sClosePixmapButtonRect.topLeft(), *sClosePixmap);
        painter.drawPixmap(sIncreasePixmapButtonRect.topLeft(), *sIncreasePixmap);
        painter.drawPixmap(sDecreasePixmapButtonRect.topLeft(), *sDecreasePixmap);
        painter.drawPixmap(sChangeModePixmapButtonRect.topLeft(), *sChangeModePixmap);
        painter.drawPixmap(mResizeItemButtonRect.topLeft(), *mResizeItem);
    }
}

void UBMagnifier::mousePressEvent ( QMouseEvent * event )
{
    if(m_isInteractive)
    {

        QWidget::mousePressEvent(event);

        if (event->pos().x() >= size().width() - mResizeItem->width() - 14 &&
            event->pos().x() < size().width() - 14 &&
            event->pos().y() >= size().height() - mResizeItem->height() - 14 &&
            event->pos().y() < size().height() - - 14)
        {
            mShouldResizeWidget = true;
        }
        else
        {
            mShouldMoveWidget = !event->isAccepted() && (event->buttons() & Qt::LeftButton);
        }

        mMousePressPos = event->pos();
        mMousePressDelta = (qreal)updPointGrab.x() + (qreal)size().width() / 2 - (qreal)event->globalPos().x();

        event->accept();

        update();
    }
    else
        event->ignore();
}

void UBMagnifier::mouseMoveEvent ( QMouseEvent * event )
{
    if(m_isInteractive)
    {
        if(mShouldMoveWidget && (event->buttons() & Qt::LeftButton))
        {
            move(pos() - mMousePressPos + event->pos());
            event->accept();

            QWidget::mouseMoveEvent(event);
            emit magnifierMoved_Signal(QPoint(this->pos().x() + size().width() / 2, this->pos().y() + size().height() / 2 ));
            return;
        }

        if(mShouldResizeWidget && (event->buttons() & Qt::LeftButton))
        {

            QPoint currGlobalPos = event->globalPos();
            qreal cvW = mView->width();

            qreal newXSize = ( currGlobalPos.x() + mMousePressDelta - updPointGrab.x() ) * 2;
            qreal newPercentSize = newXSize * 100 / cvW;

            emit magnifierResized_Signal(newPercentSize);

            event->ignore();
            return;
        }

        if (mResizeItemButtonRect.contains(event->pos())&&
            isCusrsorAlreadyStored == false
           )
        {
            mOldCursor = cursor();
            isCusrsorAlreadyStored = true;
            setCursor(mResizeCursor);
        }

    }
    else
        event->ignore();
}


void UBMagnifier::mouseReleaseEvent(QMouseEvent * event)
{
    if(m_isInteractive)
    {
        mShouldMoveWidget = false;
        mShouldResizeWidget = false;

        if (sClosePixmapButtonRect.contains(event->pos()))
        {
            event->accept();
            emit magnifierClose_Signal();
        }
        else
        if (sIncreasePixmapButtonRect.contains(event->pos()))
        {
            event->accept();
            emit magnifierZoomIn_Signal();
        }
        else
        if (sDecreasePixmapButtonRect.contains(event->pos()))
        {
            event->accept();
            emit magnifierZoomOut_Signal();
        }
        else
        if (sChangeModePixmapButtonRect.contains(event->pos()))
        {
            event->accept();
            emit magnifierDrawingModeChange_Signal(static_cast<int>(mDrawingMode+1)%modesCount);
        }
        else
            QWidget::mouseReleaseEvent(event); // don't propgate to parent, the widget is deleted in UBApplication::boardController->removeTool
    }
    else
        event->ignore();

}

void UBMagnifier::slot_refresh()
{
    if(!(updPointGrab.isNull()))
        grabPoint(updPointGrab);

    if(isCusrsorAlreadyStored)
    {
        QPoint globalCursorPos = QCursor::pos();
        QPoint cursorPos = mapFromGlobal(globalCursorPos);
        if (cursorPos.x() < size().width() - mResizeItem->width() - 14 ||
            cursorPos.x() > size().width() - 14 ||
            cursorPos.y() < size().height() - mResizeItem->height() - 14 ||
            cursorPos.y() > size().height() - - 14
            )
        {
            isCusrsorAlreadyStored = false;
            setCursor(mOldCursor);
        }
    }
}

void UBMagnifier::grabPoint()
{
    QMatrix transM = UBApplication::boardController->controlView()->matrix();
    QPointF itemPos = gView->mapFromGlobal(updPointGrab);

    qreal zWidth = width() / (params.zoom * transM.m11());
    qreal zWidthHalf = zWidth / 2;
    qreal zHeight = height() / (params.zoom * transM.m22());
    qreal zHeightHalf = zHeight / 2;


    QPointF pfScLtF(UBApplication::boardController->controlView()->mapToScene(QPoint(itemPos.x(), itemPos.y())));

    float x = pfScLtF.x() - zWidthHalf;
    float y = pfScLtF.y() - zHeightHalf;

    QPointF leftTop(x,y);
    QPointF rightBottom(x + zWidth, y + zHeight);
    QRectF srcRect(leftTop, rightBottom);

    QPixmap newPixMap(QSize(width(), height()));
    QPainter painter(&newPixMap);

    UBApplication::boardController->activeScene()->render(&painter, QRectF(0,0,width(),height()), srcRect);
    painter.end();

    pMap.fill(Qt::transparent);
    pMap = newPixMap.scaled(QSize(width(), height()));
    pMap.setMask(bmpMask);

    update();
}

void UBMagnifier::grabPoint(const QPoint &pGrab)
{
    QMatrix transM = UBApplication::boardController->controlView()->matrix();
    updPointGrab = pGrab;
    QPointF itemPos = gView->mapFromGlobal(pGrab);

    qreal zWidth = width() / (params.zoom * transM.m11());
    qreal zWidthHalf = zWidth / 2;
    qreal zHeight = height() / (params.zoom * transM.m22());
    qreal zHeightHalf = zHeight / 2;


    QPointF pfScLtF(UBApplication::boardController->controlView()->mapToScene(QPoint(itemPos.x(), itemPos.y())));

    float x = pfScLtF.x() - zWidthHalf;
    float y = pfScLtF.y() - zHeightHalf;

    QPointF leftTop(x,y);
    QPointF rightBottom(x + zWidth, y + zHeight);
    QRectF srcRect(leftTop, rightBottom);

    QPixmap newPixMap(QSize(width(), height()));
    QPainter painter(&newPixMap);

    UBApplication::boardController->activeScene()->render(&painter, QRectF(0,0,width(),height()), srcRect);
    painter.end();

   // pMap.fill(Qt::transparent);
    pMap = newPixMap;
    pMap.setMask(bmpMask);

    update();
}



// from global
void UBMagnifier::grabNMove(const QPoint &pGrab, const QPoint &pMove, bool needGrab, bool needMove)
{
    QPoint pointToGrab = pGrab;
    updPointGrab = pointToGrab;
    updPointMove = pMove;

    if(needGrab)
        grabPoint(pointToGrab);

    if(needMove)
    {
        QPoint movePos = mView->mapFromGlobal(pMove);
        move(movePos.x() - width()/2, movePos.y() - height()/2);
        //    move(itemPos.x(), itemPos.y());
    }
}

void UBMagnifier::setGrabView(QWidget *view)
{
    gView = view;
    mRefreshTimer.setInterval(40);
    mRefreshTimer.start();
}

void UBMagnifier::setDrawingMode(int mode)
{
    mDrawingMode = static_cast<DrawingMode>(mode);

    QString sMode;

    if (circular == mDrawingMode)
    {
        sMode = "roundeRrectangle";
        resize(width(), width());
    }

    if (rectangular == mDrawingMode)
    {
        sMode = "circle";
        resize(width(), height()/3);

        if (mView)
        {
            qreal newPercentSize = size().width()/3 * 100 / mView->width();
            emit magnifierResized_Signal(newPercentSize);
        }
    }

    sChangeModePixmap->load(":/images/"+sMode+".svg");

    calculateButtonsPositions();
    if (mView && gView)
        UBApplication::boardController->controlView()->scene()->moveMagnifier();

    createMask();

    UBSettings::settings()->magnifierDrawingMode->set(mode);
}
