/* -*- c++ -*-
 *
 * roompage.cpp
 *
 * Copyright (C) 2003,2004 Sebastian Sauer <mail@dipe.org>
 * Copyright (C) 2003,2004 Petter Stokke <ummo@hellokitty.com>
 *
 * 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 <qpopupmenu.h>
#include <qstylesheet.h>
#include <kdebug.h>
#include <klocale.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kaction.h>
#include <ktabwidget.h>
#include <kinputdialog.h>

#include "kmldonkey.h"
#include "roompage.h"
#include "prefs.h"

#include "network.h"

#include <kdeversion.h>

/****************************************************************
 * RoomListViewItem
 ***************************************************************/

QString RoomListViewItem::xtext(int col) const
{
    RoomInfo* ri = KMLDonkey::App->donkey->findRoomNo(fileno);
    if (! ri) return QString();
    switch (col) {
        case 0:
            return ri->roomName();
        case 1:
            return QString::number(ri->roomUsers());
        case 2: {
            Network* net = KMLDonkey::App->donkey->findNetworkNo( ri->roomNetwork() );
            return ( net ? net->networkName() : QString::number(ri->roomNetwork()) );
        } break;
        case 3: {
            switch( ri->roomState() ) {
                case RoomInfo::Open: return i18n("Room state: open", "Open");
                case RoomInfo::Closed: return i18n("Room state: closed", "Closed");
                case RoomInfo::Paused: return i18n("Room state: paused", "Paused");
                default: return i18n("Room state: unknown", "Unknown");
            }
        } break;
        default: break;
    }
    return QString();
}

double RoomListViewItem::numeric(int col) const
{
    switch (col) {
        case 1: {
            RoomInfo* ri = KMLDonkey::App->donkey->findRoomNo(fileno);
            if (ri) return ri->roomUsers();
        } break;
        default: break;
    }
    return 0.0;
}

bool RoomListViewItem::isNumeric(int col) const
{
    switch (col) {
        case 1: return true;
        default: break;
    }
    return false;
}

/****************************************************************
 * RoomListView
 ***************************************************************/

RoomListView::RoomListView(QWidget* parent) : InfoList(parent, "roomView", true)
{
    InfoList::addColumn(i18n("Room name"));
    InfoList::addColumn(i18n("Users in a room", "Users"), -1, QListView::Maximum);
    InfoList::addColumn(i18n("Network a room is on", "Network"), -1, QListView::Maximum);
    InfoList::addColumn(i18n("State of a room", "State"), -1, QListView::Maximum);
}

RoomListView::~RoomListView()
{
}

RoomListViewItem* RoomListView::getItem(int id)
{
    return items.find(id);
}

void RoomListView::updateItem(int id, RoomInfo* ri)
{
    if (! ri) return;
    RoomListViewItem* item = items.find(id);
    if (! item) {
        item = new RoomListViewItem(this, id);
        items.insert(id, item);
    }
    item->refresh();
}

void RoomListView::clear()
{
    KListView::clear();
    items.clear();
}

/****************************************************************
 * RoomTab
 ***************************************************************/

RoomTab::RoomTab(QWidget* parent, RoomInfo* ri) : QVBox(parent)
{
    this->ri = ri;

    view = new KTextBrowser(this);
    view->setFocusPolicy(QTextBrowser::ClickFocus);
    view->setTextFormat(QTextBrowser::RichText);
    view->append( QString("<b>%1</b><hr>").arg(QStyleSheet::escape(ri->roomName())) );

    QValueList<RoomMessage*> list = ri->getMessages();
    for (QValueList<RoomMessage*>::Iterator it = list.begin(); it != list.end(); ++it)
        appendMessage(*it);
}

RoomTab::~RoomTab()
{
}

