/*
    Copyright © 2015 by The QTMyPaint Project

    This file is part of QTMyPaint, a Qt-based interface for MyPaint C++ library.

    QTMyPaint is libre 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 3 of the License, or
    (at your option) any later version.

    QTMyPaint 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 QTMyPaint. If not, see <http://www.gnu.org/licenses/>.
*/

#include "tapplication.h"
#include "rastermainwindow.h"
#include "tapplicationproperties.h"
#include "tuprequestbuilder.h"

#include <QFileDialog>
#include <QVBoxLayout>
#include <QMenuBar>
#include <QMenu>
#include <QAction>

RasterMainWindow::RasterMainWindow(TupProject *project, const QString &winKey, TupProject::Mode context, int scene,
                                   const QPen &pen, const QString &zoomFactor, QWidget *parent):
                                   TMainWindow(winKey, RasterView, parent)
{    
    spaceContext = context;
    sceneIndex = scene;
    projectSize = project->getDimension();
    tupBg = project->getBackgroundFromScene(scene);

    TCONFIG->beginGroup("Raster");
    TCONFIG->setValue("ProjectWidth", projectSize.width());
    TCONFIG->setValue("ProjectHeight", projectSize.height());
    TCONFIG->sync();

    #ifdef TUP_DEBUG
        qDebug() << "---";
        qDebug() << "[RasterMainWindow::RasterMainWindow()] - projectSize ->" << projectSize;
        qDebug() << "[RasterMainWindow::RasterMainWindow()] - zoomFactor ->" << zoomFactor;
        qDebug() << "[RasterMainWindow::RasterMainWindow()] - pen.color() ->" << pen.color();
    #endif

    createTopResources();

    TCONFIG->beginGroup("BrushParameters");
    double thickness = TCONFIG->value("RasterThickness", 2).toDouble();
    if (thickness > 5)
        thickness = 2;

    createCentralWidget(project, thickness, pen.color());

    colorWidget = new RasterColorWidget(pen, project->getCurrentBgColor(), this);
    connect(colorWidget, SIGNAL(paintAreaEventTriggered(const TupPaintAreaEvent *)),
            this, SIGNAL(paintAreaEventTriggered(const TupPaintAreaEvent *)));
    connect(colorWidget, SIGNAL(paintAreaEventTriggered(const TupPaintAreaEvent *)),
            this, SLOT(processColorEvent(const TupPaintAreaEvent *)));

    colorView = addToolView(colorWidget, Qt::LeftDockWidgetArea, RasterView, "Brush Color", QKeySequence(tr("Shift+C")));
    colorView->expandDock(false);

    brushesWidget = new RasterBrushesWidget(RASTER_RESOURCES_DIR + "brushes");
    connect(brushesWidget, SIGNAL(brushSelected(const QByteArray&)),
            rasterCanvas, SLOT(loadBrush(const QByteArray&)));

    sizeWidget = new RasterSizeWidget(thickness, pen.color());
    connect(sizeWidget, SIGNAL(brushSizeChanged(double)), rasterCanvas, SLOT(setBrushSize(double)));
    connect(colorWidget, SIGNAL(colorChanged(QColor)), sizeWidget, SLOT(updateColor(QColor)));

    sizeView = addToolView(sizeWidget, Qt::LeftDockWidgetArea, RasterView, "Brush Size", QKeySequence(tr("Shift+S")));
    sizeView->expandDock(false);

    brushesView = addToolView(brushesWidget, Qt::LeftDockWidgetArea, RasterView, "Brushes", QKeySequence(tr("Shift+B")));
    brushesView->expandDock(true);

    status = new TupPaintAreaStatus(TupPaintAreaStatus::Raster);
    connect(status, SIGNAL(resetClicked()), this, SLOT(resetWorkSpaceTransformations()));
    connect(status, SIGNAL(safeAreaClicked()), this, SLOT(drawActionSafeArea()));
    connect(status, SIGNAL(gridClicked()), this, SLOT(drawGrid()));
    connect(status, SIGNAL(zoomChanged(qreal)), this, SLOT(setZoomFactor(qreal)));
    connect(status, SIGNAL(angleChanged(int)), this, SLOT(setRotationAngle(int)));
    connect(rasterCanvas, SIGNAL(rotated(int)), status, SLOT(updateRotationAngle(int)));
    setStatusBar(status);

    status->setZoomPercent(zoomFactor);
    tabletIsActive = false;
    brushesWidget->loadInitSettings();
}

