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

#include <QAction>
#include <QDebug>
#include <QLabel>
#include <QMenu>
#include <QMouseEvent>
#include <QPainter>
#include <QToolButton>

#include "MvQMethods.h"
#include "MvQPalette.h"
#include "MvQRequestPanelHelp.h"

#include "LineFactory.h"
#include "RequestPanel.h"

//==============================================
//
// MvQColourListWidget
//
//==============================================

MvQColourListWidget::MvQColourListWidget(QWidget* parent) :
    QWidget(parent),
    edited_(false),
    cellWidth_(0),
    currentCell_(-1),
    editorGapX_(2),
    editorGapY_(4)
{
    blackPen_ = QPen(Qt::black, 2., Qt::SolidLine);
    whitePen_ = QPen(Qt::white, 2., Qt::SolidLine);

    setContextMenuPolicy(Qt::ActionsContextMenu);

    insertBeforeAc_ = new QAction(this);
    insertBeforeAc_->setText(tr("Insert before cell"));
    insertBeforeAc_->setData("insertBefore");
    insertBeforeAc_->setIcon(QPixmap(":/desktop/insertBefore.svg"));
    insertBeforeAc_->setToolTip(tr("Insert before cell"));

    addAction(insertBeforeAc_);

    connect(insertBeforeAc_, SIGNAL(triggered()),
            this, SLOT(slotInsertBeforeCell()));

    insertAfterAc_ = new QAction(this);
    insertAfterAc_->setText(tr("Insert after cell"));
    insertAfterAc_->setData("insertAfter");
    insertAfterAc_->setIcon(QPixmap(":/desktop/insertAfter.svg"));
    insertAfterAc_->setToolTip(tr("Insert after cell"));

    addAction(insertAfterAc_);

    connect(insertAfterAc_, SIGNAL(triggered()),
            this, SLOT(slotInsertAfterCell()));

    deleteCellAc_ = new QAction(this);
    deleteCellAc_->setText(tr("Delete cell"));
    deleteCellAc_->setData("deleteCell");
    deleteCellAc_->setIcon(QPixmap(":/desktop/deleteCell.svg"));
    deleteCellAc_->setToolTip(tr("Remove cell"));

    addAction(deleteCellAc_);

    connect(deleteCellAc_, SIGNAL(triggered()),
            this, SLOT(slotDeleteCell()));

    //----------------------------------
    // Colour context menu
    //-----------------------------------

    auto* sep = new QAction(this);
    sep->setSeparator(true);
    addAction(sep);

    copyColAc_ = new QAction(this);
    copyColAc_->setText(tr("&Copy colour cell"));
    copyColAc_->setShortcut(QKeySequence(tr("Ctrl+C")));
    //copyColAc_->setIcon(QPixmap(":/desktop/editcopy.svg"));
    copyColAc_->setData("ignore");
    addAction(copyColAc_);

    connect(copyColAc_, SIGNAL(triggered()),
            this, SLOT(slotCopyColour()));

    pasteColAc_ = new QAction(this);
    pasteColAc_->setText(tr("&Paste colour cell"));
    pasteColAc_->setShortcut(QKeySequence(tr("Ctrl+V")));
    //pasteColAc_->setIcon(QPixmap(":/desktop/editpaste.svg"));
    pasteColAc_->setData("ignore");
    addAction(pasteColAc_);

    connect(pasteColAc_, SIGNAL(triggered()),
            this, SLOT(slotPasteColour()));

#if 0
    QAction *acCopyRgb=new QAction(this);
    acCopyRgb->setText(tr("Copy colour as &RGB"));
    acCopyRgb->setData("ignore");
    addAction(acCopyRgb);

    connect(acCopyRgb,SIGNAL(triggered()),
            this,SLOT(slotCopyRgb()));

    QAction *acCopyHsl=new QAction(this);
    acCopyHsl->setText(tr("Copy colour as &HSL"));
    acCopyHsl->setData("ignore");
    addAction(acCopyHsl);

    connect(acCopyHsl,SIGNAL(triggered()),
            this,SLOT(slotCopyHsl()));

#endif

    auto* sep1 = new QAction(this);
    sep1->setSeparator(true);
    addAction(sep1);

    auto* acCopyColList = new QAction(this);
    acCopyColList->setText(tr("&Copy colour list"));
    acCopyColList->setData("ignore");
    addAction(acCopyColList);

    connect(acCopyColList, SIGNAL(triggered()),
            this, SLOT(slotCopyColourList()));


    auto* acPasteColList = new QAction(this);
    acPasteColList->setText(tr("&Paste colour list"));
    acPasteColList->setData("ignore");
    addAction(acPasteColList);

    connect(acPasteColList, SIGNAL(triggered()),
            this, SLOT(slotPasteColourList()));
}

