/*
 * This file is part of the KDE project
 *
 * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
 *  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 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 "wdgscriptsmanager.h"

#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqheader.h>
#include <tqobjectlist.h>
#include <tqtooltip.h>

#include <tdeapplication.h>
#include <tdeversion.h>
#include <tdefiledialog.h>
#include <kiconloader.h>
#include <tdelistview.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kpushbutton.h>
#include <kstandarddirs.h>
#include <tdetoolbar.h>

#if KDE_IS_VERSION(3, 4, 0)
  // The TDENewStuffSecure we use internaly for the GetHotNewStuff-functionality
  // was introduced with KDE 3.4.
  #define KROSS_SUPPORT_NEWSTUFF
#endif

#ifdef KROSS_SUPPORT_NEWSTUFF
  #include <tdenewstuff/provider.h>
  #include <tdenewstuff/engine.h>
  #include <tdenewstuff/downloaddialog.h>
  #include <tdenewstuff/knewstuffsecure.h>
#endif

#include "scriptguiclient.h"
#include "scriptaction.h"

namespace Kross { namespace Api {

#ifdef KROSS_SUPPORT_NEWSTUFF
class ScriptNewStuff : public TDENewStuffSecure
{
    public:
        ScriptNewStuff(ScriptGUIClient* scripguiclient, const TQString& type, TQWidget *parentWidget = 0)
            : TDENewStuffSecure(type, parentWidget)
            , m_scripguiclient(scripguiclient) {}
        virtual ~ScriptNewStuff() {}
    private:
        ScriptGUIClient* m_scripguiclient;
        virtual void installResource() { m_scripguiclient->installScriptPackage( m_tarName ); }
};
#endif

class ListItem : public TQListViewItem
{
    private:
        ScriptActionCollection* m_collection;
        ScriptAction::Ptr m_action;
    public:
        ListItem(TQListView* parentview, ScriptActionCollection* collection)
            : TQListViewItem(parentview), m_collection(collection), m_action(0) {}

        ListItem(ListItem* parentitem, TQListViewItem* afteritem, ScriptAction::Ptr action)
            : TQListViewItem(parentitem, afteritem), m_collection( parentitem->collection() ), m_action(action) {}

        ScriptAction::Ptr action() const { return m_action; }
        ScriptActionCollection* collection() const { return m_collection; }
        //ScriptActionMenu* actionMenu() const { return m_menu; }
};

class ToolTip : public TQToolTip
{
    public:
        ToolTip(TDEListView* parent) : TQToolTip(parent->viewport()), m_parent(parent) {}
        virtual ~ToolTip () { remove(m_parent->viewport()); }
    protected:
        virtual void maybeTip(const TQPoint& p) {
            ListItem* item = dynamic_cast<ListItem*>( m_parent->itemAt(p) );
            if(item) {
                TQRect r( m_parent->itemRect(item) );
                if(r.isValid() && item->action()) {
                    tip(r, TQString("<qt>%1</qt>").arg(item->action()->toolTip()));
                }
            }
        }
    private:
        TDEListView* m_parent;
};

class WdgScriptsManagerPrivate
{
    friend class WdgScriptsManager;
    ScriptGUIClient* m_scripguiclient;
    ToolTip* m_tooltip;
#ifdef KROSS_SUPPORT_NEWSTUFF
    ScriptNewStuff* newstuff;
#endif
    //enum { LoadBtn = 0, UnloadBtn, InstallBtn, UninstallBtn, ExecBtn, NewStuffBtn };
};

WdgScriptsManager::WdgScriptsManager(ScriptGUIClient* scr, TQWidget* parent, const char* name, WFlags fl )
    : WdgScriptsManagerBase(parent, name, fl)
    , d(new WdgScriptsManagerPrivate)
{
    d->m_scripguiclient = scr;
    d->m_tooltip = new ToolTip(scriptsList);
#ifdef KROSS_SUPPORT_NEWSTUFF
    d->newstuff = 0;
#endif

    scriptsList->header()->hide();
    //scriptsList->header()->setClickEnabled(false);
    scriptsList->setAllColumnsShowFocus(true);
    //scriptsList->setRootIsDecorated(true);
    scriptsList->setSorting(-1);
    scriptsList->addColumn("text");
    //scriptsList->setColumnWidthMode(1, TQListView::Manual);

    slotFillScriptsList();

    slotSelectionChanged(0);
    connect(scriptsList, TQ_SIGNAL(selectionChanged(TQListViewItem*)), this, TQ_SLOT(slotSelectionChanged(TQListViewItem*)));

    btnExec->setIconSet(TDEGlobal::instance()->iconLoader()->loadIconSet( "application-x-executable", TDEIcon::MainToolbar, 16 ));
    connect(btnExec, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotExecuteScript()));
    btnLoad->setIconSet(TDEGlobal::instance()->iconLoader()->loadIconSet( "document-open", TDEIcon::MainToolbar, 16 ));
    connect(btnLoad, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotLoadScript()));
    btnUnload->setIconSet(TDEGlobal::instance()->iconLoader()->loadIconSet( "window-close", TDEIcon::MainToolbar, 16 ));
    connect(btnUnload, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotUnloadScript()));
    btnInstall->setIconSet(TDEGlobal::instance()->iconLoader()->loadIconSet( "fileimport", TDEIcon::MainToolbar, 16 ));
    connect(btnInstall, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotInstallScript()));
    btnUninstall->setIconSet(TDEGlobal::instance()->iconLoader()->loadIconSet( "window-close", TDEIcon::MainToolbar, 16 ));
    connect(btnUninstall, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotUninstallScript()));
#ifdef KROSS_SUPPORT_NEWSTUFF
    btnNewStuff->setIconSet(TDEGlobal::instance()->iconLoader()->loadIconSet( "knewstuff", TDEIcon::MainToolbar, 16 ));
    connect(btnNewStuff, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotGetNewScript()));
#endif
/*
    toolBar->setIconText( TDEToolBar::IconTextRight );

    toolBar->insertButton("application-x-executable", WdgScriptsManagerPrivate::ExecBtn, false, i18n("Execute"));
    toolBar->addConnection(WdgScriptsManagerPrivate::ExecBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotExecuteScript()));
    toolBar->insertLineSeparator();
    toolBar->insertButton("document-open", WdgScriptsManagerPrivate::LoadBtn, true, i18n("Load"));
    toolBar->addConnection(WdgScriptsManagerPrivate::LoadBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotLoadScript()));
    toolBar->insertButton("window-close", WdgScriptsManagerPrivate::UnloadBtn, false, i18n("Unload"));
    toolBar->addConnection(WdgScriptsManagerPrivate::UnloadBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotUnloadScript()));
    toolBar->insertLineSeparator();
    toolBar->insertButton("fileimport", WdgScriptsManagerPrivate::InstallBtn, true, i18n("Install"));
    toolBar->addConnection(WdgScriptsManagerPrivate::InstallBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotInstallScript()));
    toolBar->insertButton("window-close", WdgScriptsManagerPrivate::UninstallBtn, false, i18n("Uninstall"));
    toolBar->addConnection(WdgScriptsManagerPrivate::UninstallBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotUninstallScript()));
#ifdef KROSS_SUPPORT_NEWSTUFF
    toolBar->insertLineSeparator();
    toolBar->insertButton("knewstuff", WdgScriptsManagerPrivate::NewStuffBtn, true, i18n("Get More Scripts"));
    toolBar->addConnection(WdgScriptsManagerPrivate::NewStuffBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotGetNewScript()));
#endif
*/
    connect(scr, TQ_SIGNAL( collectionChanged(ScriptActionCollection*) ),
            this, TQ_SLOT( slotFillScriptsList() ));
}

