#include "optionstab.h"

#include "iconset.h"

#include <QLayout>
#include <QMap>
#include <QTabWidget>
#include <QVBoxLayout>

//----------------------------------------------------------------------------
// OptionsTab
//----------------------------------------------------------------------------

OptionsTab::OptionsTab(QObject *parent, const char *name) : QObject(parent) { setObjectName(name); }

OptionsTab::OptionsTab(QObject *parent, QByteArray _id, QByteArray _parentId, QString _name, QString _desc,
                       QString _tabIconName, QString _iconName) :
    QObject(parent)
{
    setObjectName(_name);
    v_id          = _id;
    v_parentId    = _parentId;
    v_name        = _name;
    v_desc        = _desc;
    v_tabIconName = _tabIconName;
    v_iconName    = _iconName;
}

OptionsTab::~OptionsTab() { }

QByteArray OptionsTab::id() const { return v_id; }

QByteArray OptionsTab::parentId() const { return v_parentId; }

QString OptionsTab::tabName() const { return v_name; }

QIcon OptionsTab::tabIcon() const
{
    if (v_tabIconName.isEmpty())
        return QIcon();

    auto icon = const_cast<PsiIcon *>(IconsetFactory::iconPtr(v_tabIconName));
    return icon ? icon->icon() : QIcon();
}

QString OptionsTab::name() const { return v_name; }

QString OptionsTab::desc() const { return v_desc; }

PsiIcon *OptionsTab::psiIcon() const
{
    if (v_iconName.isEmpty()) {
        // if ( tabIcon() )
        //    return tabIcon();

        return const_cast<PsiIcon *>(IconsetFactory::iconPtr("psi/logo_32"));
    }

    return const_cast<PsiIcon *>(IconsetFactory::iconPtr(v_iconName));
}

void OptionsTab::applyOptions() { }

void OptionsTab::restoreOptions() { }

void OptionsTab::tabAdded(OptionsTab *) { }

bool OptionsTab::stretchable() const { return false; }

void OptionsTab::setData(PsiCon *, QWidget *) { }

//----------------------------------------------------------------------------
// OptionsTabWidget
//----------------------------------------------------------------------------

class OptionsTabWidget : public QTabWidget {
    Q_OBJECT
public:
    OptionsTabWidget(QWidget *parent);
    void addTab(OptionsTab *);
    void restoreOptions();
    void enableOtherTabs(bool);

signals:
    void connectDataChanged(QWidget *);
    void noDirty(bool);

private slots:
    void updateCurrent(int);

private:
    struct TabData {
        TabData()
        {
            tab         = nullptr;
            initialized = false;
        }
        TabData(OptionsTab *t)
        {
            tab         = t;
            initialized = false;
        }
        OptionsTab *tab;
        bool        initialized;
    };
    QMap<QWidget *, TabData> w2tab;
};

OptionsTabWidget::OptionsTabWidget(QWidget *parent) : QTabWidget(parent)
{
    connect(this, SIGNAL(currentChanged(int)), SLOT(updateCurrent(int)));
}

void OptionsTabWidget::addTab(OptionsTab *tab)
{
    if (tab->tabName().isEmpty())
        return; // skip the dummy tabs

    // the widget will have no parent; it will be reparented
    // when inserting it with "addTab"
    QWidget *w = new QWidget(nullptr);
    w->setObjectName(tab->name());

    if (!tab->desc().isEmpty())
        setTabToolTip(indexOf(w), tab->desc());

    w2tab[w] = TabData(tab);

    auto icon = tab->tabIcon();
    if (!icon.isNull())
        QTabWidget::addTab(w, icon, tab->tabName());
    else
        QTabWidget::addTab(w, tab->tabName());

    setCurrentIndex(0);
}

void OptionsTabWidget::updateCurrent(int index)
{
    Q_UNUSED(index)
    QWidget *w = currentWidget();
    if (!w2tab[w].initialized) {
        QVBoxLayout *vbox = new QVBoxLayout(w);
        vbox->setMargin(5);
        OptionsTab *opttab = w2tab[w].tab;

        QWidget *tab = opttab->widget();
        if (!tab)
            return;

        tab->setParent(w);
        vbox->addWidget(tab);
        if (!opttab->stretchable())
            vbox->addStretch();

        emit noDirty(true);
        opttab->restoreOptions();
        emit noDirty(false);

        emit connectDataChanged(tab);

        tab->show();
        w2tab[w].initialized = true;
    }
}

void OptionsTabWidget::restoreOptions()
{
    emit noDirty(true);
    w2tab[currentWidget()].tab->restoreOptions();
    emit noDirty(false);
}

void OptionsTabWidget::enableOtherTabs(bool enable)
{
    for (int i = 0; i < count(); i++) {
        if (i != currentIndex())
            setTabEnabled(i, enable);
    }
}

//----------------------------------------------------------------------------
// MetaOptionsTab
//----------------------------------------------------------------------------

MetaOptionsTab::MetaOptionsTab(QObject *parent, const char *name) : OptionsTab(parent, name) { init(); }

MetaOptionsTab::MetaOptionsTab(QObject *parent, QByteArray id, QByteArray parentId, QString name, QString desc,
                               QString tabIconName, QString iconName) :
    OptionsTab(parent, id, parentId, name, desc, tabIconName, iconName)
{
    init();
}

MetaOptionsTab::~MetaOptionsTab()
{
    qDeleteAll(tabs);

    // if ( w )   // it does not make much sense to delete it. since the widget will reparented and deleted
    // automatically
    //    delete w;
}

void MetaOptionsTab::init() { w = nullptr; }

void MetaOptionsTab::addTab(OptionsTab *tab)
{
    connect(tab, SIGNAL(dataChanged()), SIGNAL(dataChanged()));
    // connect(tab, SIGNAL(addWidgetChangedSignal(QString, QCString)), SIGNAL(addWidgetChangedSignal(QString,
    // QCString)));
    connect(tab, SIGNAL(noDirty(bool)), SIGNAL(noDirty(bool)));
    connect(tab, SIGNAL(connectDataChanged(QWidget *)), SIGNAL(connectDataChanged(QWidget *)));

    tabs.append(tab);
}

void MetaOptionsTab::enableOtherTabs(bool enable)
{
    if (!w)
        return;
    static_cast<OptionsTabWidget *>(w)->enableOtherTabs(enable);
}

QWidget *MetaOptionsTab::widget()
{
    if (w)
        return w;

    OptionsTabWidget *t = new OptionsTabWidget(nullptr);
    w                   = t;

    connect(w, SIGNAL(connectDataChanged(QWidget *)), SIGNAL(connectDataChanged(QWidget *)));
    connect(w, SIGNAL(noDirty(bool)), SIGNAL(noDirty(bool)));

    for (OptionsTab *tab : qAsConst(tabs)) {
        t->addTab(tab);
    }

    // set the current widget to 0, otherwise qt4 will show no widget
    t->setCurrentIndex(0);

    return w;
}

void MetaOptionsTab::applyOptions()
{
    for (OptionsTab *tab : qAsConst(tabs)) {
        tab->applyOptions();
    }
}

void MetaOptionsTab::restoreOptions()
{
    if (w) {
        OptionsTabWidget *d = static_cast<OptionsTabWidget *>(w);
        d->restoreOptions();
    }

    for (OptionsTab *tab : qAsConst(tabs)) {
        tab->restoreOptions();
    }
}

void MetaOptionsTab::setData(PsiCon *psi, QWidget *w)
{
    for (OptionsTab *tab : qAsConst(tabs)) {
        tab->setData(psi, w);
    }
}

#include "optionstab.moc"
