/***************************************************************************
 *   Copyright (C) 2020 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 <https://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
* This akonadi resource.
*
* @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skroogeakonadiresource.h"

#include <qdbusconnection.h>

#include <kdirwatch.h>
#include <klocalizedstring.h>

#include <akonadicore/entitydisplayattribute.h>
#include <kcalcore/todo.h>
#include <kpassworddialog.h>
#include <qfiledialog.h>

#include "settings.h"
#include "settingsadaptor.h"
#include "skgcategoryobject.h"
#include "skgdocumentbank.h"
#include "skgoperationobject.h"
#include "skgrecurrentoperationobject.h"

skroogeakonadiResource::skroogeakonadiResource(const QString& id) : ResourceBase(id)
{
    setObjectName(QStringLiteral("SkroogeResource"));
    setNeedsNetwork(false);

    new SettingsAdaptor(Settings::self());
    QDBusConnection::sessionBus().registerObject(QStringLiteral("/Settings"),
            Settings::self(), QDBusConnection::ExportAdaptors);

    if (!KDirWatch::self()->contains(Settings::self()->path())) {
        KDirWatch::self()->addFile(Settings::self()->path());
    }
    QObject::connect(KDirWatch::self(), &KDirWatch::dirty, this, &skroogeakonadiResource::refresh);

    synchronize();
}

skroogeakonadiResource::~skroogeakonadiResource() = default;

void skroogeakonadiResource::retrieveCollections()
{
    Akonadi::Collection c;
    c.setRemoteId(Settings::self()->path());
    c.setName(i18nc("Name of a collection akonadi", "Skrooge scheduled operations"));
    c.setRights(Akonadi::Collection::ReadOnly);
    c.setParentCollection(Akonadi::Collection::root());
    c.setContentMimeTypes(QStringList() <<  QStringLiteral("application/x-vnd.akonadi.calendar.todo"));

    Akonadi::EntityDisplayAttribute* const attribute = new Akonadi::EntityDisplayAttribute();
    attribute->setIconName("skrooge");
    c.addAttribute(attribute);

    collectionsRetrieved(Akonadi::Collection::List() << c);

    if (!KDirWatch::self()->contains(Settings::self()->path())) {
        KDirWatch::self()->addFile(Settings::self()->path());
    }
}

void skroogeakonadiResource::retrieveItems(const Akonadi::Collection& collection)
{
    Akonadi::Item::List items;

    // Open the document
    SKGDocumentBank doc;
    SKGError err = doc.load(collection.remoteId(), Settings::self()->password(), false, true);
    IFOK(err) {
        SKGObjectBase::SKGListSKGObjectBase objs;
        err = doc.getObjects(QStringLiteral("v_recurrentoperation_display"), QStringLiteral("i_nb_times!=0 ORDER BY d_date"), objs);
        IFOK(err) {
            int nb = objs.count();
            if (nb) {
                for (int i = 0; i < nb; ++i) {
                    Akonadi::Item item(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
                    item.setRemoteId(collection.remoteId() % ";" % SKGServices::intToString(objs.at(i).getID()));

                    items << item;
                }
            }
        }
    }
    doc.close();

    itemsRetrieved(items);
}

bool skroogeakonadiResource::retrieveItem(const Akonadi::Item& item, const QSet<QByteArray>& parts)
{
    Q_UNUSED(parts)
    QStringList params = SKGServices::splitCSVLine(item.remoteId(), ';');

    bool output = false;
    SKGDocumentBank doc;
    SKGError err = doc.load(params.at(0), Settings::self()->password(), false, true);
    IFOK(err) {
        SKGRecurrentOperationObject obj(&doc, SKGServices::stringToInt(params.at(1)));
        SKGOperationObject op;
        obj.getParentOperation(op);

        KCalCore::auto akonadiItem = new KCalCore::Todo();
        KCalCore::Todo::Ptr akonadiItemPtr(akonadiItem);
        akonadiItem->setDtDue(KDateTime(obj.getDate()));
        akonadiItem->setDescription(op.getDisplayName().right(op.getDisplayName().count() - 11));
        if (!obj.hasTimeLimit() || obj.getTimeLimit() > 1) {
            akonadiItem->setDtRecurrence(KDateTime(obj.getNextDate()));
        }

        SKGOperationObject ope;
        obj.getParentOperation(ope);
        akonadiItem->setCategories(QStringList() << ope.getAttribute(QStringLiteral("t_CATEGORY")));

        Akonadi::Item newItem(item);
        newItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
        newItem.setPayload<KCalCore::Incidence::Ptr>(akonadiItemPtr);

        itemRetrieved(newItem);
        output = true;
    }
    doc.close();

    return output;
}

void skroogeakonadiResource::configure(WId windowId)
{
    Q_UNUSED(windowId)

    // Get the old path
    const QString oldPath = Settings::self()->path();
    QUrl url;
    if (!oldPath.isEmpty()) {
        url = QUrl::fromLocalFile(oldPath);
    } else {
        url = QUrl::fromLocalFile(QDir::homePath());
    }

    const QString newPath = QFileDialog::getOpenFileName("Skrooge document", 0, url, "*.skg|" % i18nc("A file format", "Skrooge document"), 0, i18nc("@title:window", "Select Skrooge document"));

    if (newPath.isEmpty() || oldPath == newPath) {
        return;
    }

    // Password dialog
    QString password;
    QPointer<KPasswordDialog> dlg = new KPasswordDialog();
    dlg->setPrompt(i18nc("Question", "If the file is protected.\nPlease enter the password."));
    if (dlg->exec() == QDialog::Accepted) {
        password = dlg->password();
    }
    delete dlg;

    // Save settings
    Settings::self()->setPath(newPath);
    Settings::self()->setPassword(password);
    Settings::self()->save();

    KDirWatch::self()->removeDir(oldPath);
    KDirWatch::self()->addFile(newPath);

    synchronize();
}

void skroogeakonadiResource::refresh()
{
    invalidateCache(currentCollection());
    synchronize();
}

AKONADI_RESOURCE_MAIN(skroogeakonadiResource)