void MvQColourListWidget::checkActionState()
{
    if (colours_.count() <= 1)
        deleteCellAc_->setEnabled(false);
    else
        deleteCellAc_->setEnabled(true);

    if (currentCell_ == -1) {
        copyColAc_->setEnabled(false);
        pasteColAc_->setEnabled(false);
    }
    else {
        copyColAc_->setEnabled(true);
        pasteColAc_->setEnabled(true);
    }
}

void MvQColourListWidget::setColours(QList<QColor> cols)
{
    colours_ = cols;

    if (currentCell_ == -1 || currentCell_ >= colours_.count()) {
        setCurrentCell(0);
    }
    else {
        createPixmap();
        update();
    }

    checkActionState();
}

void MvQColourListWidget::resizeEvent(QResizeEvent* /*event*/)
{
    createPixmap();
    update();
}

void MvQColourListWidget::changeEvent(QEvent* event)
{
    if (event->type() == QEvent::EnabledChange) {
        createPixmap();
        update();
    }
    else {
        QWidget::changeEvent(event);
    }
}

void MvQColourListWidget::paintEvent(QPaintEvent* /*event*/)
{
    QPainter painter(this);

    if (!pix_.isNull())
        painter.drawPixmap(0, 0, pix_);

    renderCurrentCell(&painter);
}

void MvQColourListWidget::mousePressEvent(QMouseEvent* event)
{
    setCurrentCell(event->pos());
    //if(colours_.count() == 1)
    //{
    emit singleCellClicked();
    //}
}

void MvQColourListWidget::setCurrentCell(QPoint pos)
{
    int i = pos.x() / cellWidth_;
    setCurrentCell(i);
}

void MvQColourListWidget::setCurrentCell(int index)
{
    if (index >= 0 && index < colours_.count()) {
        currentCell_ = index;
        update();
        emit currentChanged(colours_[currentCell_]);
    }
}

void MvQColourListWidget::createPixmap()
{
    if (!isEnabled()) {
        pix_ = QPixmap(width(), height());
        pix_.fill(palette().color(QPalette::Disabled, QPalette::Button));
        return;
    }

    QFont font;
    QFontMetrics fm(font);
    int h = height();  //fm.height()+4;
    int w = width() / ((colours_.count() > 0) ? colours_.count() : 1);

    cellWidth_ = w;

    pix_ = QPixmap(width(), h);
    QPainter painter(&pix_);
    painter.setPen(QColor(40, 40, 40));

    if (edited_) {
        pix_.fill(Qt::gray);

        for (int i = 0; i < colours_.count(); i++) {
            painter.setBrush(colours_[i]);
            int cx = i * cellWidth_;
            int cy = editorGapY_;
            int cw = cellWidth_;
            int ch = h - 2 * editorGapY_ - 1;

            if (i == 0) {
                cx += editorGapX_;
                cw -= editorGapX_;
            }
            else if (i == colours_.count() - 1) {
                cw -= editorGapX_;
            }

            QRect r(cx, cy, cw, ch);

            if (colours_[i].alpha() != 255)
                MvQPalette::paintAlphaBg(&painter, r);

            painter.drawRect(r);
        }
    }
    else {
        for (int i = 0; i < colours_.count(); i++) {
            painter.setBrush(colours_[i]);
            int cx = i * cellWidth_;
            int cy = 0;
            int cw = cellWidth_;
            int ch = h - 1;

            QRect r(cx, cy, cw, ch);

            if (colours_[i].alpha() != 255)
                MvQPalette::paintAlphaBg(&painter, r);

            painter.drawRect(r);
        }
    }

    if (colours_.count() == 0)
        pix_.fill(palette().color(QPalette::Window));
}

