/* -*- c++ -*-
 *
 * serverpage.cpp
 *
 * Copyright (C) 2003-2004 Petter Stokke <ummo@hellokitty.com>
 * Copyright (C) 2003-2004 Sebastian Sauer <mail@dipe.org>
 *
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <klocale.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kaction.h>
#include <klineeditdlg.h>
#include <kapplication.h>
#include <knuminput.h>
#include <kinputdialog.h>
#include <qintdict.h>
#include <qcheckbox.h>
#include <qpopupmenu.h>
#include <qclipboard.h>

#include "infolist.h"
#include "prefs.h"
#include "kmldonkey.h"
#include "addserver.h"

#include "serverinfo.h"
#include "clientinfo.h"
#include "network.h"

#include "serverpage.h"
#include "serverpage.moc"

ServerPage::ServerPage(QWidget* parent)
    : QVBox(parent, "serverPage")
    , KMLDonkeyPage()
    , ClipboardHelper()
{
    m_addServerAction = 0;

    serverItemList.setAutoDelete(true);

    serverView = new InfoList(this, "serverView", true);
    serverView->addColumn( i18n( "Server name" ) );
    serverView->addColumn( i18n( "Network" ) );
    serverView->addColumn( i18n( "Status" ) );
    serverView->addColumn( i18n( "Users" ) );
    serverView->addColumn( i18n( "Files" ) );
    serverView->addColumn( i18n( "Description" ) );
    serverView->addColumn( i18n( "Address" ) );
    serverView->addColumn( i18n( "Port" ) );
    serverView->addColumn( i18n( "Score" ) );
    serverView->addColumn( i18n( "ID" ) );
    serverView->addColumn( i18n( "Preferred" ) );
    serverView->setItemsRenameable(true);

    connect(serverView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
            this, SLOT(contextServer(KListView*, QListViewItem*, const QPoint&)));
    connect(serverView, SIGNAL(selectionChanged()), SLOT(pleaseUpdateActions()));
    connect(serverView, SIGNAL(gotFocus()), SLOT(pleaseUpdateActions()));

    connect(KMLDonkey::App->donkey, SIGNAL(serverUpdated(int)), this, SLOT(serverUpdated(int)));
    connect(KMLDonkey::App->donkey, SIGNAL(serverRemoved(int)), this, SLOT(serverRemoved(int)));
    connect(KMLDonkey::App->donkey, SIGNAL(networkUpdated(int)), this, SLOT(networkUpdated(int)));
}

void ServerPage::handleGenericAction(const QString& action)
{
    if (action == "copy_url") actionServerCopyURL();
    else if (action == "copy_html") actionServerCopyHTML();
}

void ServerPage::deactivatePageActions()
{
    enableActionList(serverActions, false);
}

QStringList ServerPage::supportedGenericActions()
{
    QStringList actions;
    QPtrList<QListViewItem> sl = serverView->selectedItems();

    if (!sl.isEmpty()) {
        enableActionList(serverActions, true);
        actions.append("copy_url");
        actions.append("copy_html");
    }
    else enableActionList(serverActions, false);

    return actions;
}

void ServerPage::plugGenericActions(QObject* object, const char* slot)
{
    connect(this, SIGNAL(genericActionsChanged(KMLDonkeyPage*)), object, slot);
}

void ServerPage::pleaseUpdateActions()
{
    emit genericActionsChanged(static_cast<KMLDonkeyPage*>(this));
}

void ServerPage::setupActions(KActionCollection* actionCollection)
{
    serverActions.append(new KAction(i18n("&Connect to Server"), "connect_creating", 0, this, SLOT(actionConnectServer()),
                                         actionCollection, "connect_server"));
    KMLDonkey::App->addCoreAction(new KAction(i18n("Connect &More Servers"), "connect_established", 0, this, SLOT(actionConnectMoreServers()),
                                  actionCollection, "connect_more_servers"));
    serverActions.append(new KAction(i18n("&Disconnect From Server"), "connect_no", 0, this, SLOT(actionDisconnectServer()),
                                         actionCollection, "disconnect_server"));

    m_addServerAction = new KAction(i18n("&Add Server..."), "edit", 0, this, SLOT(actionAddServer()),
                                    actionCollection, "add_server");
    KMLDonkey::App->addCoreAction(m_addServerAction);
    networkUpdated(0);

    serverActions.append(new KAction(i18n("&Remove Server"), "editdelete", 0, this, SLOT(actionRemoveServer()),
                                         actionCollection, "remove_server"));
    KMLDonkey::App->addCoreAction(new KAction(i18n("Remove &Old Servers"), "editshred", 0, this, SLOT(actionRemoveOldServers()),
                                  actionCollection, "remove_old_servers"));
    serverActions.append(new KAction(i18n("&Blacklist Server"), "clear_left", 0, this, SLOT(actionBlacklistServer()),
                                         actionCollection, "blacklist_server"));
    serverActions.append(new KAction(i18n("Re&name Server"), "filesaveas", 0, this, SLOT(actionRenameServer()),
                         actionCollection, "rename_server"));
    serverActions.append(new KAction(i18n("Toggle &Preferred"), "bookmark", 0, this, SLOT(actionTogglePreferred()),
                         actionCollection, "toggle_server_preferred"));

    hideDisconnectedServersAction = new KToggleAction(i18n("&Hide Disconnected Servers"), "filter", 0, actionCollection, "hide_disconnected_servers");
    connect(hideDisconnectedServersAction, SIGNAL(toggled(bool)), this, SLOT(actionHideDisconnectedServers(bool)));

    hideBlacklistedServersAction = new KToggleAction(i18n("Hide B&lacklisted Servers"), "filter", 0, actionCollection, "hide_blacklisted_servers");
    connect(hideBlacklistedServersAction, SIGNAL(toggled(bool)), this, SLOT(actionHideBlacklistedServers(bool)));

    (void)new KAction(i18n("Activate Servers Page"), 0, 0, this, SLOT(actionActivatePage()),
                      actionCollection, "activate_page_servers");

    enableActionList(serverActions, false);
}

void ServerPage::clear()
{
    serverItemList.clear();
    serverView->clear();
}

void ServerPage::configurePrefsDialog(KMLDonkeyPreferences* prefs)
{
    prefs->listsPage->hideDisconnectedServersCheckbox->setChecked(hideDisconnectedServersAction->isChecked());
    prefs->listsPage->hideBlacklistedServersCheckbox->setChecked(hideBlacklistedServersAction->isChecked());

    if (serverView->sortInterval() > 0) {
        prefs->listsPage->autoServerResortCheckbox->setChecked(true);
        prefs->listsPage->serverResortEntry->setValue( serverView->sortInterval() );
    }
    else
        prefs->listsPage->autoServerResortCheckbox->setChecked(false);
}

void ServerPage::applyPreferences(KMLDonkeyPreferences* prefs)
{
    if (prefs) {
        if (prefs->listsPage->hideDisconnectedServersCheckbox->isChecked() != hideDisconnectedServersAction->isChecked())
            actionHideDisconnectedServers( prefs->listsPage->hideDisconnectedServersCheckbox->isChecked() );
        if (prefs->listsPage->hideBlacklistedServersCheckbox->isChecked() != hideBlacklistedServersAction->isChecked())
            actionHideBlacklistedServers( prefs->listsPage->hideBlacklistedServersCheckbox->isChecked() );

        if (prefs->listsPage->autoServerResortCheckbox->isChecked() != (serverView->sortInterval() > 0) ||
            prefs->listsPage->autoServerResortCheckbox->isChecked() && (serverView->sortInterval() != prefs->listsPage->serverResortEntry->value()) )
                serverView->setSortInterval( prefs->listsPage->autoServerResortCheckbox->isChecked() ? prefs->listsPage->serverResortEntry->value() : 0 );
    }

    if (KMLDonkey::App->listFont !=  serverView->font())
        serverView->setFont(KMLDonkey::App->listFont);
}

void ServerPage::restoreState(KConfig* conf)
{
    conf->setGroup("Options");
    hideDisconnectedServersAction->setChecked(conf->readBoolEntry("HideDisconnectedServers", true));
    hideBlacklistedServersAction->setChecked(conf->readBoolEntry("HideBlacklistedServers", true));
    serverView->setSortInterval(conf->readNumEntry("ServerViewSort", 0));

    serverView->initialise();
    applyPreferences();
}

void ServerPage::saveState( KConfig* conf )
{
    serverView->saveLayout();

    conf->setGroup("Options");
    conf->writeEntry("HideDisconnectedServers", hideDisconnectedServersAction->isChecked());
    conf->writeEntry("HideBlacklistedServers", hideBlacklistedServersAction->isChecked());
    conf->writeEntry("ServerViewSort", serverView->sortInterval());
}

void ServerPage::contextServer(KListView*,QListViewItem*,const QPoint& pt)
{
    QPopupMenu *pop = (QPopupMenu*)(KMLDonkey::App->factory())->container("server_actions", KMLDonkey::App);
    if (!pop)
        KMLDonkey::App->showBadInstallDialog();
    else
        pop->popup(pt);
}

void ServerPage::actionConnectServer()
{
    QPtrList<QListViewItem> list = serverView->selectedItems();
    ServerInfoItem* it;
    for (it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (!si) continue;
        KMLDonkey::App->donkey->connectServer(si->serverNo());
    }
}

void ServerPage::actionConnectMoreServers()
{
    KMLDonkey::App->donkey->connectMoreServers();
}

void ServerPage::actionDisconnectServer()
{
    QPtrList<QListViewItem> list = serverView->selectedItems();
    ServerInfoItem* it;
    for (it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (!si) continue;
        KMLDonkey::App->donkey->disconnectServer(si->serverNo());
    }
}

void ServerPage::actionAddServer()
{
    AddServerDialog *dlg = new AddServerDialog(this);
    if (dlg) dlg->show();
}

void ServerPage::actionRemoveServer()
{
    QPtrList<QListViewItem> list = serverView->selectedItems();
    ServerInfoItem* it;
    for (it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (si) KMLDonkey::App->donkey->removeServer(si->serverNo());
    }
}

void ServerPage::actionRemoveOldServers()
{
    KMLDonkey::App->donkey->cleanOldServers();
}

void ServerPage::actionBlacklistServer()
{
    QPtrList<QListViewItem> list = serverView->selectedItems();
    for (ServerInfoItem* it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        KMLDonkey::App->donkey->blacklistServer(it->fileNo());
    }
}

void ServerPage::actionRenameServer()
{
    QPtrList<QListViewItem> list = serverView->selectedItems();
    for (ServerInfoItem* it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (!si) continue;
        it->startRename(0);
        return;
    }
}

void ServerPage::actionTogglePreferred()
{
    QPtrList<QListViewItem> list = serverView->selectedItems();
    for (ServerInfoItem* it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (si)
            KMLDonkey::App->donkey->setServerPreferred(si->serverNo(), !si->serverPreferred());
    }
}

void ServerPage::copyServerToClipboard(QPtrList<ServerInfo>& servers, ClipFormat format)
{
    QClipboard* clip = KApplication::clipboard();
    QStringList out;
    QPtrListIterator<ServerInfo> it(servers);
    ServerInfo* server;
    while ((server = it.current())) {
        ++it;
        switch (format) {
        case URL:
            out.append("ed2k://|server|" + server->serverAddress() + "|" + QString::number(server->serverPort()) + "|/");
            break;
        case HTML:
            out.append("<a href=\"ed2k://|server|" + server->serverAddress() + "|" + QString::number(server->serverPort()) +
                       "|/\">" + server->serverAddress() + ":" + QString::number(server->serverPort()) + "</a>");
            break;
        default:
            break;
        }
    }
    clip->setText(out.join("\n"), QClipboard::Selection);
}

void ServerPage::actionServerCopyURL()
{
    QPtrList<ServerInfo> servers;
    QPtrList<QListViewItem> list = serverView->selectedItems();
    ServerInfoItem* it;
    for (it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (si)
            servers.append(si);
    }
    copyServerToClipboard(servers, URL);
}

void ServerPage::actionServerCopyHTML()
{
    QPtrList<ServerInfo> servers;
    QPtrList<QListViewItem> list = serverView->selectedItems();
    ServerInfoItem* it;
    for (it = (ServerInfoItem*)list.first(); it; it = (ServerInfoItem*)list.next()) {
        ServerInfo* si = KMLDonkey::App->donkey->findServerNo(it->fileNo());
        if (si)
            servers.append(si);
    }
    copyServerToClipboard(servers, HTML);
}

void ServerPage::actionHideDisconnectedServers(bool show)
{
    hideDisconnectedServersAction->setChecked(show);
    QIntDictIterator<ServerInfo> it( KMLDonkey::App->donkey->connectedServers() );
    for ( ; it.current(); ++it) serverUpdated( it.current()->serverNo() );
}

void ServerPage::actionHideBlacklistedServers(bool show)
{
    hideBlacklistedServersAction->setChecked(show);
    QIntDictIterator<ServerInfo> it( KMLDonkey::App->donkey->connectedServers() );
    for ( ; it.current(); ++it) serverUpdated( it.current()->serverNo() );
}

void ServerPage::serverUpdated( int server )
{
    ServerInfo* si = KMLDonkey::App->donkey->findServerNo( server );
    ServerInfoItem* df = serverItemList[ server ];

    if ( !si || si->serverState() == ClientInfo::Removed ||
       ( hideDisconnectedServersAction->isChecked() && ( si->serverState() == ClientInfo::NotConnected || si->serverState() == ClientInfo::NotConnected2 ) ) ||
       ( hideBlacklistedServersAction->isChecked()  &&   si->serverState() == ClientInfo::Blacklisted ) )
    {
        if ( df ) serverItemList.remove( server );
        return;
    }

    if ( df )
        df->refresh();
    else
    {
        df = new ServerInfoItem( serverView, server );
        serverItemList.insert( server, df );
    }
}

void ServerPage::serverRemoved(int server)
{
    serverItemList.remove(server);
}

void ServerPage::actionActivatePage()
{
    KMLDonkey::App->activatePage(this);
}

void ServerPage::networkUpdated(int)
{
    if (!m_addServerAction)
        return;

    QIntDictIterator<Network> it( KMLDonkey::App->donkey->availableNetworks() );
    for ( ; it.current(); ++it )
        if (it.current() && it.current()->networkEnabled() && it.current()->networkFlags() & Network::NetworkHasServers) {
            m_addServerAction->setEnabled(true);
            return;
        }
    m_addServerAction->setEnabled(false);
}