RasterMainWindow::~RasterMainWindow()
{
}

void RasterMainWindow::createTopResources()
{
    exportAction = new QAction(QIcon(THEME_DIR + "icons/bitmap.png"), tr("&Export as Image"), this);
    exportAction->setShortcuts(QKeySequence::Open);
    exportAction->setStatusTip(tr("Export as Image"));
    connect(exportAction, SIGNAL(triggered()), this, SLOT(exportImage()));

    libraryAction = new QAction(QIcon(THEME_DIR + "icons/library.png"), tr("&Import Image to Library"), this);
    libraryAction->setShortcut(QKeySequence(tr("I")));
    libraryAction->setStatusTip(tr("Import Image to Library"));
    connect(libraryAction, SIGNAL(triggered()), this, SLOT(importImageToLibrary()));

    QAction *closeAction = new QAction(QIcon(THEME_DIR + "icons/exit.png"), tr("Exit Raster Mode"), this);
    closeAction->setShortcuts(QKeySequence::Quit);
    closeAction->setStatusTip(tr("Exit Raster Mode"));
    connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));

    /* SQA: This connection doesn't work on Windows
    connect(closeAction, &QAction::triggered, this, &QWidget::close);
    */

    QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(libraryAction);
    fileMenu->addAction(exportAction);
    fileMenu->addAction(closeAction);
}