void RoomTab::appendMessage(RoomMessage* msg)
{
    QString body = QStyleSheet::escape(msg->messageBody());
    switch ( msg->messageType() ) {
        case RoomMessage::Server: {
            view->append(body);
        } break;
        case RoomMessage::Public: {
            view->append( i18n("Public message sent to a room (user, body)", "public <b>%1</b>: %2").arg(msg->messageUser()).arg(body) );
        } break;
        case RoomMessage::Private: {
            view->append( i18n("Private message from a room user (user, body)", "private <b>%1</b>: %2").arg(msg->messageUser()).arg(body) );
        } break;
        default: {
            kdDebug() << QString("Unhandled MessageType=%1, MessageBody=%2").arg(msg->messageType()).arg(body) << endl;
        } break;
    }
}

/****************************************************************
 * RoomPage
 ***************************************************************/

RoomPage::RoomPage(QWidget *parent)
    : QVBox(parent, "roomPage")
    , KMLDonkeyPage()
{
    mainsplitter = new QSplitter(this);
    roomview = new RoomListView(mainsplitter);
    mainsplitter->setResizeMode(roomview, QSplitter::KeepSize);

    connect(roomview, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
            SLOT(contextRoom(KListView*, QListViewItem*, const QPoint&)));
    connect(roomview, SIGNAL(doubleClicked(QListViewItem*)), SLOT(actionOpenRoom()));
    connect(roomview, SIGNAL(returnPressed(QListViewItem*)), SLOT(actionOpenRoom()));

    connect(roomview, SIGNAL(selectionChanged()), SLOT(pleaseUpdateActions()));
    connect(roomview, SIGNAL(gotFocus()), SLOT(pleaseUpdateActions()));

    pages = new KTabWidget(mainsplitter);
    pages->setHoverCloseButton(true);
    pages->setTabReorderingEnabled(true);
    connect(pages, SIGNAL(closeRequest(QWidget*)), SLOT(closeRoom(QWidget*)));

    connect(KMLDonkey::App->donkey, SIGNAL( roomUpdated(int) ), SLOT( actionRoomUpdated(int) ));
    connect(KMLDonkey::App->donkey, SIGNAL( roomMessage(int, RoomMessage*) ), SLOT( actionRoomMessage(int, RoomMessage*) ));
}

void RoomPage::setupActions(KActionCollection* actionCollection)
{
    RoomActions.append( new KAction(i18n("Set a room's state to open", "&Open Room"), "connect_creating", 0, this, SLOT(actionOpenRoom()),
                        actionCollection, "open_room") );
    RoomActions.append( new KAction(i18n("Set a room's state to paused", "&Pause Room"), "connect_established", 0, this, SLOT(actionPausedRoom()),
                        actionCollection, "paused_room") );
    RoomActions.append( new KAction(i18n("Set a room's state to closed", "&Close Room"), "connect_no", 0, this, SLOT(actionCloseRoom()),
                        actionCollection, "close_room") );
    ActionCloseAllRooms = new KAction(i18n("Close all open rooms", "Close &All Rooms"), "connect_no", 0, this, SLOT(actionCloseAllRooms()),
                          actionCollection, "close_all_rooms");
    deactivatePageActions();
}

void RoomPage::deactivatePageActions()
{
    enableActionList(RoomActions, false);
    ActionCloseAllRooms->setEnabled(false);
}

void RoomPage::applyPreferences(KMLDonkeyPreferences* /*prefs*/)
{
    roomview->QListView::setFont( KMLDonkey::App->listFont );
}

void RoomPage::saveState(KConfig* conf)
{
    roomview->saveLayout();
    conf->setGroup("Rooms");
    conf->writeEntry("mainsplitter", mainsplitter->sizes());
}

void RoomPage::restoreState(KConfig* conf)
{
    roomview->initialise();
    conf->setGroup("Rooms");
    mainsplitter->setSizes(conf->readIntListEntry("mainsplitter"));
    applyPreferences();
}

void RoomPage::clear()
{
    actionCloseAllRooms();
    roomview->clear();
    pleaseUpdateActions();
}

void RoomPage::pleaseUpdateActions()
{
    enableActionList(RoomActions, (roomview->hasFocus() && ! roomview->selectedItems().isEmpty()) );
    ActionCloseAllRooms->setEnabled( pages->count() > 0 );
}

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

