/***************************************************************************
 *   Copyright (C) 2016 The Qt Company Ltd.                                *
 *   Copyright (C) 2016-2024 by Ilya Kotov                                 *
 *   forkotov02@ya.ru                                                      *
 *                                                                         *
 *   This program 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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

//Based on QTabWidget class copyrighted by Qt Company Ltd.

#include <QStylePainter>
#include <QSettings>
#include <QApplication>
#include <QStyleOptionTabWidgetFrame>
#include <qmmpui/playlistmanager.h>
#include "qsuitabwidget.h"

QSUiTabWidget::QSUiTabWidget(QWidget *parent) : QWidget(parent)
{
    m_tabBar = new QSUiTabBar(this);
    m_tabBar->setMovable(true);
    m_tabBar->setExpanding(false);
    m_listWidget = new QSUiListWidget(PlayListManager::instance()->selectedPlayList(), this);
    m_listWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
                                            QSizePolicy::TabWidget));
    setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding,
                              QSizePolicy::TabWidget));


    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(m_tabBar);

    m_menu = new QMenu(this);
    m_group = new QActionGroup(this);
    m_group->setExclusive(true);
    connect(m_tabBar, &QSUiTabBar::tabMoved, this, &QSUiTabWidget::tabMoved);
    connect(m_tabBar, &QSUiTabBar::tabMoved, this, &QSUiTabWidget::updateActions);
    connect(m_tabBar, &QSUiTabBar::tabCloseRequested, this, &QSUiTabWidget::tabCloseRequested);
    connect(m_tabBar, &QSUiTabBar::currentChanged, this, &QSUiTabWidget::onCurrentChanged);
    connect(m_menu, &QMenu::triggered, this, &QSUiTabWidget::onActionTriggered);
    readSettings();
}

QSUiTabBar *QSUiTabWidget::tabBar() const
{
    return m_tabBar;
}

QSUiListWidget *QSUiTabWidget::listWidget() const
{
    return m_listWidget;
}

void QSUiTabWidget::setCornerWidget(QWidget *widget, Qt::Corner corner)
{
    if(widget && widget->parentWidget() != this)
            widget->setParent(this);

    if(corner & Qt::TopRightCorner)
    {
        if(m_rightCornerWidget)
            m_rightCornerWidget->hide();
        m_rightCornerWidget = widget;
    }
    else
    {
        if(m_leftCornerWidget)
            m_leftCornerWidget->hide();
        m_leftCornerWidget = widget;
    }
    setUpLayout();
}

void QSUiTabWidget::readSettings()
{
    QSettings settings;
    settings.beginGroup(u"Simple"_s);
    m_tabBar->setTabsClosable(settings.value(u"pl_tabs_closable"_s, false).toBool());
    QFont tab_font = qApp->font(m_tabBar);
    if(!settings.value(u"use_system_fonts"_s, true).toBool())
    {
        tab_font.fromString(settings.value(u"pl_tabs_font"_s, tab_font.toString()).toString());
    }
    m_tabBar->setFont(tab_font);
    m_tabBar->setShape(static_cast<QTabBar::Shape>(settings.value(u"pl_tab_position"_s, QTabBar::RoundedNorth).toInt()));
    settings.endGroup();
    m_tabBar->updateGeometry();
    setUpLayout();
}

QMenu *QSUiTabWidget::menu() const
{
    return m_menu;
}

void QSUiTabWidget::setTabText(int index, const QString &text)
{
    QString tabText = text;
    tabText.replace(u"&"_s, u"&&"_s);
    m_tabBar->setTabText(index, tabText);
    m_menu->actions().at(index)->setText(tabText);
}

int QSUiTabWidget::addTab(const QString &label)
{
    return insertTab(-1, label);
}

int QSUiTabWidget::addTab(const QIcon &icon, const QString &label)
{
    return insertTab(-1, icon, label);
}

int QSUiTabWidget::insertTab(int index, const QString &label)
{
    return insertTab(index, QIcon(), label);
}

int QSUiTabWidget::insertTab(int index, const QIcon &icon, const QString &label)
{
    QString tabText = label;
    index = m_tabBar->insertTab(index, icon, tabText.replace(u"&"_s, u"&&"_s));
    setUpLayout();
    tabInserted(index);
    return index;
}

void QSUiTabWidget::removeTab(int index)
{
    m_tabBar->removeTab(index);
    setUpLayout();
    tabRemoved(index);
}

void QSUiTabWidget::setTabsVisible(bool visible)
{
    m_tabBar->setVisible(visible);
}

void QSUiTabWidget::setCurrentIndex(int index)
{
    m_tabBar->setCurrentIndex(index);
}

void QSUiTabWidget::onCurrentChanged(int index)
{
    emit currentChanged(index);
    if(index >= m_menu->actions().count())
        return;
    m_menu->actions().at(index)->setChecked(true);
}

void QSUiTabWidget::onActionTriggered(QAction *action)
{
    m_tabBar->setCurrentIndex(m_menu->actions().indexOf(action));
}

void QSUiTabWidget::updateActions()
{
    for(int i = 0; i < m_menu->actions().size(); ++i)
    {
        m_menu->actions().at(i)->setText(m_tabBar->tabText(i));
    }
    m_menu->actions().at(m_tabBar->currentIndex())->setChecked(true);
}

void QSUiTabWidget::initStyleOption(QStyleOptionTabWidgetFrame *option) const
{
    if(!option)
        return;

    option->initFrom(this);
    option->shape = m_tabBar->shape();
    option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this);

    int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, nullptr, this);
    QSize t(0, 0);
    if(m_tabBar->isVisibleTo(const_cast<QSUiTabWidget *>(this)))
        t = m_tabBar->sizeHint();

    if(m_rightCornerWidget)
    {
        const QSize rightCornerSizeHint = m_rightCornerWidget->sizeHint();
        const QSize bounds(rightCornerSizeHint.width(), t.height() - exth);
        option->rightCornerWidgetSize = rightCornerSizeHint.boundedTo(bounds);
    }
    else
    {
        option->rightCornerWidgetSize = QSize(0, 0);
    }

    if(m_leftCornerWidget)
    {
        const QSize leftCornerSizeHint = m_leftCornerWidget->sizeHint();
        const QSize bounds(leftCornerSizeHint.width(), t.height() - exth);
        option->leftCornerWidgetSize = leftCornerSizeHint.boundedTo(bounds);
    }
    else
    {
        option->leftCornerWidgetSize = QSize(0, 0);
    }

    option->tabBarSize = t;

    QRect tbRect = m_tabBar->geometry();
    QRect selectedTabRect = tabBar()->tabRect(tabBar()->currentIndex());
    option->tabBarRect = tbRect;
    selectedTabRect.moveTopLeft(selectedTabRect.topLeft() + tbRect.topLeft());
    option->selectedTabRect = selectedTabRect;
}

void QSUiTabWidget::setUpLayout()
{
    QStyleOptionTabWidgetFrame option;
    initStyleOption(&option);

    QRect tabRect = style()->subElementRect(QStyle::SE_TabWidgetTabBar, &option, this);
    m_panelRect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this);
    QRect contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this);
    QRect leftCornerRect = style()->subElementRect(QStyle::SE_TabWidgetLeftCorner, &option, this);
    QRect rightCornerRect = style()->subElementRect(QStyle::SE_TabWidgetRightCorner, &option, this);

    m_tabBar->setGeometry(tabRect);
    m_listWidget->setGeometry(contentsRect);
    if(m_leftCornerWidget)
        m_leftCornerWidget->setGeometry(leftCornerRect);
    if(m_rightCornerWidget)
        m_rightCornerWidget->setGeometry(rightCornerRect);

    updateGeometry();
}

void QSUiTabWidget::showEvent(QShowEvent *)
{
    setUpLayout();
}

void QSUiTabWidget::resizeEvent(QResizeEvent *e)
{
    QWidget::resizeEvent(e);
    if(isVisible())
        setUpLayout();
}

void QSUiTabWidget::paintEvent(QPaintEvent *)
{
    if(!m_tabBar->isVisibleTo(this))
        return;
    QStylePainter p(this);

    QStyleOptionTabWidgetFrame opt;
    initStyleOption(&opt);
    opt.rect = m_panelRect;
    p.drawPrimitive(QStyle::PE_FrameTabWidget, opt);
}

void QSUiTabWidget::changeEvent(QEvent *ev)
{
    if(ev->type() == QEvent::StyleChange
#ifdef Q_OS_MAC
            || ev->type() == QEvent::MacSizeChange
#endif
            )
        setUpLayout();
    QWidget::changeEvent(ev);
}

bool QSUiTabWidget::event(QEvent *ev)
{
    if(ev->type() == QEvent::LayoutRequest)
        setUpLayout();
    return QWidget::event(ev);
}

void QSUiTabWidget::tabInserted(int index)
{
    QAction *action = new QAction(m_menu);
    action->setCheckable(true);
    action->setActionGroup(m_group);
    action->setText(m_tabBar->tabText(index));

    if(m_menu->actions().isEmpty() || index == m_menu->actions().count())
    {
        m_menu->addAction(action);
    }
    else
    {
        QAction *before = m_menu->actions().at(index);
        m_menu->insertAction(before, action);
    }
    if(m_tabBar->currentIndex() == index)
        action->setChecked(true);
}

void QSUiTabWidget::tabRemoved(int index)
{
    QAction *a = m_menu->actions().at(index);
    m_menu->removeAction(a);
    delete a;
}

void QSUiTabWidget::mousePressEvent(QMouseEvent *e)
{
    if((e->button() == Qt::MiddleButton) && (childAt(e->pos()) == nullptr))
    {
        e->accept();
        emit createPlayListRequested();
    }
    QWidget::mousePressEvent(e);
}

void QSUiTabWidget::mouseDoubleClickEvent(QMouseEvent *e)
{
    if((e->button() == Qt::LeftButton) &&
            (childAt(e->pos()) == nullptr))
    {
        e->accept();
        emit createPlayListRequested();
    }
    QWidget::mouseDoubleClickEvent(e);
}
