/***************************************************************************
 *   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 plugin to manage properties on objects.
 *
 * @author Stephane MANKOWSKI
 */
#include "skgpropertiesplugindockwidget.h"

#include <KFileDialog>
#include <KMessageBox>

#include <QFile>
#include <QDesktopServices>

#include "skgmainpanel.h"
#include "skgtraces.h"
#include "skgdocument.h"
#include "skgservices.h"
#include "skgnamedobject.h"
#include "skgobjectmodelbase.h"
#include "skgsortfilterproxymodel.h"
#include "skgtransactionmng.h"
#include "skgpropertyobject.h"


SKGPropertiesPluginDockWidget::SKGPropertiesPluginDockWidget(SKGDocument* iDocument)
    : SKGWidget(iDocument)
{
    SKGTRACEINFUNC(1);
    if (!iDocument) {
        return;
    }

    ui.setupUi(this);

    ui.kPicture->hide();

    ui.kAdd->setMaximumWidth(ui.kAdd->height());
    ui.kRemove->setMaximumWidth(ui.kRemove->height());
    ui.kSelectFile->setMaximumWidth(ui.kSelectFile->height());

    ui.kAdd->setIcon(KIcon("list-add"));
    ui.kRename->setIcon(KIcon("dialog-ok-apply"));
    ui.kRemove->setIcon(KIcon("list-remove"));
    ui.kSelectFile->setIcon(KIcon("document-open"));
    ui.kOpenBtn->setIcon(KIcon("skg_open"));

    ui.kForCmb->addItem(i18n("Selection"));
    ui.kForCmb->addItem(i18n("All"));

    // Add model
    SKGObjectModelBase* modelview = new SKGObjectModelBase(getDocument(), "parameters", "1=1 ORDER BY t_uuid_parent, t_name", this, "", false);
    SKGSortFilterProxyModel* modelproxy = new SKGSortFilterProxyModel(this);
    modelproxy->setSourceModel(modelview);
    ui.kView->setModel(modelproxy);

    ui.kFilterEdit->setProxy(modelproxy);

    ui.kView->setDefaultSaveParameters(getDocument(), "SKG_DEFAULT_PROPERTIES");
    connect(modelview, SIGNAL(beforeReset()), ui.kView, SLOT(saveSelection()));
    connect(modelview, SIGNAL(afterReset()), ui.kView, SLOT(resetSelection()));
    connect(ui.kView, SIGNAL(selectionChangedDelayed()), this, SLOT(onSelectionChanged()));
    connect(ui.kForCmb, SIGNAL(currentIndexChanged(int)), this, SLOT(refresh()));

    ui.kView->setTextResizable(false);
}

SKGPropertiesPluginDockWidget::~SKGPropertiesPluginDockWidget()
{
    SKGTRACEINFUNC(1);
}

void SKGPropertiesPluginDockWidget::refresh()
{
    SKGTRACEINFUNC(1);

    // Change filter
    SKGObjectModelBase* model = static_cast<SKGObjectModelBase*>(ui.kView->model());
    QSortFilterProxyModel* proxyModel = qobject_cast<QSortFilterProxyModel*>(model);
    if (proxyModel) {
        model = static_cast<SKGObjectModelBase*>(proxyModel->sourceModel());
    }

    if (model) {
        QString filter;
        if (ui.kForCmb->currentIndex() == 1) {
            filter = "t_uuid_parent!='document' AND t_name NOT LIKE 'SKG_%'";
            ui.kAdd->setEnabled(false);
            ui.kSelectFile->setEnabled(false);
            ui.kRemove->setEnabled(false);
            ui.kAttribute->setEnabled(false);
            ui.kValue->setEnabled(false);
        } else if (ui.kForCmb->currentIndex() == 0) {
            filter = "t_uuid_parent IN (";
            SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
            int nb = selection.count();
            if (nb) {
                ui.kAdd->setEnabled(true);
                ui.kSelectFile->setEnabled(true);
                ui.kRemove->setEnabled(false);
                ui.kAttribute->setEnabled(true);
                ui.kValue->setEnabled(true);

                QString tableName;
                for (int i = 0; i < nb; ++i) {
                    if (i > 0) {
                        filter += ',';
                    } else {
                        tableName = selection.at(i).getRealTable();
                    }
                    filter += '\'' % selection.at(i).getUniqueID() % '\'';
                }

                // Fill combo box
                QString t = tableName;
                if (t.startsWith(QLatin1String("sub"))) {
                    t = t.right(t.length() - 3);
                }
                SKGMainPanel::fillWithDistinctValue(ui.kAttribute, getDocument(), "parameters", "t_name", "(t_uuid_parent like '%-" % t % "' OR t_uuid_parent like '%-sub" % t % "') AND t_name NOT LIKE 'SKG_%'");
                SKGMainPanel::fillWithDistinctValue(ui.kValue, getDocument(), "parameters", "t_value", "(t_uuid_parent like '%-" % t % "' OR t_uuid_parent like '%-sub" % t % "') AND t_name NOT LIKE 'SKG_%'");
            } else {
                filter += "'XXX'";  // Always false
                ui.kAdd->setEnabled(false);
                ui.kSelectFile->setEnabled(false);
                ui.kRemove->setEnabled(false);
                ui.kAttribute->setEnabled(false);
                ui.kValue->setEnabled(false);
            }
            filter += ") AND t_name NOT LIKE 'SKG_%'";
        }
        filter += " ORDER BY t_uuid_parent, t_name";
        ui.kView->saveSelection();

        model->setFilter(filter);
        model->refresh();

        ui.kView->resetSelection();
    }

    ui.kView->setState("");
    if (ui.kView->isAutoResized()) {
        ui.kView->resizeColumnsToContentsDelayed();
    }

    onSelectionChanged();
}

