/*
    Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.com>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/
#include "dbinitializer.h"
#include "akonadiserver_debug.h"

#include <storage/querybuilder.h>
#include <storage/datastore.h>
#include <storage/parttypehelper.h>

using namespace Akonadi;
using namespace Akonadi::Server;

DbInitializer::~DbInitializer()
{
    cleanup();
}

Resource DbInitializer::createResource(const char *name)
{
    Resource res;
    qint64 id = -1;
    res.setName(QLatin1String(name));
    const bool ret = res.insert(&id);
    Q_ASSERT(ret);
    Q_UNUSED(ret);
    mResource = res;
    return res;
}

Collection DbInitializer::createCollection(const char *name, const Collection &parent)
{
    Collection col;
    if (parent.isValid()) {
        col.setParent(parent);
    }
    col.setName(QLatin1String(name));
    col.setRemoteId(QLatin1String(name));
    col.setResource(mResource);
    const bool ret = col.insert();
    Q_ASSERT(ret);
    Q_UNUSED(ret);
    return col;
}

PimItem DbInitializer::createItem(const char *name, const Collection &parent)
{
    PimItem item;
    MimeType mimeType = MimeType::retrieveByName(QLatin1String("test"));
    if (!mimeType.isValid()) {
        MimeType mt;
        mt.setName(QLatin1String("test"));
        mt.insert();
        mimeType = mt;
    }
    item.setMimeType(mimeType);
    item.setCollection(parent);
    item.setRemoteId(QLatin1String(name));
    const bool ret = item.insert() ;
    Q_ASSERT(ret);
    Q_UNUSED(ret);
    return item;
}

Part DbInitializer::createPart(qint64 pimItem, const QByteArray &partName, const QByteArray &partData)
{
    auto partType = PartTypeHelper::parseFqName(QString::fromLatin1(partName));
    PartType type = PartType::retrieveByFQNameOrCreate(partType.first, partType.second);

    Part part;
    part.setPimItemId(pimItem);
    part.setPartTypeId(type.id());
    part.setData(partData);
    part.setDatasize(partData.size());
    const bool ret = part.insert();
    Q_ASSERT(ret);
    Q_UNUSED(ret);
    return part;
}

QByteArray DbInitializer::toByteArray(bool enabled)
{
    if (enabled) {
        return "TRUE";
    }
    return "FALSE";
}

QByteArray DbInitializer::toByteArray(Collection::Tristate tristate)
{

    switch (tristate) {
    case Collection::True:
        return "TRUE";
    case Collection::False:
        return "FALSE";
    case Collection::Undefined:
    default:
        break;
    }
    return "DEFAULT";
}

Akonadi::Protocol::FetchCollectionsResponsePtr DbInitializer::listResponse(const Collection &col,
                                                                           bool ancestors,
                                                                           bool mimetypes,
                                                                           const QStringList &ancestorFetchScope)
{
    auto resp = Akonadi::Protocol::FetchCollectionsResponsePtr::create(col.id());
    resp->setParentId(col.parentId());
    resp->setName(col.name());
    if (mimetypes) {
        QStringList mts;
        for (const Akonadi::Server::MimeType &mt : col.mimeTypes()) {
            mts << mt.name();
        }
        resp->setMimeTypes(mts);
    }
    resp->setRemoteId(col.remoteId());
    resp->setRemoteRevision(col.remoteRevision());
    resp->setResource(col.resource().name());
    resp->setIsVirtual(col.isVirtual());
    Akonadi::Protocol::CachePolicy cp;
    cp.setInherit(true);
    cp.setLocalParts({ QLatin1String("ALL") });
    resp->setCachePolicy(cp);
    if (ancestors) {
        QVector<Akonadi::Protocol::Ancestor> ancs;
        Collection parent = col.parent();
        while (parent.isValid()) {
            Akonadi::Protocol::Ancestor anc;
            anc.setId(parent.id());
            anc.setRemoteId(parent.remoteId());
            anc.setName(parent.name());
            if (!ancestorFetchScope.isEmpty()) {
                anc.setRemoteId(parent.remoteId());
                Akonadi::Protocol::Attributes attrs;
                Q_FOREACH(const CollectionAttribute &attr, parent.attributes()) {
                    if (ancestorFetchScope.contains(QString::fromLatin1(attr.type()))) {
                        attrs.insert(attr.type(), attr.value());
                    }
                }
                attrs.insert("ENABLED", parent.enabled() ? "TRUE" : "FALSE");
                anc.setAttributes(attrs);
            }
            parent = parent.parent();
            ancs.push_back(anc);
        }
        // Root
        ancs.push_back(Akonadi::Protocol::Ancestor(0));
        resp->setAncestors(ancs);
    }
    resp->setReferenced(col.referenced());
    resp->setEnabled(col.enabled());
    resp->setDisplayPref(static_cast<Tristate>(col.displayPref()));
    resp->setSyncPref(static_cast<Tristate>(col.syncPref()));
    resp->setIndexPref(static_cast<Tristate>(col.indexPref()));

    Akonadi::Protocol::Attributes attrs;
    Q_FOREACH(const CollectionAttribute &attr, col.attributes()) {
        attrs.insert(attr.type(), attr.value());
    }
    resp->setAttributes(attrs);
    return resp;
}

Collection DbInitializer::collection(const char *name)
{
    return Collection::retrieveByName(QLatin1String(name));
}

void DbInitializer::cleanup()
{
    Q_FOREACH (Collection col, mResource.collections()) { //krazy:exclude=foreach
        if (!col.isVirtual()) {
            col.remove();
        }
    }
    mResource.remove();

    if (DataStore::self()->database().isOpen()) {
        {
            QueryBuilder qb(Relation::tableName(), QueryBuilder::Delete);
            qb.exec();
        }
        {
            QueryBuilder qb(Tag::tableName(), QueryBuilder::Delete);
            qb.exec();
        }
        {
            QueryBuilder qb(TagType::tableName(), QueryBuilder::Delete);
            qb.exec();
        }
    }

    Q_FOREACH(Part part, Part::retrieveAll()) {          //krazy:exclude=foreach
        part.remove();
    }
    Q_FOREACH(PimItem item, PimItem::retrieveAll()) {    //krazy:exclude=foreach
        item.remove();
    }
}
