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

 Copyright 2013 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 "MvQFolderViewDelegate.h"

#include <QApplication>
#include <QDebug>
#include <QLinearGradient>
#include <QLineEdit>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QTimer>

#include "MvQFolderModel.h"
#include "MvQMethods.h"
#include "MvQTheme.h"

//===========================================
//
//  MvQFolderViewDelegate
//
//===========================================

MvQFolderViewDelegate::MvQFolderViewDelegate(QWidget* parent) :
    QStyledItemDelegate(parent),
    timer_(nullptr),
    blinkCnt_(-1),
    blinkNum_(5),
    enablePaint_(true)
{
    setColours();
}

void MvQFolderViewDelegate::setColours()
{
    QString group = "folderview";
    editPen_ = QPen(MvQTheme::colour(group, "edit_pen"));
    editBrush_ = MvQTheme::brush(group, "edit_brush");
    hoverPen_ = QPen(MvQTheme::colour(group, "hover_pen"));
    hoverBrush_ = MvQTheme::brush(group, "hover_brush");
    selectPen_ = QPen(MvQTheme::colour(group, "select_pen"));
    selectBrush_ = MvQTheme::brush(group, "select_brush");
}

void MvQFolderViewDelegate::blink(const QModelIndex& index)
{
    blinkIndex_ = index;
    if (!timer_) {
        timer_ = new QTimer(this);
        connect(timer_, SIGNAL(timeout()),
                this, SLOT(slotBlink()));
    }

    blinkCnt_ = 0;
    timer_->start(150);
}

void MvQFolderViewDelegate::slotBlink()
{
    emit repaintIt(blinkIndex_);
    if (blinkCnt_ == 2 * blinkNum_ + 1) {
        timer_->stop();
        blinkIndex_ = QModelIndex();
        blinkCnt_ = -1;
    }
    else
        blinkCnt_++;
}

QWidget* MvQFolderViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
                                             const QModelIndex& index) const
{
    if (index.column() == 0) {
        auto* le = new QLineEdit(parent);
        // timeEdit->setDisplayFormat("mm:ss");

        // connect(le,SIGNAL(editingFinished()),
        //	this,SLOT(commitAndCloseEditor()));
        QFont font;
        QFontMetrics fm(font);
        le->setMinimumHeight(fm.height() + 10);
        return le;
    }
    else {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}

void MvQFolderViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
    if (index.column() == 0) {
        auto* le = qobject_cast<QLineEdit*>(editor);
        le->setObjectName("iconLabel");
        QString txt = index.model()->data(index, Qt::EditRole).toString();
        le->setText(txt);

        QFont font;
        QFontMetrics fm(font);
        le->setMinimumWidth(MvQ::textWidth(fm, txt) + 16);

        le->setCursorPosition(0);
        le->deselect();

        connect(le, SIGNAL(cursorPositionChanged(int, int)),
                this, SLOT(slotInitEditor(int, int)));
    }
    else {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

void MvQFolderViewDelegate::setModelData(QWidget* editor,
                                         QAbstractItemModel* model,
                                         const QModelIndex& index) const
{
    if (index.column() == 0) {
        auto* le = qobject_cast<QLineEdit*>(editor);
        model->setData(index, le->text());
    }
    else {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}

void MvQFolderViewDelegate::slotInitEditor(int /*oldPos*/, int /*newPos*/)
{
    auto* le = qobject_cast<QLineEdit*>(sender());

    le->setCursorPosition(0);
    le->deselect();

    le->disconnect(SIGNAL(cursorPositionChanged(int, int)));
}

void MvQFolderViewDelegate::changeSize(const QModelIndex& index)
{
    emit sizeHintChanged(index);
}


//===========================================
//
//  MvQIconDelegate
//
//===========================================

MvQIconDelegate::MvQIconDelegate(QWidget* parent) :
    MvQFolderViewDelegate(parent)
{
}

void MvQIconDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
                            const QModelIndex& index) const
{
    if (!enablePaint_) {
        return;
    }

    if (index.column() == 0) {
        bool blink = (blinkCnt_ != -1 && (index == blinkIndex_ && blinkCnt_ % 2 == 0));

        QStyleOptionViewItem vopt(option);
        initStyleOption(&vopt, index);

        const QStyle* style = vopt.widget ? vopt.widget->style() : QApplication::style();
        const QWidget* widget = vopt.widget;

        auto pixmap = index.data(Qt::DecorationRole).value<QPixmap>();

        // Save painter state
        painter->save();


        QString text = index.data(Qt::DisplayRole).toString();
        QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);

        // Background

        if (blink) {
            QRect fillRect = option.rect.adjusted(0, 1, -1, -1);
            painter->fillRect(fillRect, Qt::black);
        }
        else if (index.data(MvQFolderModel::EditorRole).toBool()) {
            QRect fillRect = option.rect.adjusted(0, 1, -1, -1);
            painter->fillRect(fillRect, editBrush_);
            painter->setPen(editPen_);
            painter->drawRect(fillRect);
        }
        else if (option.state & QStyle::State_Selected) {
            // QRect fillRect=option.rect.adjusted(0,1,-1,-textRect.height()-1);
            QRect fillRect = option.rect.adjusted(0, 1, -1, -1);
            painter->fillRect(fillRect, selectBrush_);
            painter->setPen(selectPen_);
            painter->drawRect(fillRect);
        }
        else if (option.state & QStyle::State_MouseOver) {
            QRect fillRect = option.rect.adjusted(0, 1, -1, -1);
            painter->fillRect(fillRect, hoverBrush_);
            painter->setPen(hoverPen_);
            painter->drawRect(fillRect);
        }

        // Pixmap
        QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &vopt, widget);
        painter->drawPixmap(iconRect, pixmap);

        // Text rect
        auto font = index.data(Qt::FontRole).value<QFont>();
        painter->setFont(font);

        if (blink)
            painter->setPen(Qt::white);
        else
            painter->setPen(index.data(Qt::ForegroundRole).value<QColor>());

        painter->drawText(textRect, Qt::AlignLeft, text);

        painter->restore();
    }
    else {
        QStyledItemDelegate::paint(painter, option, index);
    }
}