void SKGPropertiesPluginDockWidget::onSelectionChanged()
{
    SKGTRACEINFUNC(10);
    int nbSelected = getNbSelectedObjects();
    ui.kPicture->hide();
    ui.kOpenBtn->hide();
    ui.kRemove->setEnabled(nbSelected > 0);
    if (nbSelected > 0) {
        SKGObjectBase::SKGListSKGObjectBase objs = getSelectedObjects();
        SKGObjectBase obj = objs.at(0);
        ui.kAttribute->setText(obj.getAttribute("t_name"));
        ui.kValue->setText(obj.getAttribute("t_value"));

        if (nbSelected == 1) {
            QStringList uuid = obj.getAttribute("t_uuid_parent").split('-');
            if (uuid.count() == 2) {
                SKGObjectBase p(getDocument(), uuid.at(1), SKGServices::stringToInt(uuid.at(0)));
                QVariant blob = p.getPropertyBlob(obj.getAttribute("t_name"));

                // Is it a copied file ?
                if (!blob.isNull()) {
                    // Yes, this is a file
                    QByteArray blob_bytes = blob.toByteArray();

                    // Save temporary file
                    QString fileName = QDir::tempPath() % '/' % obj.getAttribute("t_value");

                    QFile file(fileName);
                    file.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
                    if (file.open(QIODevice::WriteOnly)) {
                        file.write(blob_bytes);
                        file.flush();
                        file.close();
                        file.setPermissions(QFile::ReadOwner);  // To be sure that no modifications are done

                        ui.kPicture->show();
                        ui.kOpenBtn->show();
                        ui.kPicture->showPreview(KUrl(fileName));
                    }
                } else if (QFile(obj.getAttribute("t_value")).exists()) {
                    // Is it a linked file ? Yes
                    ui.kPicture->show();
                    ui.kOpenBtn->show();
                    ui.kPicture->showPreview(KUrl(obj.getAttribute("t_value")));
                } else {
                    // Is it a linked file ? No, Is it a http url ?
                    QUrl url(obj.getAttribute("t_value"));
                    if (!url.scheme().isEmpty()) {
                        ui.kOpenBtn->show();
                    }
                }
            }
        }
    }

    if (ui.kView->isAutoResized()) {
        ui.kView->resizeColumnsToContentsDelayed();
    }
}

void SKGPropertiesPluginDockWidget::onOpenFile()
{
    SKGTRACEINFUNC(10);
    int nbSelected = getNbSelectedObjects();
    if (nbSelected > 0) {
        SKGObjectBase::SKGListSKGObjectBase objs = getSelectedObjects();
        if (nbSelected == 1) {
            SKGObjectBase obj = objs.at(0);

            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
            QStringList uuid = obj.getAttribute("t_uuid_parent").split('-');
            if (uuid.count() == 2) {
                SKGObjectBase p(getDocument(), uuid.at(1), SKGServices::stringToInt(uuid.at(0)));
                QVariant blob = p.getPropertyBlob(obj.getAttribute("t_name"));
                // Is it a copied file ?
                if (!blob.isNull()) {
                    // Yes, this is a file
                    // Display temporary file
                    QString fileName = QDir::tempPath() % '/' % obj.getAttribute("t_value");
                    if (!QDesktopServices::openUrl(KUrl(fileName))) {
                        QString fileNameToSave = SKGMainPanel::getSaveFileName("kfiledialog:///IMPEXP", "" , SKGMainPanel::getMainPanel());
                        if (!fileNameToSave.isEmpty()) {
                            QFile(fileName).copy(fileNameToSave);
                        }
                    }
                } else if (QFile().exists(obj.getAttribute("t_value"))) {
                    // Is it a linked file? Yes
                    QDesktopServices::openUrl(KUrl(obj.getAttribute("t_value")));
                } else {
                    // Is it a linked file?  No, Is it a http url ?
                    QUrl url(obj.getAttribute("t_value"));
                    if (!url.scheme().isEmpty()) {
                        QDesktopServices::openUrl(url);
                    }
                }
            }
            QApplication::restoreOverrideCursor();
        }
    }

    if (ui.kView->isAutoResized()) {
        ui.kView->resizeColumnsToContentsDelayed();
    }
}

