#include "tabmanager.h"

#include <QtAlgorithms>

#include "tabdlg.h"
#include "tabbablewidget.h"
#include "groupchatdlg.h"
#include "chatdlg.h"
#include "psioptions.h"

TabManager::TabManager(PsiCon* psiCon, QObject *parent)
    : QObject(parent)
    , psiCon_(psiCon)
    , tabDlgDelegate_(0)
    , userManagement_(true)
    , tabSingles_(true)
    , simplifiedCaption_(false)
{
}

TabManager::~TabManager()
{
    deleteAll();
}

PsiCon* TabManager::psiCon() const
{
    return psiCon_;
}

TabDlg* TabManager::getTabs(QWidget *widget)
{
    QChar kind = tabKind(widget);
    if (preferedTabsetForKind_.contains(kind)) {
        return preferedTabsetForKind_[kind];
    } else {
        return newTabs(widget);
    }
}

QChar TabManager::tabKind(QWidget *widget) {
    QChar retval = 0;

    if (qobject_cast<ChatDlg*> (widget)) {
        retval = 'C';
    } else if (qobject_cast<GCMainDlg*> (widget)) {
        retval = 'M';
    } else {
        qDebug("Checking if widget should be tabbed: Unknown type");
    }
    return retval;
}

bool TabManager::shouldBeTabbed(QWidget *widget)
{
    if (!PsiOptions::instance()->getOption("options.ui.tabs.use-tabs").toBool()) {
        return false;
    }

    QString grouping = PsiOptions::instance()->getOption("options.ui.tabs.grouping").toString();
    if (grouping.contains(tabKind(widget))) {
        return true;
    }
    return false;
}

TabDlg* TabManager::newTabs(QWidget *widget)
{
    QChar kind = tabKind(widget);
    QString group, grouping = PsiOptions::instance()->getOption("options.ui.tabs.grouping").toString();
    foreach(QString g, grouping.split(':')) {
        if (g.contains(kind)) {
            group = g;
            break;
        }
    }

    QString geometryOption = QString("options.ui.tabs.group-state.%1.size").arg(group);

    TabDlg *tab = new TabDlg(this, geometryOption, tabDlgDelegate_);
    tab->setUserManagementEnabled(userManagement_);
    tab->setTabBarShownForSingles(tabSingles_);
    tab->setSimplifiedCaptionEnabled(simplifiedCaption_);
    tabsetToKinds_.insert(tab, group);
    for (int i=0; i < group.length(); i++) {
        QChar k = group.at(i);
        if (!preferedTabsetForKind_.contains(k)) {
            preferedTabsetForKind_.insert(k, tab);
        }
    }
    tabs_.append(tab);
    connect(tab, SIGNAL(destroyed(QObject*)), SLOT(tabDestroyed(QObject*)));
    connect(psiCon_, SIGNAL(emitOptionsUpdate()), tab, SLOT(optionsUpdate()));
    return tab;
}

void TabManager::tabDestroyed(QObject* obj)
{
    Q_ASSERT(tabs_.contains(static_cast<TabDlg*>(obj)));
    tabs_.removeAll(static_cast<TabDlg*>(obj));
    tabsetToKinds_.remove(static_cast<TabDlg*>(obj));
    QMutableMapIterator<QChar, TabDlg*> it(preferedTabsetForKind_);
    while (it.hasNext()) {
        it.next();
        if (preferedTabsetForKind_[it.key()] != obj) continue;
        bool ok = false;
        foreach(TabDlg* tabDlg, tabs_) {
            // currently destroyed tab is removed from the list a few lines above
            if (tabsetToKinds_[tabDlg].contains(it.key())) {
                preferedTabsetForKind_[it.key()] = tabDlg;
                ok = true;
                break;
            }
        }
        if (!ok) it.remove();
    }
}

TabDlg *TabManager::preferredTabsForKind(QChar kind) {
    return preferedTabsetForKind_.value(kind);
}

void TabManager::setPreferredTabsForKind(QChar kind, TabDlg *tab) {
    Q_ASSERT(tabs_.contains(tab));
    preferedTabsetForKind_[kind] = tab;
}

bool TabManager::isChatTabbed(const TabbableWidget* chat) const
{
    foreach(TabDlg* tabDlg, tabs_) {
        if (tabDlg->managesTab(chat)) {
            return true;
        }
    }
    return false;
}

TabDlg* TabManager::getManagingTabs(const TabbableWidget* chat) const
{
    //FIXME: this looks like it could be broken to me (KIS)
    //Does this mean that opening two chats to the same jid will go wrong?
    foreach(TabDlg* tabDlg, tabs_) {
        if (tabDlg->managesTab(chat)) {
            return tabDlg;
        }
    }
    return 0;
}

const QList<TabDlg*>& TabManager::tabSets()
{
    return tabs_;
}

void TabManager::deleteAll()
{
    qDeleteAll(tabs_);
    tabs_.clear();
}

void TabManager::setTabDlgDelegate(TabDlgDelegate *delegate)
{
    tabDlgDelegate_ = delegate;
}

void TabManager::setUserManagementEnabled(bool enabled)
{
    if (userManagement_ == enabled) {
        return;
    }

    userManagement_ = enabled;
    foreach (TabDlg *tab, tabs_) {
        tab->setUserManagementEnabled(enabled);
    }
}

void TabManager::setTabBarShownForSingles(bool enabled)
{
    if (tabSingles_ == enabled) {
        return;
    }

    tabSingles_ = enabled;
    foreach (TabDlg *tab, tabs_) {
        tab->setTabBarShownForSingles(enabled);
    }
}

void TabManager::setSimplifiedCaptionEnabled(bool enabled)
{
    if (simplifiedCaption_ == enabled) {
        return;
    }

    simplifiedCaption_ = enabled;
    foreach (TabDlg *tab, tabs_) {
        tab->setSimplifiedCaptionEnabled(enabled);
    }
}