void RasterMainWindow::createCentralWidget(TupProject *project, double thickness, const QColor &color)
{
    // Central widget
    rasterCanvas = new RasterCanvas(project, thickness, color, this);
    connect(rasterCanvas, SIGNAL(closeWindow()), this, SLOT(saveCanvas()));
    connect(rasterCanvas, SIGNAL(zoomIn()), this, SLOT(applyZoomIn()));
    connect(rasterCanvas, SIGNAL(zoomOut()), this, SLOT(applyZoomOut()));
    connect(rasterCanvas, SIGNAL(rasterStrokeMade()), this, SIGNAL(rasterStrokeMade()));
    connect(rasterCanvas, SIGNAL(scaled(qreal)), this, SLOT(applyZoom(qreal)));

    topBar = new QToolBar(tr("Raster actions"), this);
    topBar->setIconSize(QSize(16, 16));

    QAction *clearCanvas = new QAction(QIcon(THEME_DIR + "icons/new.png"), tr("Clear Canvas"), this);
    clearCanvas->setIconVisibleInMenu(true);
    clearCanvas->setShortcut(Qt::Key_Backspace);
    connect(clearCanvas, SIGNAL(triggered()), this, SLOT(clearCanvas()));

    QAction *undo = new QAction(QIcon(THEME_DIR + "icons/undo.png"), tr("Undo"), this);
    undo->setIconVisibleInMenu(true);
    undo->setShortcut(Qt::Key_Control + Qt::Key_Z);
    connect(undo, SIGNAL(triggered()), rasterCanvas, SLOT(undo()));

    QAction *redo = new QAction(QIcon(THEME_DIR + "icons/redo.png"), tr("Redo"), this);
    redo->setIconVisibleInMenu(true);
    undo->setShortcut(Qt::Key_Control + Qt::Key_Y);
    connect(redo, SIGNAL(triggered()), rasterCanvas, SLOT(redo()));

    QWidget *cEmpty0 = new QWidget();
    cEmpty0->setFixedWidth(5);

    topBar->addAction(clearCanvas);
    topBar->addWidget(cEmpty0);
    topBar->addAction(undo);
    topBar->addAction(redo);
    // topBar->addAction(kApp->findGlobalAction("undo"));
    // topBar->addAction(kApp->findGlobalAction("redo"));
    topBar->addSeparator();
    topBar->addAction(exportAction);
    topBar->addAction(libraryAction);

    QString imgPath = RASTER_BG_DIR + QString::number(sceneIndex) + "/bg/";
    if (spaceContext == TupProject::RASTER_STATIC_BG_MODE) {
        // Raster Static Settings
        setWindowTitle(tr("Raster Static Background"));
        setWindowIcon(QIcon(THEME_DIR + "icons/raster_mode.png"));
        imgPath += "static_bg.png";
    } else {
        // Raster Dynamic Settings
        setWindowTitle(tr("Raster Dynamic Background"));
        setWindowIcon(QIcon(THEME_DIR + "icons/dynamic_raster_mode.png"));
        imgPath += "dynamic_bg.png";

        QLabel *dirLabel = new QLabel();
        QPixmap dirPix(THEME_DIR + "icons/mov_orientation.png");
        dirLabel->setToolTip(tr("Movement Orientation"));
        dirLabel->setPixmap(dirPix);

        QComboBox *dirCombo = new QComboBox;
        dirCombo->setToolTip(tr("Movement Orientation"));
        dirCombo->addItem(QIcon(THEME_DIR + "icons/mov_right.png"), "   " + tr("Right"));
        dirCombo->addItem(QIcon(THEME_DIR + "icons/mov_left.png"), "   " + tr("Left"));
        dirCombo->addItem(QIcon(THEME_DIR + "icons/mov_up.png"), "   " + tr("Up"));
        dirCombo->addItem(QIcon(THEME_DIR + "icons/mov_down.png"), "   " + tr("Down"));
        dirCombo->setCurrentIndex(tupBg->rasterDynamicDirection());
        connect(dirCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setBackgroundDirection(int)));

        QWidget *dEmpty0 = new QWidget();
        dEmpty0->setFixedWidth(5);
        QWidget *dEmpty1 = new QWidget();
        dEmpty1->setFixedWidth(5);
        QWidget *dEmpty2 = new QWidget();
        dEmpty2->setFixedWidth(5);
        QWidget *dEmpty3 = new QWidget();
        dEmpty3->setFixedWidth(5);
        QWidget *dEmpty4 = new QWidget();
        dEmpty4->setFixedWidth(5);
        QWidget *dEmpty5 = new QWidget();
        dEmpty5->setFixedWidth(5);
        QWidget *dEmpty6 = new QWidget();
        dEmpty6->setFixedWidth(5);

        QLabel *shiftLabel = new QLabel();
        QPixmap shiftPix(THEME_DIR + "icons/shift_length.png");
        shiftLabel->setToolTip(tr("Shift Length"));
        shiftLabel->setPixmap(shiftPix);

        QSpinBox *shiftSpin = new QSpinBox(this);
        shiftSpin->setSingleStep(1);
        shiftSpin->setRange(1, 1000);
        shiftSpin->setValue(tupBg->rasterDynamicShift());
        shiftSpin->setToolTip(tr("Shift Length"));
        connect(shiftSpin, SIGNAL(valueChanged(int)), this, SLOT(updateBackgroundShiftProperty(int)));

        topBar->addWidget(dEmpty0);
        topBar->addSeparator();
        topBar->addWidget(dEmpty1);
        topBar->addWidget(dirLabel);
        topBar->addWidget(dEmpty2);
        topBar->addWidget(dirCombo);
        topBar->addWidget(dEmpty3);
        topBar->addSeparator();
        topBar->addWidget(dEmpty4);
        topBar->addWidget(shiftLabel);
        topBar->addWidget(dEmpty5);
        topBar->addWidget(shiftSpin);
        topBar->addWidget(dEmpty6);
    }

    if (QFile::exists(imgPath)) {
        rasterCanvas->loadFromFile(imgPath);
    } else {
        #ifdef TUP_DEBUG
            qDebug() << "[RasterMainWindow::createCentralWidget()] - Warning: Image doesn't exist ->"
                     << imgPath;
        #endif
    }

    QWidget *centralWidget = new QWidget();
    QVBoxLayout *centralLayout = new QVBoxLayout(centralWidget);
    centralLayout->addWidget(topBar);
    centralLayout->addWidget(rasterCanvas);

    setCentralWidget(centralWidget);
}