void SKGPropertiesPluginDockWidget::onAddProperty()
{
    SKGTRACEINFUNC(10);
    SKGError err;
    QStringList listUUID;
    // Scope for the transaction
    {
        // Get parameters
        QString name = ui.kAttribute->text();
        QString value = ui.kValue->text();
        QVariant blob;
        QFile file(value);
        if (file.exists()) {
            int mode = KMessageBox::questionYesNoCancel(this, i18nc("Question", "Do you want copy or link the file?"),
                       QString(),
                       KGuiItem(i18nc("Question", "Copy") , "edit-copy"),
                       KGuiItem(i18nc("Question", "Link") , "edit-link"));

            if (mode == KMessageBox::Cancel) {
                return;
            }
            if (mode == KMessageBox::Yes) {
                // Value is a file name ==> blob
                if (Q_UNLIKELY(!file.open(QIODevice::ReadOnly))) {
                    err = SKGError(ERR_INVALIDARG, i18nc("Error message: could not open the requested file", "Open file '%1' failed", value));
                } else {
                    QByteArray blob_bytes = file.readAll();
                    if (!blob_bytes.count()) {
                        err = SKGError(ERR_INVALIDARG, i18nc("Error message: could not open the requested file", "Open file '%1' failed", value));
                    } else {
                        blob = blob_bytes;
                        value = QFileInfo(value).fileName();
                    }

                    // close file
                    file.close();
                }
            }
        }

        // Create properties
        IFOK(err) {
            SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
            int nb = selection.count();
            SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Create a user defined property", "Property creation"), err, nb);
            for (int i = 0; !err && i < nb; ++i) {
                SKGPropertyObject prop;
                err = selection[i].setProperty(name, value, blob, &prop);

                IFOK(err) {
                    listUUID.push_back(prop.getUniqueID());
                    err = getDocument()->stepForward(i + 1);
                }
            }
        }
    }

    // status bar
    IFOK(err) {
        err = SKGError(0, i18nc("The user defined property was successfully created", "Property created"));
        ui.kView->selectObjects(listUUID, true);
    }
    SKGMainPanel::displayErrorMessage(err);
}

void SKGPropertiesPluginDockWidget::onRenameProperty()
{
    SKGTRACEINFUNC(10);
    SKGError err;
    QStringList listUUID;
    // Scope for the transaction
    {
        // Rename properties
        IFOK(err) {
            SKGObjectBase::SKGListSKGObjectBase selection = ui.kView->getSelectedObjects();
            int nb = selection.count();
            SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Create a user defined property", "Rename property"), err, nb);
            for (int i = 0; !err && i < nb; ++i) {
                SKGObjectBase prop(selection.at(i));
                IFOKDO(err, getDocument()->executeSqliteOrder("UPDATE parameters SET t_name='" % SKGServices::stringToSqlString(ui.kAttribute->text()) % "' WHERE id=" % SKGServices::intToString(prop.getID())))
                IFOK(err) {
                    listUUID.push_back(prop.getUniqueID());
                    err = getDocument()->stepForward(i + 1);
                }
            }
        }
    }

    // status bar
    IFOK(err) {
        err = SKGError(0, i18nc("The user property was successfully renamed", "Property renamed"));
        ui.kView->selectObjects(listUUID, true);
    }
    SKGMainPanel::displayErrorMessage(err);
}

void SKGPropertiesPluginDockWidget::onSelectFile()
{
    QString fileName = KFileDialog::getOpenFileName(KUrl("kfiledialog:///IMPEXP"), "" , this);
    ui.kValue->setText(fileName);
}

void SKGPropertiesPluginDockWidget::onRemoveProperty()
{
    SKGError err;
    SKGTRACEINFUNCRC(10, err);
    {
        SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();
        int nb = selection.count();
        SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Verb, delete an item", "Delete"), err, nb);
        for (int i = 0; !err && i < nb; ++i) {
            err = selection[i].remove();
            IFOKDO(err, getDocument()->stepForward(i + 1))
        }
    }

    // status bar
    IFOKDO(err, SKGError(0, i18nc("The user defined property was successfully deleted", "Properties deleted.")))
    else {
        err.addError(ERR_FAIL, i18nc("Error message: Could not delete an item", "Delete failed"));
    }

    // Display error
    SKGMainPanel::displayErrorMessage(err);
}

void SKGPropertiesPluginDockWidget::cleanEditor()
{
    if (getNbSelectedObjects() == 0) {
        ui.kAttribute->setText("");
        ui.kValue->setText("");
    }
}

QWidget* SKGPropertiesPluginDockWidget::mainWidget()
{
    return ui.kView;
}

#include "skgpropertiesplugindockwidget.moc"


