/***************************************************************************
 *   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
 * This file is a plugin for bookmarks management.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgbookmarkplugindockwidget.h"

#include <KMenu>
#include <KIconDialog>

#include <QHeaderView>
#include <QResizeEvent>

#include "skgbookmark_settings.h"
#include "skgtraces.h"
#include "skgdocument.h"
#include "skgobjectmodelbase.h"
#include "skgmainpanel.h"
#include "skgsortfilterproxymodel.h"
#include "skgnodeobject.h"
#include "skginterfaceplugin.h"
#include "skgtransactionmng.h"

bool SKGBookmarkPluginDockWidget::m_middleClick = false;

SKGBookmarkPluginDockWidget::SKGBookmarkPluginDockWidget(SKGDocument* iDocument)
    : SKGWidget(iDocument), m_mainMenu(NULL), m_actDelete(NULL), m_actRename(NULL), m_actChangeIcon(NULL), m_actAddBookmark(NULL), m_actAddBookmarks(NULL),
      m_actAddBookmarkGroup(NULL), m_actSetAutostart(NULL), m_actUnsetAutostart(NULL)
{
    SKGTRACEINFUNC(1);
    if (!iDocument) {
        return;
    }

    ui.setupUi(this);

    QPalette newPalette = QApplication::palette();
    newPalette.setColor(QPalette::Base, Qt::transparent);
    ui.kBookmarksList->setPalette(newPalette);
    ui.kBookmarksList->setRootIsDecorated(false);
    ui.kBookmarksList->setAnimated(false);  // Not compatible with double click
    ui.kBookmarksList->setEditTriggers(QAbstractItemView::NoEditTriggers);

    ui.kTools->setIcon(KIcon("configure"));
    QTimer::singleShot(200, this, SLOT(initMenu()));

    ui.kBookmarksList->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui.kBookmarksList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));

    // Add model
    m_modelview = new SKGObjectModelBase(getDocument(), "v_node", "1=1 ORDER BY f_sortorder, t_name", this, "rd_node_id");
    SKGSortFilterProxyModel* modelproxy = new SKGSortFilterProxyModel(this);
    modelproxy->setSourceModel(m_modelview);
    ui.kBookmarksList->setModel(modelproxy);

    ui.kFilterEdit->setProxy(modelproxy);

    connect(ui.kBookmarksList, SIGNAL(selectionChangedDelayed()), this, SLOT(refresh()));
    connect(ui.kBookmarksList, SIGNAL(pressed(QModelIndex)), this, SLOT(onBeforeOpenBookmark()));
    connect(ui.kBookmarksList, SIGNAL(clicked(QModelIndex)), this, SLOT(onOpenBookmark(QModelIndex)));
    connect(ui.kBookmarksList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onOpenBookmarkFolder(QModelIndex)));
    connect(SKGMainPanel::getMainPanel(), SIGNAL(currentPageChanged()), this, SLOT(onPageChanged()), Qt::QueuedConnection);

    connect(m_modelview, SIGNAL(beforeReset()), ui.kBookmarksList, SLOT(saveSelection()));
    connect(m_modelview, SIGNAL(afterReset()), ui.kBookmarksList, SLOT(resetSelection()));

    ui.kBookmarksList->setTextResizable(false);

    // Refresh action states
    refresh();
}

SKGBookmarkPluginDockWidget::~SKGBookmarkPluginDockWidget()
{
    SKGTRACEINFUNC(1);
    m_mainMenu = NULL;
    m_actDelete = NULL;
    m_actRename = NULL;
    m_actChangeIcon = NULL;
    m_actAddBookmark = NULL;
    m_actAddBookmarks = NULL;
    m_actAddBookmarkGroup = NULL;
    m_actSetAutostart = NULL;
    m_actUnsetAutostart = NULL;
    m_modelview = NULL;
}

QWidget* SKGBookmarkPluginDockWidget::mainWidget()
{
    return ui.kBookmarksList;
}

void SKGBookmarkPluginDockWidget::initMenu()
{
    if (!m_mainMenu) {
        // Build contextual menu
        m_mainMenu = new KMenu(ui.kBookmarksList);
        QAction* actExpandAll = m_mainMenu->addAction(KIcon("format-indent-more"), i18nc("Noun, user action", "Expand all"));
        connect(actExpandAll, SIGNAL(triggered(bool)), ui.kBookmarksList, SLOT(expandAll()));

        QAction* actCollapseAll = m_mainMenu->addAction(KIcon("format-indent-less"), i18nc("Noun, user action", "Collapse all"));
        connect(actCollapseAll, SIGNAL(triggered(bool)), ui.kBookmarksList, SLOT(collapseAll()));
        ui.kBookmarksList->insertAction(0, actCollapseAll);

        m_mainMenu->addSeparator();

        m_actAddBookmark = m_mainMenu->addAction(KIcon("list-add"), i18nc("Verb", "Bookmark current page"));
        connect(m_actAddBookmark, SIGNAL(triggered(bool)), this, SLOT(onAddBookmark()));

        m_actAddBookmarks = m_mainMenu->addAction(KIcon("list-add"), i18nc("Verb", "Bookmark all pages"));
        connect(m_actAddBookmarks, SIGNAL(triggered(bool)), this, SLOT(onAddBookmarks()));

        m_actAddBookmarkGroup = m_mainMenu->addAction(KIcon("folder-new"), i18nc("Verb", "Add bookmark group"));
        connect(m_actAddBookmarkGroup, SIGNAL(triggered(bool)), this, SLOT(onAddBookmarkGroup()));

        m_mainMenu->addSeparator();

        m_actDelete = m_mainMenu->addAction(KIcon("edit-delete"), i18nc("Verb, delete an item", "Delete"));
        connect(m_actDelete, SIGNAL(triggered(bool)), this, SLOT(onRemoveBookmark()));

        m_mainMenu->addSeparator();

        m_actSetAutostart = m_mainMenu->addAction(KIcon("user-online"), i18nc("Verb, automatically load when the application is started", "Autostart"));
        connect(m_actSetAutostart, SIGNAL(triggered(bool)), this, SLOT(onSetAutostart()));

        m_actUnsetAutostart = m_mainMenu->addAction(KIcon("user-offline"), i18nc("Verb", "Remove Autostart"));
        connect(m_actUnsetAutostart, SIGNAL(triggered(bool)), this, SLOT(onUnsetAutostart()));

        m_actRename = m_mainMenu->addAction(KIcon("edit-rename"), i18nc("Verb, change the name of an item", "Rename"));
        connect(m_actRename, SIGNAL(triggered(bool)), this, SLOT(onRenameBookmark()));

        m_actChangeIcon = m_mainMenu->addAction(KIcon("view-media-visualization"), i18nc("Verb, change the icon of an item", "Change icon..."));
        connect(m_actChangeIcon, SIGNAL(triggered(bool)), this, SLOT(onChangeIconBookmark()));

        m_mainMenu->addSeparator();
        m_mainMenu->addAction(SKGMainPanel::getMainPanel()->getGlobalAction("tab_overwritebookmark"));

        ui.kTools->setMenu(m_mainMenu);
    }
}

void SKGBookmarkPluginDockWidget::showMenu(const QPoint& iPos)
{
    initMenu();
    m_mainMenu->popup(ui.kBookmarksList->mapToGlobal(iPos));
}

void SKGBookmarkPluginDockWidget::onSetAutostart()
{
    SKGTRACEINFUNC(10);
    setAutostart("Y");
}

void SKGBookmarkPluginDockWidget::onUnsetAutostart()
{
    SKGTRACEINFUNC(10);
    setAutostart("N");
}

void SKGBookmarkPluginDockWidget::setAutostart(const QString& value)
{
    SKGTRACEINFUNC(10);
    SKGObjectBase::SKGListSKGObjectBase selectedBookmarks = getSelectedObjects();

    SKGError err;

    // foreach selected bookmark, set the t_autostart attribute to 'y' or 'n'
    {
        int nb = selectedBookmarks.count();
        SKGBEGINPROGRESSTRANSACTION(*getDocument(), value == "Y" ? i18nc("Noun, name of the user action", "Autostart bookmarks") : i18nc("Noun, name of the user action", "Do not Autostart bookmarks"), err, nb);
        for (int i = 0 ; !err && i < nb  ; ++i) {
            SKGNodeObject bookmark(selectedBookmarks.at(i));
            err = bookmark.setAttribute("t_autostart", value);
            IFOKDO(err, bookmark.save())
            IFOKDO(err, getDocument()->stepForward(i + 1))
        }
    }

    // status bar
    IFOKDO(err, SKGError(0, value == "Y" ? i18nc("Successful message after an user action", "Autostart bookmarks") : i18nc("Successful message after an user action", "Do not Autostart bookmarks")))
    SKGMainPanel::displayErrorMessage(err);
}


void SKGBookmarkPluginDockWidget::openBookmark(const SKGNodeObject& iNode, bool iFirstInNewPage, bool iPin)
{
    SKGTRACEINFUNC(1);
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

    QList<SKGNodeObject> nodes;
    nodes.push_back(iNode);

    int setForcusOn = 0;
    int nbTab = SKGMainPanel::getMainPanel()->countPages();
    if (nbTab) {
        setForcusOn = nbTab - 1;

        SKGTabPage* cPage = SKGMainPanel::getMainPanel()->currentPage();
        if (m_middleClick || (cPage && cPage->isPin())) {
            setForcusOn = nbTab;
        } else {
            setForcusOn = SKGMainPanel::getMainPanel()->currentPageIndex();
        }
    }

    int tabNumberForNextOpen = (m_middleClick || iFirstInNewPage ? -1 : SKGMainPanel::getMainPanel()->currentPageIndex());
    for (int i = 0; i < nodes.count(); ++i) {  // WARNING: This list is modified dynamically
        SKGNodeObject selectedNode = nodes.at(i);
        QStringList data = SKGServices::splitCSVLine(selectedNode.getData());
        if (data.count() > 2) {
            // This bookmark has information ==> we open it
            SKGTabPage* page = SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName(data[0]), tabNumberForNextOpen, data[2], selectedNode.getName(), SKGServices::intToString(selectedNode.getID()), i == nodes.count() - 1);
            if (page) {
                if (skgbookmark_settings::pinhomebookmarks()) {
                    page->setPin(iPin);
                }
                SKGTabWidget* tab = SKGMainPanel::getMainPanel()->getTabWidget();
                if (tab) {
                    tab->setTabIcon(SKGMainPanel::getMainPanel()->currentPageIndex(), selectedNode.getIcon());
                }
                selectedNode.opened = true;
                tabNumberForNextOpen = -1;
            }
        } else {
            // This bookmark is a folder ==> we open children by recursion
            SKGObjectBase::SKGListSKGObjectBase children;
            selectedNode.getNodes(children);
            foreach(const SKGObjectBase & item, children) {
                nodes.push_back(SKGNodeObject(item));
            }
        }
    }
    QApplication::restoreOverrideCursor();

    // Set focus on first page
    SKGMainPanel::getMainPanel()->setCurrentPage(setForcusOn);
}

void SKGBookmarkPluginDockWidget::onBeforeOpenBookmark()
{
    m_middleClick = QApplication::keyboardModifiers() & Qt::ControlModifier || QApplication::mouseButtons() & Qt::MidButton;
}

void SKGBookmarkPluginDockWidget::onOpenBookmark(const QModelIndex& index)
{
    SKGTRACEINFUNC(1);
    QSortFilterProxyModel* proxyModel = qobject_cast<QSortFilterProxyModel*>(ui.kBookmarksList->model());
    SKGObjectModelBase* model = static_cast<SKGObjectModelBase*>(proxyModel->sourceModel());
    if (model) {
        SKGNodeObject node(model->getObject(proxyModel->mapToSource(index)));
        if (!node.isFolder()) {
            openBookmark(node);
        }
    }
}

void SKGBookmarkPluginDockWidget::onOpenBookmarkFolder(const QModelIndex& index)
{
    SKGTRACEINFUNC(1);
    QSortFilterProxyModel* proxyModel = qobject_cast<QSortFilterProxyModel*>(ui.kBookmarksList->model());
    SKGObjectModelBase* model = static_cast<SKGObjectModelBase*>(proxyModel->sourceModel());
    if (model) {
        SKGNodeObject node(model->getObject(proxyModel->mapToSource(index)));
        if (node.isFolder()) {
            openBookmark(node);
        }
    }
}

void SKGBookmarkPluginDockWidget::onAddBookmarkGroup()
{
    SKGTRACEINFUNC(1);
    SKGError err;
    SKGNodeObject node;
    {
        // Get current selection name
        QString name;
        SKGObjectBase::SKGListSKGObjectBase bookmarks = getSelectedObjects();
        if (bookmarks.count()) {
            SKGNodeObject parentNode(bookmarks.at(0));
            if (!parentNode.isFolder()) {
                // This is not a folder, we have to take the parent
                SKGNodeObject parentNodeTmp;
                parentNode.getParentNode(parentNodeTmp);
                parentNode = parentNodeTmp;
            }
            name = parentNode.getFullName();
        }

        // Add current name
        if (!name.isEmpty()) {
            name += OBJECTSEPARATOR;
        }
        name += i18nc("Default name for bookmark", "New bookmark");

        // Create bookmark folder
        SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Bookmark folder creation '%1'", name), err);
        err = SKGNodeObject::createPathNode(getDocument(), name, node, true);
    }

    // status bar
    IFOK(err) {
        ui.kBookmarksList->selectObject(node.getUniqueID());
        err = SKGError(0, i18nc("Successful message after an user action", "Bookmark group created"));
    }
    SKGMainPanel::displayErrorMessage(err);
}

void SKGBookmarkPluginDockWidget::onAddBookmarks()
{
    SKGTRACEINFUNC(1);
    SKGError err;
    SKGNodeObject rootNode;
    {
        // Get current selection name
        QString name;
        SKGObjectBase::SKGListSKGObjectBase bookmarks = getSelectedObjects();
        if (bookmarks.count()) {
            SKGNodeObject parentNode(bookmarks.at(0));
            if (!parentNode.isFolder()) {
                // This is not a folder, we have to take the parent
                SKGNodeObject parentNodeTmp;
                parentNode.getParentNode(parentNodeTmp);
                parentNode = parentNodeTmp;
            }
            name = parentNode.getFullName();
        }

        // Add current name
        if (!name.isEmpty()) {
            name += OBJECTSEPARATOR;
        }
        name += i18nc("Default name for bookmark", "New bookmark");

        // Create bookmark folder
        SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Bookmarks creation"), err);
        err = SKGNodeObject::createPathNode(getDocument(), name, rootNode, true);
        int nb = SKGMainPanel::getMainPanel()->countPages();
        for (int i = 0; !err && i < nb; ++i) {
            SKGNodeObject node;
            err = createNodeFromPage(SKGMainPanel::getMainPanel()->page(i), rootNode, node);
        }
    }

    // status bar
    IFOK(err) {
        ui.kBookmarksList->selectObject(rootNode.getUniqueID());
        err = SKGError(0, i18nc("Successful message after an user action", "Bookmarks created"));
    }
    SKGMainPanel::displayErrorMessage(err);
}

void SKGBookmarkPluginDockWidget::onAddBookmark()
{
    SKGTRACEINFUNC(1);
    SKGError err;

    // Get current page
    SKGNodeObject node;
    {
        // Get current selection
        SKGNodeObject parentNode(getDocument(), 0);
        SKGObjectBase::SKGListSKGObjectBase bookmarks = getSelectedObjects();
        if (bookmarks.count()) {
            parentNode = bookmarks.at(0);
        }

        // Create bookmark
        err = createNodeFromPage(SKGMainPanel::getMainPanel()->currentPage(), parentNode, node);
    }
    // status bar
    IFOK(err) {
        ui.kBookmarksList->selectObject(node.getUniqueID());
        err = SKGError(0, i18nc("Successful message after an user action", "Bookmark created"));
    }
    SKGMainPanel::displayErrorMessage(err);
}

SKGError SKGBookmarkPluginDockWidget::createNodeFromPage(SKGTabPage* iPage, const SKGNodeObject& iParentNode, SKGNodeObject& oCreatedNode)
{
    SKGTRACEINFUNC(1);
    SKGError err;

    // Get current page
    oCreatedNode = SKGNodeObject();
    if (iPage) {
        // Get current selection name
        QString name;
        SKGNodeObject parentNode = iParentNode;
        if (!parentNode.isFolder()) {
            // This is not a folder, we have to take the parent
            SKGNodeObject parentNodeTmp;
            parentNode.getParentNode(parentNodeTmp);
            parentNode = parentNodeTmp;
        }
        name = parentNode.getFullName();

        // Add current name
        if (!name.isEmpty()) {
            name += OBJECTSEPARATOR;
        }

        QString defaultName = iPage->objectName();
        QString defaultIcon;
        SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByName(defaultName);
        if (plugin) {
            defaultName = plugin->title();
            defaultIcon = plugin->icon();
        }
        name += defaultName;

        // Create bookmark
        SKGBEGINTRANSACTION(*iParentNode.getDocument(), i18nc("Noun, name of the user action", "Bookmark creation '%1'", name), err);
        err = SKGNodeObject::createPathNode(iParentNode.getDocument(), name, oCreatedNode, true);
        IFOK(err) {
            QString value = SKGServices::stringToCsv(iPage->objectName()) % ';' %
                            SKGServices::stringToCsv(defaultName) % ';' %
                            SKGServices::stringToCsv(iPage->getState());

            err = oCreatedNode.setData(value);
            IFOKDO(err, oCreatedNode.setIcon(defaultIcon))
            IFOKDO(err, oCreatedNode.save())
        }
    }
    return err;
}

void SKGBookmarkPluginDockWidget::onRenameBookmark()
{
    SKGTRACEINFUNC(1);

    SKGObjectBase::SKGListSKGObjectBase selection;
    QItemSelectionModel* selModel = ui.kBookmarksList->selectionModel();
    QSortFilterProxyModel* proxyModel = qobject_cast< QSortFilterProxyModel* >(ui.kBookmarksList->model());
    if (proxyModel && selModel) {
        SKGObjectModelBase* model = static_cast<SKGObjectModelBase*>(proxyModel->sourceModel());
        if (model) {
            QModelIndexList indexes = selModel->selectedRows();
            if (indexes.count() == 1) {
                ui.kBookmarksList->edit(indexes.at(0));
            }
        }
    }
}

void SKGBookmarkPluginDockWidget::onChangeIconBookmark()
{
    SKGTRACEINFUNC(1);

    SKGObjectBase::SKGListSKGObjectBase bookmarks = getSelectedObjects();
    if (bookmarks.count() == 1) {
        SKGNodeObject node(bookmarks.at(0));
        KIconDialog diag(this);
        QString icon = diag.openDialog();
        if (!icon.isEmpty()) {
            SKGError err;
            {
                SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Bookmark icon change"), err);
                err = node.setIcon(icon);
                IFOKDO(err, node.save())
            }
            // status bar
            IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Bookmark icon changed")))
            SKGMainPanel::displayErrorMessage(err);
        }
    }
}


void SKGBookmarkPluginDockWidget::onRemoveBookmark()
{
    SKGTRACEINFUNC(1);
    SKGError err;
    {
        SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Bookmark delete"), err);
        // Get current selection
        SKGObjectBase::SKGListSKGObjectBase bookmarks = getSelectedObjects();
        int nb = bookmarks.count();
        for (int i = 0; i < nb && !err; ++i) {
            SKGNodeObject node(bookmarks.at(i));
            err = node.remove();
        }
    }

    // status bar
    IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Bookmark deleted")))
    SKGMainPanel::displayErrorMessage(err);
}

void SKGBookmarkPluginDockWidget::onBookmarkEditorChanged()
{
    SKGTRACEINFUNC(10);

    // Enable bookmark buttons
    int nbSelectedObjects = getNbSelectedObjects();
    bool testAdd = getDocument()->getDatabase() != NULL && nbSelectedObjects <= 1;
    if (m_actAddBookmarkGroup) {
        m_actAddBookmarkGroup->setEnabled(testAdd);
    }
    if (m_actAddBookmark) {
        m_actAddBookmark->setEnabled(testAdd && SKGMainPanel::getMainPanel()->currentPageIndex() >= 0);
    }
    if (m_actAddBookmarks) {
        m_actAddBookmarks->setEnabled(testAdd && SKGMainPanel::getMainPanel()->currentPageIndex() >= 0);
    }
    if (m_actDelete) {
        m_actDelete->setEnabled(nbSelectedObjects > 0);
    }
    if (m_actRename) {
        m_actRename->setEnabled(nbSelectedObjects == 1);
    }
    if (m_actChangeIcon) {
        m_actChangeIcon->setEnabled(nbSelectedObjects == 1);
    }
}

void SKGBookmarkPluginDockWidget::refresh()
{
    SKGTRACEINFUNC(10);
    // Bookmarks
    SKGObjectBase::SKGListSKGObjectBase bookmarks = getSelectedObjects();
    int nbSelectedObjects = bookmarks.count();
    if (nbSelectedObjects == 1) {
        SKGNodeObject node(bookmarks.at(0));
        if (m_actSetAutostart) {
            m_actSetAutostart->setEnabled(node.getAttribute("t_autostart") != "Y");
        }
        if (m_actUnsetAutostart) {
            m_actUnsetAutostart->setEnabled(node.getAttribute("t_autostart") == "Y");
        }
    } else {
        if (m_actSetAutostart) {
            m_actSetAutostart->setEnabled(nbSelectedObjects > 1);
        }
        if (m_actUnsetAutostart) {
            m_actUnsetAutostart->setEnabled(nbSelectedObjects > 1);
        }
    }

    onBookmarkEditorChanged();
}

void SKGBookmarkPluginDockWidget::onPageChanged()
{
    // Set current selection of dock
    QString id;
    SKGTabPage* cPage = SKGMainPanel::getMainPanel()->currentPage();
    if (cPage) {
        id = cPage->getBookmarkID();
    }
    ui.kBookmarksList->selectObject(id % "-node");
}

void SKGBookmarkPluginDockWidget::resizeEvent(QResizeEvent* iEvent)
{
    if (iEvent) {
        QSize newSize = iEvent->size();

        // Compute icon size
        int s = qMax(qMin(newSize.width() / 5, 64), 16);
        ui.kBookmarksList->setIconSize(QSize(s, s));
    }

    QWidget::resizeEvent(iEvent);
}

#include "skgbookmarkplugindockwidget.moc"
