/***************************************************************************
 *   Copyright (C) 2004 by Alexander Dymo <adymo@kdevelop.org>             *
 *                                                                         *
 *   This program 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 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 Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/
#include "profileengine.h"

#include <tqdir.h>

#include <kurl.h>
#include <kdebug.h>
#include <tdeglobal.h>
#include <kstandarddirs.h>

#include <kdevplugin.h>

ProfileEngine::ProfileEngine()
{
    TQStringList dirs = TDEGlobal::dirs()->findDirs("data", "tdevelop/profiles");

    m_rootProfile = new Profile(0, "KDevelop");

    TQString currPath = "/";
    TQMap<TQString, Profile*> passedPaths;

    for (TQStringList::const_iterator it = dirs.constBegin(); it != dirs.constEnd(); ++it)
        processDir(*it, currPath, passedPaths, m_rootProfile);
}

ProfileEngine::~ProfileEngine()
{
    delete m_rootProfile;
}

void ProfileEngine::processDir(const TQString &dir, const TQString &currPath, TQMap<TQString, Profile*> &passedPaths, Profile *root)
{
//     kdDebug() << "processDir: " << dir << " " << currPath << endl;

    TQDir qDir(dir);
    TQStringList entryList = qDir.entryList(TQDir::Dirs);
    for (TQStringList::const_iterator eit = entryList.constBegin(); eit != entryList.constEnd(); ++eit)
    {
        if ((*eit != "..") && (*eit != "."))
        {
            TQString dirName = *eit;
            Profile *profile = 0;
            if (passedPaths.contains(currPath + dirName))
                profile = passedPaths[currPath + dirName];
            else
            {
                profile = new Profile(root, dirName);
                passedPaths[currPath + dirName] = profile;
            }
            processDir(dir + *eit + "/", currPath + dirName, passedPaths, profile);
        }
    }
}

TDETrader::OfferList ProfileEngine::offers(const TQString &profileName, OfferType offerType)
{
    ProfileListing listing;
    Profile *profile = 0;
    getProfileWithListing(listing, &profile, profileName);

    if (!profile)
        return TDETrader::OfferList();

    TQString constraint = TQString::fromLatin1("[X-TDevelop-Version] == %1").arg(TDEVELOP_PLUGIN_VERSION);
    switch (offerType) {
        case Global:
            constraint += TQString::fromLatin1(" and [X-TDevelop-Scope] == 'Global'");
            break;
        case Project:
            constraint += TQString::fromLatin1(" and [X-TDevelop-Scope] == 'Project'");
            break;
        case Core:
            constraint += TQString::fromLatin1(" and [X-TDevelop-Scope] == 'Core'");
            break;
    }
    TQString constraint_add = "";
    Profile::EntryList properties = profile->list(Profile::Properties);
    int i = 0;
    for (Profile::EntryList::const_iterator it = properties.begin(); it != properties.end(); ++it)
        constraint_add += TQString::fromLatin1(" %1 '%2' in [X-TDevelop-Properties]").
            arg((i++)==0?"":"or").arg((*it).name);
    if (!constraint_add.isEmpty())
        constraint += " and ( " + constraint_add + " ) ";

//BEGIN debug
/*    kdDebug(9000) << "=============" << endl
        << "    =============" << endl
        << "        =============   Query for Profile:" << endl
        << "        " << constraint << endl << endl << endl;*/
//END debug

    TDETrader::OfferList list = TDETrader::self()->query(TQString::fromLatin1("TDevelop/Plugin"), constraint);
    TQStringList names;

/* Wrong, this is not what we want to do.
    Profile::EntryList disableList = profile->list(Profile::ExplicitDisable);
    TDETrader::OfferList::iterator it = list.begin();
    while (it != list.end())
    {
        TQString name = (*it)->desktopEntryName();
        names.append(name);
        if (profile->hasInEntryList(disableList, name))
        {
            it = list.remove(it);
            continue;
        }
        ++it;
    }
*/
    Profile::EntryList enableList = profile->list(Profile::ExplicitEnable);
    for (Profile::EntryList::const_iterator it = enableList.begin(); it != enableList.end(); ++it)
    {
        if (names.contains((*it).name))
            continue;
        TQString constraint = TQString::fromLatin1("[X-TDevelop-Version] == %1").arg(TDEVELOP_PLUGIN_VERSION);
        constraint += TQString::fromLatin1("and [Name] == '%1'").arg((*it).name);
        TDETrader::OfferList enable = TDETrader::self()->query(TQString::fromLatin1("TDevelop/Plugin"), constraint);
        list += enable;
    }