WdgScriptsManager::~WdgScriptsManager()
{
    delete d->m_tooltip;
    delete d;
}

void WdgScriptsManager::slotFillScriptsList()
{
    scriptsList->clear();

    addItem( d->m_scripguiclient->getActionCollection("executedscripts") );
    addItem( d->m_scripguiclient->getActionCollection("loadedscripts") );
    addItem( d->m_scripguiclient->getActionCollection("installedscripts") );
}

void WdgScriptsManager::addItem(ScriptActionCollection* collection)
{
    if(! collection)
        return;

    ListItem* i = new ListItem(scriptsList, collection);
    i->setText(0, collection->actionMenu()->text());
    i->setOpen(true);

    TQValueList<ScriptAction::Ptr> list = collection->actions();
    TQListViewItem* lastitem = 0;
    for(TQValueList<ScriptAction::Ptr>::Iterator it = list.begin(); it != list.end(); ++it)
        lastitem = addItem(*it, i, lastitem);
}

TQListViewItem* WdgScriptsManager::addItem(ScriptAction::Ptr action, TQListViewItem* parentitem, TQListViewItem* afteritem)
{
    if(! action)
        return 0;

    ListItem* i = new ListItem(dynamic_cast<ListItem*>(parentitem), afteritem, action);
    i->setText(0, action->text()); // FIXME: i18nise it for ko2.0
    //i->setText(1, action->getDescription()); // FIXME: i18nise it for ko2.0
    //i->setText(2, action->name());

    TQPixmap pm;
    if(action->hasIcon()) {
        TDEIconLoader* icons = TDEGlobal::iconLoader();
        pm = icons->loadIconSet(action->icon(), TDEIcon::Small).pixmap(TQIconSet::Small, TQIconSet::Active);
    }
    else {
        pm = action->iconSet(TDEIcon::Small, 16).pixmap(TQIconSet::Small, TQIconSet::Active);
    }
    if(! pm.isNull())
        i->setPixmap(0, pm); // display the icon

    return i;
}