void RasterMainWindow::closeEvent(QCloseEvent *event)
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::closeEvent()]";
    #endif

    saveCanvas();

    colorView->expandDock(false);
    brushesView->expandDock(false);

    rasterCanvas->resetMem();

    // Cleaning memory
    colorView = nullptr;
    delete colorView;

    brushesView = nullptr;
    delete brushesView;

    colorWidget = nullptr;
    delete colorWidget;

    brushesWidget = nullptr;
    delete brushesWidget;

    rasterCanvas = nullptr;
    delete rasterCanvas;

    status = nullptr;
    delete status;
    //

    TMainWindow::closeEvent(event);
}

void RasterMainWindow::resetWorkSpaceTransformations()
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::resetWorkSpaceTransformations()]";
    #endif

    rasterCanvas->resetWorkSpaceCenter(projectSize);
    status->setRotationAngle("0");
    status->setZoomPercent("100");
}

void RasterMainWindow::drawGrid()
{
    rasterCanvas->drawGrid(!rasterCanvas->getGridState());
}

void RasterMainWindow::drawActionSafeArea()
{
    rasterCanvas->drawActionSafeArea(!rasterCanvas->getSafeAreaState());
}

void RasterMainWindow::applyZoom(qreal factor)
{
    #ifdef TUP_DEBUG
        qDebug() << "---";
        qDebug() << "[RasterMainWindow::applyZoom()] - factor ->" << factor;
    #endif

    status->updateZoomFactor(factor);
}

void RasterMainWindow::setZoomFactor(qreal factor)
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::setZoomFactor()] - factor ->" << factor;
    #endif

    rasterCanvas->setZoom(factor);
}

void RasterMainWindow::applyZoomIn()
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::applyZoomIn()]";
    #endif

    qreal zoom = status->currentZoomFactor();
    if (zoom <= 495) {
        zoom += 5;
        status->setZoomPercent(QString::number(zoom));
    }
}

void RasterMainWindow::applyZoomOut()
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::applyZoomOut()]";
    #endif

    qreal zoom = status->currentZoomFactor();
    if (zoom >= 15) {
        zoom -= 5;
        status->setZoomPercent(QString::number(zoom));
    }
}

void RasterMainWindow::setRotationAngle(int angle)
{
    rasterCanvas->setRotationAngle(angle);
}

void RasterMainWindow::processColorEvent(const TupPaintAreaEvent *event)
{
    QColor color = qvariant_cast<QColor>(event->getData());
    if (event->getAction() == TupPaintAreaEvent::ChangePenColor) {
        rasterCanvas->updateBrushColor(color);
    } else if (event->getAction() == TupPaintAreaEvent::ChangeBgColor) {
        rasterCanvas->setBgColor(color);
    }
}

void RasterMainWindow::setTabletDevice(QTabletEvent* event)
{
    rasterCanvas->setTabletDevice(event);
}

void RasterMainWindow::openProject()
{
    // Path
    QString initPath = QDir::homePath();
    QString filePath = QFileDialog::getOpenFileName(this, tr("Open Image"), initPath);

    if (filePath.isEmpty())
        return; // false;

    rasterCanvas->loadFromFile(filePath);
}