void MvQColourListWidget::renderCurrentCell(QPainter* painter)
{
    if (edited_ and colours_.count() > 1 and currentCell_ >= 0 && currentCell_ < colours_.count()) {
        int cx = currentCell_ * cellWidth_;
        int cy = 0;
        int cw = cellWidth_;
        int ch = pix_.height() - 1;

        if (currentCell_ == 0) {
            cx += editorGapX_;
            cw -= editorGapX_;
        }
        else if (currentCell_ == colours_.count() - 1) {
            cw -= editorGapX_;
        }

        QRect r(cx, cy, cw, ch);

        if (colours_[currentCell_].alpha() != 255)
            MvQPalette::paintAlphaBg(painter, r);

        painter->setPen(blackPen_);
        painter->fillRect(r, colours_[currentCell_]);
        painter->drawRect(cx - 1, cy + 1, cw + 2, ch - 2);
    }
}

QColor MvQColourListWidget::currentColour() const
{
    if (currentCell_ >= 0 && currentCell_ < colours_.count())
        return colours_[currentCell_];

    return QColor();
}

void MvQColourListWidget::setCurrentColour(QColor col)
{
    if (col.isValid() &&
        currentCell_ >= 0 && currentCell_ < colours_.count()) {
        colours_[currentCell_] = col;
        createPixmap();
        update();
        emit changed();
    }
}

void MvQColourListWidget::slotInsertBeforeCell()
{
    insertBeforeCell(currentCell_);
}

void MvQColourListWidget::slotInsertAfterCell()
{
    insertAfterCell(currentCell_);
}

void MvQColourListWidget::slotDeleteCell()
{
    deleteCell(currentCell_);
}

void MvQColourListWidget::deleteCell(int index)
{
    if (colours_.count() > 1 && index >= 0 && index < colours_.count()) {
        colours_.removeAt(index);

        createPixmap();
        if (index < colours_.count() - 1)
            setCurrentCell(index);
        else
            setCurrentCell(colours_.count() - 1);

        emit changed();

        checkActionState();
    }
}


void MvQColourListWidget::insertBeforeCell(int index)
{
    if (index >= 0 && index < colours_.count()) {
        QColor col = colours_[index];
        colours_.insert(index, col);

        createPixmap();
        setCurrentCell(index);
        emit changed();
    }
}


void MvQColourListWidget::insertAfterCell(int index)
{
    if (index >= 0 && index < colours_.count()) {
        QColor col = colours_[index];
        colours_.insert(index + 1, col);

        createPixmap();
        setCurrentCell(index + 1);
        emit changed();
    }
}

void MvQColourListWidget::setEdited(bool edited)
{
    if (edited_ != edited) {
        edited_ = edited;
        createPixmap();
        update();
    }
}

void MvQColourListWidget::slotCopyColourList()
{
    if (!colours_.isEmpty()) {
        MvQ::toClipboard(MvQPalette::toStringAsList(colours_));
    }
}

void MvQColourListWidget::slotCopyColour()
{
    QColor col = currentColour();
    if (col.isValid()) {
        MvQ::toClipboard("\"" + QString::fromStdString(MvQPalette::toString(col)) + "\"");
    }
}