/*//BEGIN debug
    kdDebug() << "=============" << endl
        << "    =============" << endl
        << "        =============   Plugins for Profile:" << endl;
    for (TDETrader::OfferList::const_iterator it = list.begin(); it != list.end(); ++it)
        kdDebug() << "        " << (*it)->name() << endl;
    kdDebug() << endl << endl;
//END debug*/

    return list;
}

TDETrader::OfferList ProfileEngine::allOffers(OfferType offerType)
{
    TQString constraint = TQString::fromLatin1("[X-TDevelop-Version] == %1").arg(TDEVELOP_PLUGIN_VERSION);
    switch (offerType) {
        case Global:
            constraint += TQString::fromLatin1(" and [X-TDevelop-Scope] == 'Global'");
            break;
        case Project:
            constraint += TQString::fromLatin1(" and [X-TDevelop-Scope] == 'Project'");
            break;
        case Core:
            constraint += TQString::fromLatin1(" and [X-TDevelop-Scope] == 'Core'");
            break;
    }
    return TDETrader::self()->query(TQString::fromLatin1("TDevelop/Plugin"), constraint);
}

void ProfileEngine::getProfileWithListing(ProfileListing &listing, Profile **profile,
    const TQString &profileName)
{
    if (profileName == "KDevelop")
        *profile = m_rootProfile;
    else
    {
        walkProfiles<ProfileListing>(listing, m_rootProfile);
        *profile = listing.profiles[profileName];
    }
}

KURL::List ProfileEngine::resources(const TQString &profileName, const TQString &nameFilter)
{
    ProfileListing listing;
    Profile *profile = 0;
    getProfileWithListing(listing, &profile, profileName);

    if (!profile)
        return KURL::List();

    return resources(profile, nameFilter);
}

KURL::List ProfileEngine::resources(Profile *profile, const TQString &nameFilter)
{
    return profile->resources(nameFilter);
}

KURL::List ProfileEngine::resourcesRecursive(const TQString &profileName, const TQString &nameFilter)
{
    ProfileListing listing;
    Profile *profile = 0;
    getProfileWithListing(listing, &profile, profileName);
    KURL::List resources = profile->resources(nameFilter);

    ProfileListingEx listingEx(nameFilter);
    walkProfiles<ProfileListingEx>(listingEx, profile);

    resources += listingEx.resourceList;
    return resources;
}

void ProfileEngine::diffProfiles(OfferType offerType, const TQString &profile1,
    const TQString &profile2, TQStringList &unload, TDETrader::OfferList &load)
{
    TDETrader::OfferList offers1 = offers(profile1, offerType);
    TDETrader::OfferList offers2 = offers(profile2, offerType);

    TQStringList offers1List;
    for (TDETrader::OfferList::const_iterator it = offers1.constBegin();
        it != offers1.constEnd(); ++it)
        offers1List.append((*it)->desktopEntryName());
    TQMap<TQString, KService::Ptr> offers2List;
    for (TDETrader::OfferList::const_iterator it = offers2.constBegin();
        it != offers2.constEnd(); ++it)
        offers2List[(*it)->desktopEntryName()] = *it;

//    kdDebug() << "OLD PROFILE: " << offers1List << endl;
//    kdDebug() << "NEW PROFILE: " << offers2List << endl;

    for (TQStringList::const_iterator it = offers1List.constBegin();
        it != offers1List.constEnd(); ++it)
    {
//         kdDebug() << "checking: " << *it << endl;
        if (offers2List.contains(*it))
        {
//             kdDebug() << "    keep" << endl;
            offers2.remove(offers2List[*it]);
        }
        else
        {
//             kdDebug() << "    unload" << endl;
            unload.append(*it);
        }
    }
    load = offers2;
}

Profile *ProfileEngine::findProfile(const TQString & profileName)
{
    Profile *profile;
    ProfileListing listing;
    getProfileWithListing(listing, &profile, profileName);
    return profile;
}

void ProfileEngine::addResource(const TQString &profileName, const KURL &url)
{
    ProfileListing listing;
    Profile *profile = 0;
    getProfileWithListing(listing, &profile, profileName);

    if (!profile)
        return;

    profile->addResource(url);
}