void WdgScriptsManager::slotSelectionChanged(TQListViewItem* item)
{
    ListItem* i = dynamic_cast<ListItem*>(item);
    Kross::Api::ScriptActionCollection* installedcollection = d->m_scripguiclient->getActionCollection("installedscripts");

    //toolBar->setItemEnabled(WdgScriptsManagerPrivate::ExecBtn, i && i->action());
    //toolBar->setItemEnabled(WdgScriptsManagerPrivate::UninstallBtn, i && i->action() && i->collection() == installedcollection);
    //toolBar->setItemEnabled(WdgScriptsManagerPrivate::UnloadBtn, i && i->action() && i->collection() != installedcollection);
    btnExec->setEnabled(i && i->action());
    btnUnload->setEnabled(i && i->action() && i->collection() != installedcollection);
    btnUninstall->setEnabled(i && i->action() && i->collection() == installedcollection);
}

void WdgScriptsManager::slotLoadScript()
{
    if(d->m_scripguiclient->loadScriptFile())
        slotFillScriptsList();
}

void WdgScriptsManager::slotInstallScript()
{
    KFileDialog* filedialog = new KFileDialog(
        TQString(), // startdir
        "*.tar.gz *.tgz *.bz2", // filter
        this, // parent widget
        "WdgScriptsManagerInstallFileDialog", // name
        true // modal
    );
    filedialog->setCaption( i18n("Install Script Package") );

    if(! filedialog->exec())
        return;

    if(! d->m_scripguiclient->installScriptPackage( filedialog->selectedURL().path() )) {
        krosswarning("Failed to install scriptpackage");
        return;
    }

    slotFillScriptsList();
}

void WdgScriptsManager::slotUninstallScript()
{
    ListItem* item = dynamic_cast<ListItem*>( scriptsList->currentItem() );
    if( !item || !item->action() )
        return;

    Kross::Api::ScriptActionCollection* installedcollection = d->m_scripguiclient->getActionCollection("installedscripts");
    if( !item->collection() || item->collection() != installedcollection)
        return;

    const TQString packagepath = item->action()->getPackagePath();
    if( !packagepath)
        return;

    if( KMessageBox::warningContinueCancel(0,
        i18n("Uninstall the script package \"%1\" and delete the package's folder \"%2\"?")
            .arg(item->action()->text()).arg(packagepath),
        i18n("Uninstall")) != KMessageBox::Continue )
    {
        return;
    }

    if(! d->m_scripguiclient->uninstallScriptPackage(packagepath)) {
        krosswarning("Failed to uninstall scriptpackage");
        return;
    }

    slotFillScriptsList();
}

void WdgScriptsManager::slotExecuteScript()
{
    ListItem* item = dynamic_cast<ListItem*>( scriptsList->currentItem() );
    if(item && item->action())
        item->action()->activate();
}

void WdgScriptsManager::slotUnloadScript()
{
    ListItem* item = dynamic_cast<ListItem*>( scriptsList->currentItem() );
    if(item && item->action()) {
        item->collection()->detach( item->action() );
        slotFillScriptsList();
    }
}

void WdgScriptsManager::slotGetNewScript()
{
#ifdef KROSS_SUPPORT_NEWSTUFF
    const TQString appname = TDEApplication::kApplication()->name();
    const TQString type = TQString("%1 1.x script").arg(appname);

    if(! d->newstuff) {
        d->newstuff = new ScriptNewStuff(d->m_scripguiclient, type);
        connect(d->newstuff, TQ_SIGNAL(installFinished()), this, TQ_SLOT(slotResourceInstalled()));
    }

    KNS::Engine *engine = new KNS::Engine(d->newstuff, type, this);
    KNS::DownloadDialog *d = new KNS::DownloadDialog( engine, this );
    d->setType(type);

    KNS::ProviderLoader *p = new KNS::ProviderLoader(this);
    TQObject::connect(p, TQ_SIGNAL(providersLoaded(Provider::List*)),
                     d, TQ_SLOT(slotProviders(Provider::List*)));

    p->load(type, "https://www.trinitydesktop.org/ocs/providers.xml");
    d->exec();
#endif
}

void WdgScriptsManager::slotResourceInstalled()
{
    // Delete TDENewStuff's configuration entries. These entries reflect what has
    // already been installed. As we cannot yet keep them in sync after uninstalling
    // scripts, we deactivate the check marks entirely.
    TDEGlobal::config()->deleteGroup("TDENewStuffStatus");
}

}}

#include "wdgscriptsmanager.moc"