void RasterMainWindow::exportImage()
{
    // Path
    QString initPath = QDir::homePath() + "/dynamic_bg.png";
    if (spaceContext == TupProject::RASTER_STATIC_BG_MODE)
        initPath = QDir::homePath() + "/static_bg.png";

    QString filePath = QFileDialog::getSaveFileName(this, tr("Export Image"), initPath);
    if (filePath.isEmpty()) {
        #ifdef TUP_DEBUG
            qDebug() << "[RasterMainWindow::exportImage()] - File path is empty ->" << filePath;
        #endif
        return;
    }

    rasterCanvas->saveToFile(filePath);
}

void RasterMainWindow::saveCanvas()
{
    QString imgPath = RASTER_BG_DIR + QString::number(sceneIndex) + "/bg/";
    QString file = imgPath + "dynamic_bg.png";
    if (spaceContext == TupProject::RASTER_STATIC_BG_MODE)
        file = imgPath + "static_bg.png";

    if (!rasterCanvas->canvasIsEmpty()) {
        QDir dir(imgPath);
        if (!dir.exists()) {
            if (!QDir().mkpath(imgPath)) {
                #ifdef TUP_DEBUG
                    qDebug() << "[RasterMainWindow::saveCanvas()] - Error while creating raster background path!";
                    qDebug() << "[RasterMainWindow::saveCanvas()] - Image Path ->" << imgPath;
                #endif
            }
        }

        rasterCanvas->saveToFile(file);

        #ifdef TUP_DEBUG
            qWarning() << "[RasterMainWindow::saveCanvas()] - Creating PNG image!";
        #endif

        emit closeWindow(file);
    } else {
        #ifdef TUP_DEBUG
            qWarning() << "[RasterMainWindow::saveCanvas()] - Nothing new to save!";
        #endif
        if (QFile::exists(file)) {
            #ifdef TUP_DEBUG
                qWarning() << "[RasterMainWindow::saveCanvas()] - Removing previous image ->" << file;
            #endif
            QFile bg(file);
            bg.remove();
        }
        emit closeWindow("");
    }
}

void RasterMainWindow::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event)
    // rasterCanvas->setSize(this->centralWidget()->rect().size());
}

void RasterMainWindow::keyPressEvent(QKeyEvent *event)
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::keyPressEvent()] - key ->" << event;
    #endif

    switch(event->key()) {
        case Qt::Key_F11:
        case Qt::Key_Escape:
        case Qt::Key_Return:
            saveCanvas();
        break;
        default:
            #ifdef TUP_DEBUG
                qDebug() << "[RasterMainWindow::keyPressEvent()] - Key wasn't processed ->" << event->key();
            #endif
        break;
    }
}

void RasterMainWindow::setBackgroundDirection(int direction)
{
    tupBg->setRasterDynamicDirection(direction);
}

void RasterMainWindow::updateBackgroundShiftProperty(int shift)
{
    tupBg->setRasterDynamicShift(shift);
}

void RasterMainWindow::undoRasterItem()
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::undoRasterItem()]";
    #endif

    rasterCanvas->undo();
}

void RasterMainWindow::redoRasterItem()
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::redoRasterItem()]";
    #endif

    rasterCanvas->redo();
}

void RasterMainWindow::clearCanvas()
{
    #ifdef TUP_DEBUG
        qDebug() << "[RasterMainWindow::clearCanvas()]";
    #endif

    rasterCanvas->clearCanvas();
    emit canvasCleared();
}

void RasterMainWindow::undoClearRasterAction()
{
    rasterCanvas->undo();
}

void RasterMainWindow::redoClearRasterAction()
{
    rasterCanvas->redo();
}

void RasterMainWindow::importImageToLibrary()
{
    QString imgPath = CACHE_DIR + "rasterImg.png";
    rasterCanvas->saveToFile(imgPath);

    emit libraryCall(imgPath);
}