QSize MvQIconDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    QSize s = QStyledItemDelegate::sizeHint(option, index);

    // qDebug() << "decoration" <<index.data(Qt::DisplayRole).toString() <<  option.decorationSize;

    return s;
}

//===========================================
//
//  MvDetailedViewDelegate
//
//===========================================

MvQDetailedViewDelegate::MvQDetailedViewDelegate(QWidget* parent) :
    MvQFolderViewDelegate(parent)
{
}

void MvQDetailedViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
                                    const QModelIndex& index) const
{
    if (index.column() <= 5) {
        bool blink = (blinkCnt_ != -1 && (index == blinkIndex_ && blinkCnt_ % 2 == 0));

        QStyleOptionViewItem vopt(option);
        initStyleOption(&vopt, index);

        const QStyle* style = vopt.widget ? vopt.widget->style() : QApplication::style();
        const QWidget* widget = vopt.widget;

        // Save painter state
        painter->save();

        // Get current values from model
        QString text = index.data(Qt::DisplayRole).toString();
        QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &vopt, widget);

        // Background
        if (index.column() == 0) {
            QRect fillRect = QRect(option.rect.x(), option.rect.y(), painter->device()->width(), option.rect.height());

            if (blink) {
                painter->fillRect(option.rect, Qt::black);
            }
            else if (index.data(MvQFolderModel::EditorRole).toBool()) {
                painter->fillRect(fillRect, editBrush_);
                //                painter->setPen(editPen_);
                //                painter->drawLine(fillRect.topLeft(), fillRect.topRight());
                //                painter->drawLine(fillRect.bottomLeft(), fillRect.bottomRight());
            }
            else if (option.state & QStyle::State_Selected) {
                // QRect fillRect=option.rect.adjusted(0,1,-1,-textRect.height()-1);
                painter->fillRect(fillRect, selectBrush_);
                //                painter->setPen(selectPen_);
                //                painter->drawLine(fillRect.topLeft(), fillRect.topRight());
                //                painter->drawLine(fillRect.bottomLeft(), fillRect.bottomRight());
            }
            else if (option.state & QStyle::State_MouseOver) {
                // QRect fillRect=option.rect.adjusted(0,1,-1,-1);
                painter->fillRect(fillRect, hoverBrush_);
                //                painter->setPen(hoverPen_);
                //                painter->drawLine(fillRect.topLeft(), fillRect.topRight());
                //                painter->drawLine(fillRect.bottomLeft(), fillRect.bottomRight());
            }
        }

        // Pixmap
        if (index.column() == 0) {
            auto pixmap = index.data(Qt::DecorationRole).value<QPixmap>();
            QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &vopt, widget);
            // iconRect.adjust(2,2,-2,-2);
            painter->drawPixmap(iconRect, pixmap);
        }


        // Text rect
        auto font = index.data(Qt::FontRole).value<QFont>();
        painter->setFont(font);
        if (blink)
            painter->setPen(Qt::white);
        else
            painter->setPen(index.data(Qt::ForegroundRole).value<QColor>());

        painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);

        // restore painter state
        painter->restore();
    }
    else {
        QStyledItemDelegate::paint(painter, option, index);
    }
}

QSize MvQDetailedViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    QSize size = QStyledItemDelegate::sizeHint(option, index);
    return size + QSize(0, 4);
}