void RoomPage::actionOpenRoom()
{
    if (! KMLDonkey::App->donkey->isConnected()) return;
    QPtrList<QListViewItem> list = roomview->selectedItems();
    RoomListViewItem *item;
    for (item = (RoomListViewItem*)list.first(); item; item = (RoomListViewItem*)list.next()) {
        RoomInfo* ri = KMLDonkey::App->donkey->findRoomNo( item->roomNo() );
        if (! ri) continue;

        RoomTab* tab = tabs.find( item->roomNo() );
        if (tab)
            pages->showPage( (QWidget*)tab );
        else {
            tab = new RoomTab(this, ri);
            tabs.insert(item->roomNo(), tab);
            QString caption = ri->roomName().left(35); // truncate long roomnames
            pages->addTab(tab, KGlobal::iconLoader()->loadIconSet("fileclose", KIcon::Small), caption);

            // Workaround for a strange rendering bug
            pages->hide();
            pages->show();

            KMLDonkey::App->donkey->setRoomState(item->roomNo(), RoomInfo::Open);
        }
    }
    pages->setCurrentPage(pages->count() - 1);
    pleaseUpdateActions();
}

void RoomPage::actionPausedRoom()
{
    if (! KMLDonkey::App->donkey->isConnected()) return;
    QPtrList<QListViewItem> list = roomview->selectedItems();
    RoomListViewItem *item;
    for (item = (RoomListViewItem*)list.first(); item; item = (RoomListViewItem*)list.next()) {
        RoomInfo* ri = KMLDonkey::App->donkey->findRoomNo( item->roomNo() );
        if (! ri) continue;
        if (ri->roomState() == RoomInfo::Open)
            KMLDonkey::App->donkey->setRoomState(ri->roomNum(), RoomInfo::Paused);
    }
}

void RoomPage::actionCloseRoom()
{
    if (! KMLDonkey::App->donkey->isConnected()) return;
    QPtrList<QListViewItem> list = roomview->selectedItems();
    RoomListViewItem *item;
    for (item = (RoomListViewItem*)list.first(); item; item = (RoomListViewItem*)list.next())
        closeRoom(item);
}

void RoomPage::actionCloseAllRooms()
{
    while (pages->count())
        closeRoom( pages->page(pages->currentPageIndex()) );
}

void RoomPage::actionRoomUpdated(int roomnr)
{
    // not needed to check if findRoomNo() results 'foo' cause updateItem() does that for us.
    roomview->updateItem(roomnr, KMLDonkey::App->donkey->findRoomNo(roomnr));
}

void RoomPage::actionRoomMessage(int roomid, RoomMessage* msg)
{
    RoomTab* tab = tabs.find(roomid);
    if (tab) tab->appendMessage(msg);
}

void RoomPage::closeRoom(RoomListViewItem* item)
{
    RoomTab* tab = tabs.find( item->roomNo() );
    if (tab) // if a RoomTab for this room exists close it as well
        closeRoom(tab);
    else {
        RoomInfo* ri = KMLDonkey::App->donkey->findRoomNo( item->roomNo() );
        if (ri) { // try to send a close-request if room isn't already closed
            if(ri->roomState() != RoomInfo::Closed && KMLDonkey::App->donkey->isConnected())
                KMLDonkey::App->donkey->setRoomState(ri->roomNum(), RoomInfo::Closed);
        }
    }
}

void RoomPage::closeRoom(QWidget* widget)
{
    RoomTab* tab = static_cast<RoomTab*>(widget);
    RoomInfo* ri = tab->getRoomInfo();
    if (ri) {
        tabs.remove( ri->roomNum() );
        if (ri->roomState() != RoomInfo::Closed && KMLDonkey::App->donkey->isConnected())
            KMLDonkey::App->donkey->setRoomState(ri->roomNum(), RoomInfo::Closed);
    }
    delete widget;
    pleaseUpdateActions();
}

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

#include "roompage.moc"
