/***************************** 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 <QDebug>
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QPainter>
#include <QStackedWidget>
#include <QStyle>
#include <QStyleOption>
#include <QTabBar>
#include <QToolButton>
#include <QVBoxLayout>

#include "MvQDrawerPanel.h"

#include "MvQContextMenu.h"

//==============================================
//
//     MvQDrawerTabBar
//
//==============================================

MvQDrawerTabBar::MvQDrawerTabBar(QWidget* parent) :
    QTabBar(parent)
{
}

void MvQDrawerTabBar::mousePressEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton) {
        event->ignore();
        emit leftClicked(tabAt(event->pos()));
        return;
    }

    QTabBar::mousePressEvent(event);
}

//==============================================
//
//     MvQDrawerPanel
//
//==============================================

MvQDrawerPanel::MvQDrawerPanel(QWidget* parent) :
    QWidget(parent),
    sorted_(true)
{
    setProperty("helper", "true");


    auto* layout = new QVBoxLayout(this);
    layout->setSpacing(0);
    layout->setContentsMargins(0, 0, 0, 0);

    barLayout_ = new QHBoxLayout;
    barLayout_->setSpacing(0);
    barLayout_->setContentsMargins(0, 0, 0, 0);
    layout->addLayout(barLayout_, Qt::AlignBottom);

    bar_ = new MvQDrawerTabBar(this);

    // bar_->setDrawBase(false);
    // bar_->setDocumentMode(true);
    bar_->setExpanding(true);
    barLayout_->addWidget(bar_);

    QFont f;
    QFontMetrics fm(f);

    stacked_ = new QStackedWidget(this);
    stacked_->setFixedHeight(2 + 6 + 20 + 5 + fm.height() + 6 + 20);
    stacked_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

    layout->addWidget(stacked_);

    connect(bar_, SIGNAL(currentChanged(int)),
            stacked_, SLOT(setCurrentIndex(int)));

    connect(bar_, SIGNAL(leftClicked(int)),
            this, SLOT(slotTabClicked(int)));

    // Contextmenu
    bar_->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(bar_, SIGNAL(customContextMenuRequested(const QPoint&)),
            this, SLOT(slotContextMenu(const QPoint&)));


    openIcon_ = QIcon(QPixmap(":/desktop/drawer_open.svg"));
    closeIcon_ = QIcon(QPixmap(":/desktop/drawer_close.svg"));
    noIcon_ = QIcon();
}

MvQDrawerPanel::~MvQDrawerPanel() = default;


void MvQDrawerPanel::addCornerButton(QAbstractButton* b)
{
    barLayout_->addSpacing(4);
    barLayout_->addWidget(b);
}

void MvQDrawerPanel::addDrawer(QWidget* w, QString name)
{
    bar_->addTab(name);
    stacked_->addWidget(w);

    // Add tool button
    auto* tb = new QToolButton(this);
    tb->setToolButtonStyle(Qt::ToolButtonIconOnly);
    tb->setAutoRaise(true);
    tb->setIconSize(QSize(12, 12));
    tb->setObjectName("drawerTabTb");
    bar_->setTabButton(bar_->count() - 1, QTabBar::RightSide, tb);

    connect(tb, SIGNAL(clicked()),
            this, SLOT(slotTabButton()));

    if (sorted_)
        sortDrawers();

    setCurrent(name);
}


void MvQDrawerPanel::renameDrawer(int index, QString name)
{
    if (index >= 0 && index < bar_->count()) {
        bar_->setTabText(index, name);

        if (sorted_)
            sortDrawers();
    }
}

void MvQDrawerPanel::deleteDrawer(int index)
{
    if (index >= 0 && index < bar_->count()) {
        QWidget* w = stacked_->widget(index);
        bar_->removeTab(index);
        stacked_->removeWidget(w);
        w->hide();
        w->deleteLater();
    }
}

void MvQDrawerPanel::sortDrawers()
{
    QMap<QString, int> oriIdx;
    QStringList ori, sorted;

    for (int i = 0; i < bar_->count(); i++) {
        oriIdx[bar_->tabText(i)] = i;
        ori << bar_->tabText(i);
    }


    sorted = ori;
    sorted.sort();

    // qDebug() << oriIdx;
    // qDebug() << ori;
    // qDebug() << sorted;

    for (int i = 0; i < sorted.count(); i++) {
        // qDebug() << i << sorted[i] <<bar_->tabText(i);

        if (sorted[i] != bar_->tabText(i)) {
            int from = oriIdx[sorted[i]];
            int to = i;

            // qDebug() << "--> to from" << to << from;

            bar_->moveTab(from, to);

            QWidget* w = stacked_->widget(from);
            stacked_->removeWidget(w);
            stacked_->insertWidget(to, w);
        }
    }
}

void MvQDrawerPanel::setCurrent(QString name)
{
    for (int i = 0; i < bar_->count(); i++)
        if (bar_->tabText(i) == name) {
            bar_->setCurrentIndex(i);
            updateTabButtonStatus();
            return;
        }
}


int MvQDrawerPanel::drawerCount()
{
    return stacked_->count();
}

int MvQDrawerPanel::drawerIndex(QWidget* w)
{
    return stacked_->indexOf(w);
}

QWidget* MvQDrawerPanel::drawer(int index)
{
    return (index >= 0 && index < stacked_->count()) ? stacked_->widget(index) : nullptr;
}

QString MvQDrawerPanel::drawerText(int index)
{
    return bar_->tabText(index);
}

void MvQDrawerPanel::slotTabClicked(int index)
{
    bool changed = false;

    if (index != bar_->currentIndex()) {
        bar_->setCurrentIndex(index);
        changed = true;
    }

    if (changed) {
        stacked_->show();
    }
    else {
        if (!stacked_->isVisible()) {
            stacked_->show();
        }
        else {
            stacked_->hide();
        }
    }

    updateTabButtonStatus();
}

void MvQDrawerPanel::shrink()
{
    stacked_->hide();
}

void MvQDrawerPanel::updateTabButtonStatus()
{
    if (stacked_->isVisible()) {
        for (int i = 0; i < bar_->count(); i++) {
            if (i == bar_->currentIndex())
                setTabButtonStatus(i, closeIcon_, tr("Close drawer"));
            else
                setTabButtonStatus(i, noIcon_, "");
        }
    }
    else {
        for (int i = 0; i < bar_->count(); i++)
            setTabButtonStatus(i, openIcon_, tr("Open drawer"));
    }
}

void MvQDrawerPanel::slotTabButton()
{
    if (auto* w = dynamic_cast<QWidget*>(sender())) {
        for (int i = 0; i < bar_->count(); i++)
            if (w == bar_->tabButton(i, QTabBar::RightSide)) {
                slotTabClicked(i);
                break;
            }
    }
}

void MvQDrawerPanel::setTabButtonStatus(int index, const QIcon& icon, QString txt)
{
    if (QWidget* w = bar_->tabButton(index, QTabBar::RightSide))
        if (auto* tb = dynamic_cast<QToolButton*>(w)) {
            tb->setIcon(icon);
            tb->setToolTip(txt);
        }
}


//----------------------------------------------
// Context menu
//----------------------------------------------

void MvQDrawerPanel::slotContextMenu(const QPoint& pos)
{
    MvQContextItemSet* cms = cmSet();
    if (!cms)
        return;

    if (pos.isNull())
        return;

    int index = bar_->tabAt(pos);

    QString selected = MvQContextMenu::instance()->exec(cms->icon(), mapToGlobal(pos), this);
    if (!selected.isEmpty())

        command(selected, index);
}

void MvQDrawerPanel::paintEvent(QPaintEvent*)
{
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
