/***************************************************************************
 *   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   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, see <http://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
 * A widget to select what to show.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgshow.h"

#include <KLocale>
#include <KMenu>
#include <KIcon>

#include "skgservices.h"

SKGShow::SKGShow(QWidget* iParent)
    : QToolButton(iParent), m_mode(OR), m_inTrigger(false), m_displayTitle(true)
{
    setPopupMode(QToolButton::InstantPopup);
    setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    setAutoRaise(true);

    m_menu = new KMenu(this);
    setMenu(m_menu);

    // Time to emit stateChanged
    m_timer.setSingleShot(true);
    connect(&m_timer, SIGNAL(timeout()), this, SIGNAL(stateChanged()), Qt::QueuedConnection);

    hide();
}

SKGShow::~SKGShow()
{
    m_menu = NULL;
}

SKGShow::OperatorMode SKGShow::getMode()
{
    return m_mode;
}

void SKGShow::setMode(SKGShow::OperatorMode iMode)
{
    m_mode = iMode;
}

QString SKGShow::getState()
{
    QStringList itemsChecked;
    if (m_menu) {
        QList<QAction*> actionsList = m_menu->actions();
        int nb = actionsList.count();
        for (int i = 0; i < nb; ++i) {
            QAction* act = actionsList.at(i);
            if (act && act->isChecked()) itemsChecked.push_back(act->data().toString());
        }
    }
    return SKGServices::stringsToCsv(itemsChecked);
}

QString SKGShow::getWhereClause() const
{
    QString wc;
    if (m_menu) {
        QList<QAction*> actionsList = m_menu->actions();
        int nb = actionsList.count();
        bool noCheck = true;
        for (int i = 0; i < nb; ++i) {
            QAction* act = actionsList.at(i);
            if (act && act->isChecked()) {
                if (!wc.isEmpty()) wc += (m_mode == OR ? " OR " : " AND ");
                wc += '(' % m_whereclause[act] % ')';
                noCheck = false;

                if (m_whereclause[act].isEmpty()) {
                    wc = "";
                    break;
                }
            };
        }
        if (nb && noCheck) wc = "1=0";
    }
    return wc;
}

QString SKGShow::getTitle() const
{
    QString wc;
    if (m_menu) {
        int nb = m_actions.count();
        for (int i = 0; i < nb; ++i) {
            QAction* act = m_actions.at(i);
            if (act && act->isChecked()) {
                if (!wc.isEmpty()) wc += (m_mode == OR ? " + " : " , ");
                wc += act->toolTip();
            };
        }
    }
    return wc;
}

void SKGShow::setDefaultState(const QString& iState)
{
    m_defaultState = iState;
    setState(m_defaultState);
}

void SKGShow::setState(const QString& iState)
{
    if (m_menu) {
        QStringList itemsChecked = SKGServices::splitCSVLine(iState.isEmpty() ? m_defaultState : iState);

        int nb = m_actions.count();
        for (int i = 0; i < nb; ++i) {
            m_actions.at(i)->setChecked(itemsChecked.contains(m_actions.at(i)->data().toString()));
        }

        // Change tooltip
        setToolTip(getTitle());

        // Emit event
        emit stateChanged();
    }
}

void SKGShow::clear()
{
    m_check_to_check.clear();
    m_uncheck_to_check.clear();
    m_check_to_uncheck.clear();
    m_uncheck_to_uncheck.clear();
    m_actions.clear();
    m_icons.clear();
    m_whereclause.clear();
    m_defaultState.clear();
    m_menu->clear();
}

int SKGShow::count()
{
    return m_check_to_check.count();
}

int SKGShow::addGroupedItem(const QString& iIdentifier, const QString& iText, const QString& iIcon, const QString& iWhereClose, const QString& iGroup)
{
    if (m_menu) {
        QActionGroup* groupAction = m_groups[iGroup];
        if (!groupAction) {
            groupAction = new QActionGroup(this);
            m_groups[iGroup] = groupAction;
        }

        QString name = iText;
        name = name.replace('&', "&&");
        QAction* act = m_menu->addAction(name);
        if (act) {
            act->setToolTip(name);
            act->setIcon(KIcon(iIcon));
            act->setData(iIdentifier);
            act->setCheckable(true);

            m_check_to_check[act] = "";
            m_check_to_uncheck[act] = "";
            m_uncheck_to_check[act] = "";
            m_uncheck_to_uncheck[act] = "";
            m_actions.push_back(act);
            m_icons.push_back(iIcon);

            m_whereclause[act] = iWhereClose;

            connect(act, SIGNAL(toggled(bool)), this, SLOT(trigger()));

            groupAction->addAction(act);
        }

        show();

        return (m_actions.count() - 1);
    }
    return -1;
}

int SKGShow::addItem(const QString& iIdentifier, const QString& iText, const QString& iIcon,
                     const QString& iWhereClose,
                     const QString& iListIdToCheckWhenChecked ,
                     const QString& iListIdToUncheckWhenChecked ,
                     const QString& iListIdToCheckWhenUnchecked ,
                     const QString& iListIdToUncheckWhenUnchecked
                    )
{
    if (m_menu) {
        QString name = iText;
        name = name.replace('&', "&&");
        QAction* act = m_menu->addAction(name);
        if (act) {
            act->setToolTip(name);
            act->setIcon(KIcon(iIcon));
            act->setData(iIdentifier);
            act->setCheckable(true);

            m_check_to_check[act] = iListIdToCheckWhenChecked;
            m_check_to_uncheck[act] = iListIdToUncheckWhenChecked;
            m_uncheck_to_check[act] = iListIdToCheckWhenUnchecked;
            m_uncheck_to_uncheck[act] = iListIdToUncheckWhenUnchecked;
            m_actions.push_back(act);
            m_icons.push_back(iIcon);

            m_whereclause[act] = iWhereClose;

            connect(act, SIGNAL(toggled(bool)), this, SLOT(trigger()));
        }

        show();

        return (m_actions.count() - 1);
    }
    return -1;
}

void SKGShow::setListIdToCheckWhenChecked(int iIndex, const QString& iIds)
{
    m_check_to_check[m_actions.at(iIndex)] = iIds;
}

void SKGShow::setListIdToCheckWhenUnchecked(int iIndex, const QString& iIds)
{
    m_uncheck_to_check[m_actions.at(iIndex)] = iIds;
}

void SKGShow::setListIdToUncheckWhenChecked(int iIndex, const QString& iIds)
{
    m_check_to_uncheck[m_actions.at(iIndex)] = iIds;
}

void SKGShow::setListIdToUncheckWhenUnchecked(int iIndex, const QString& iIds)
{
    m_uncheck_to_uncheck[m_actions.at(iIndex)] = iIds;
}

void SKGShow::addSeparator()
{
    if (m_menu) m_menu->addSeparator();
}

void SKGShow::trigger()
{
    QAction* act = qobject_cast<QAction*>(sender());
    if (act && !m_inTrigger) {
        m_inTrigger = true;

        // Apply rules
        QStringList over;
        if (act->isChecked()) {
            {
                // Check items
                QStringList items = SKGServices::splitCSVLine(m_check_to_check[act]);
                int nb = items.count();
                for (int i = 0; i < nb; ++i) {
                    QAction* act2 = getAction(items.at(i));
                    if (act2 && act2 != act) act2->setChecked(true);
                }
            }

            {
                // Uncheck items
                QStringList items = SKGServices::splitCSVLine(m_check_to_uncheck[act]);
                int nb = items.count();
                for (int i = 0; i < nb; ++i) {
                    QAction* act2 = getAction(items.at(i));
                    if (act2 && act2 != act) act2->setChecked(false);
                }
            }
        } else {
            {
                // Check items
                QStringList items = SKGServices::splitCSVLine(m_uncheck_to_check[act]);
                int nb = items.count();
                for (int i = 0; i < nb; ++i) {
                    QAction* act2 = getAction(items.at(i));
                    if (act2 && act2 != act) act2->setChecked(true);
                }
            }

            {
                // Uncheck items
                QStringList items = SKGServices::splitCSVLine(m_uncheck_to_uncheck[act]);
                int nb = items.count();
                for (int i = 0; i < nb; ++i) {
                    QAction* act2 = getAction(items.at(i));
                    if (act2 && act2 != act) act2->setChecked(false);
                }
            }
        }

        // Change tooltip
        setToolTip(getTitle());

        // Change icon
        QStringList icons;
        QString mainIcon;
        if (m_menu) {
            int nb = m_actions.count();
            for (int i = 0; i < nb; ++i) {
                QAction* act2 = m_actions.at(i);
                if (act2 && act2->isChecked()) {
                    if (!m_icons.at(i).isEmpty()) {
                        if (mainIcon.isEmpty()) mainIcon = m_icons.at(i);
                        else {
                            icons.push_back(m_icons.at(i));
                        }
                    } else {
                        if (mainIcon.isEmpty()) mainIcon = "show-menu";
                    }
                }
            }
        }
        if (mainIcon.isEmpty()) mainIcon = "show-menu";
        setIcon(KIcon(mainIcon, NULL, icons));

        // Emit event
        m_timer.start(300);

        // Change title
        refreshTitle();

        m_inTrigger = false;
    }
}

bool SKGShow::getDisplayTitle()
{
    return m_displayTitle;
}

void SKGShow::setDisplayTitle(bool iDisplay)
{
    m_displayTitle = iDisplay;
    refreshTitle();
}

void SKGShow::refreshTitle()
{
    if (m_displayTitle) setText(i18n("Show: %1", getTitle()));
    else {
        setText(i18n("Show"));
    }
}

QAction* SKGShow::getAction(const QString& iIdentifier) const
{
    QAction* output = NULL;
    if (m_menu) {
        QList<QAction*> actionsList = m_menu->actions();
        int nb = actionsList.count();
        for (int i = 0; !output && i < nb; ++i) {
            QAction* act = actionsList.at(i);
            if (act && act->data().toString() == iIdentifier) output = act;
        }
    }
    return output;
}

#include "skgshow.moc"