void MvQColourListWidget::slotCopyRgb()
{
    QColor col = currentColour();
    if (col.isValid()) {
        MvQ::toClipboard(MvQPalette::toRgbString(col));
    }
}

void MvQColourListWidget::slotCopyHsl()
{
    QColor col = currentColour();
    if (col.isValid()) {
        MvQ::toClipboard(MvQPalette::toHslString(col));
    }
}

void MvQColourListWidget::slotPasteColour()
{
    QString txt = MvQ::fromClipboard();
    if (!txt.isEmpty()) {
        QColor col = MvQPalette::magics(txt.toStdString());
        if (col.isValid() && currentCell_ != -1) {
            colours_[currentCell_] = col;
            update();
            emit currentChanged(colours_[currentCell_]);
        }
    }
}

void MvQColourListWidget::slotPasteColourList()
{
    QString txt        = MvQ::fromClipboard();
    QList<QColor> cLst = MvQPalette::toColourList(txt);
    if (cLst.count() > 0) {
        colours_ = cLst;
        update();
        emit currentChanged(colours_[0]);
    }
}

//==============================================
//
// MvQColourListLine
//
//==============================================

MvQColourListLine::MvQColourListLine(RequestPanel& owner, const MvIconParameter& param) :
    MvQRequestPanelLine(owner, param)
{
    widget_ = new MvQColourListWidget(parentWidget_);

    QFont font;
    QFontMetrics fm(font);
    //int h=fm.height()+4;

    owner_.addWidget(widget_, row_, WidgetColumn);

    connect(widget_, SIGNAL(currentChanged(QColor)),
            this, SLOT(slotCurrentChanged(QColor)));

    connect(widget_, SIGNAL(changed()),
            this, SLOT(slotListChanged()));

    connect(widget_, SIGNAL(singleCellClicked()),
            this, SLOT(slotSingleCellClicked()));
}


void MvQColourListLine::buildHelper()
{
    MvQRequestPanelLine::buildHelper();

    //Customisation
    if (helper_)
        helper_->setExternalActions(widget_->actions());

    /*connect(helper_,SIGNAL(insertBefore()),
                widget_,SLOT(slotInsertBeforeCell()));
		
	connect(helper_,SIGNAL(insertAfter()),
                widget_,SLOT(slotInsertAfterCell()));
			
	connect(helper_,SIGNAL(deleteCell()),
                widget_,SLOT(slotDeleteCell()));*/
}

void MvQColourListLine::slotHelperOpened(bool b)
{
    widget_->setEdited(b);
    updateHelper();
}

void MvQColourListLine::refresh(const std::vector<std::string>& values)
{
    if (values.size() > 0) {
        QList<QColor> colours;

        for (const auto& value : values) {
            QString name = QString::fromStdString(value);
            colours << MvQPalette::magics(value);
        }

        widget_->setColours(colours);
    }

    //changed_ = false;
}


void MvQColourListLine::slotListChanged()
{
    std::vector<std::string> vals;
    foreach (QColor col, widget_->colours()) {
        vals.push_back(MvQPalette::toString(col));
    }

    owner_.set(param_.name(), vals);
}

void MvQColourListLine::slotSingleCellClicked()
{
    if (helpTb_) {
        if (!helpTb_->isChecked())
            helpTb_->toggle();
    }
}

void MvQColourListLine::updateHelper()
{
    if (!helper_)
        return;

    std::vector<std::string> vals;
    vals.push_back(MvQPalette::toString(widget_->currentColour()));
    helper_->refresh(vals);
}

void MvQColourListLine::slotCurrentChanged(QColor)
{
    updateHelper();
}

void MvQColourListLine::slotHelperEdited(const std::vector<std::string>& vals)
{
    if (vals.size() == 0)
        return;

    QString name = QString::fromStdString(vals[0]);
    widget_->setCurrentColour(MvQPalette::magics(vals[0]));
}


static LineMaker<MvQColourListLine> maker1("colourlist");
