/* -*- c++ -*-
 *
 * clientlist.cpp
 *
 * Copyright (C) 2003 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 <klocale.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kpopupmenu.h>
#include <qpainter.h>

#include "clientlist.h"
#include "kmldonkey.h"
#include "clientinfo.h"

#include "network.h"

#include "clientlist.moc"



SourceItem::SourceItem(ClientList* parent, int fileno, int clientno)
    : KListViewItem((KListView*)parent)
    , AvailabilityRenderer(fileno, clientno)
{
    fn = fileno; cn = clientno;
    if (!KMLDonkey::App->donkey->findClientNo(cn))
	KMLDonkey::App->donkey->refreshClientInfo(cn);
}

int SourceItem::fileNo() const { return fn; }
int SourceItem::clientNo() const { return cn; }

QString SourceItem::text(int column) const
{
    ClientInfo* cl = KMLDonkey::App->donkey->findClientNo(cn);
    if (!cl) {
	if (column) return QString::null;
	return i18n("Unknown");
    }

    switch (column) {
    case 0: // Name
	return cl->clientName();
    case 1: { // Network
	Network* net = KMLDonkey::App->donkey->findNetworkNo(cl->clientNetwork());
	if (!net) return i18n("Unknown");
	return net->networkName();
    }
    case 2: // Type
	switch (cl->clientType()) {
	case ClientInfo::NormalClient:
	    return i18n("Normal");
	case ClientInfo::FriendClient:
	    return i18n("Friend");
	case ClientInfo::ContactClient:
	    return i18n("Contact");
	default:
	    return i18n("Unknown");
	}
    case 3: // Kind
	return cl->clientKind();
    case 4: // State
	switch (cl->clientState()) {
	case ClientInfo::NotConnected:
	case ClientInfo::NotConnected2: return i18n("Not connected");
	case ClientInfo::Connecting: return i18n("Connecting");
	case ClientInfo::Initiating: return i18n("Initiating");
	case ClientInfo::Downloading: return i18n("Downloading");
	case ClientInfo::Connected:
	case ClientInfo::Connected3: return i18n("Connected");
	case ClientInfo::Connected2: return i18n("Queued: %1").arg(cl->clientQueuePosition());
	case ClientInfo::NewHost: return i18n("New host");
	case ClientInfo::Removed: return i18n("Removed");
	case ClientInfo::Blacklisted: return i18n("Blacklisted");
	default: return i18n("Unknown: %1").arg(cl->clientState());
	}
    case 6: // Software
	if (cl->clientSoftware().isNull())
	    return i18n("Unknown");
	else {
            QString software(cl->clientSoftware());
	    if (!cl->clientEmuleMod().isEmpty())
		software += i18n("eMule mod appended to client software tag", " (%1)").arg(cl->clientEmuleMod());
            if (!cl->clientRelease().isEmpty())
                software += i18n("Client software release appended to client software tag", " %1").arg(cl->clientRelease());
            return software;
	}
    case 7: { // Currently downloading file
	if (!cl->clientDownloading()) return QString::null;
	FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo(cl->clientDownloading());
	if (!fi) {
	    kdDebug() << "Invalid file ID from downloading client: " << cl->clientDownloading() << endl;
	    return QString::null;
	}
	return fi->fileName();
    }
    default:
	return QString::null;
    }
}

void SourceItem::paintCell(QPainter* p, const QColorGroup& cg, int col, int w, int align)
{
    if (col == 5) {
	QRect foo(0, 0, w, height());
	paintAvailability(*p, foo);
	return;
    }

    QColorGroup colgrp(cg);
    if (KMLDonkey::App->coloredViews) {
	ClientInfo* cl = KMLDonkey::App->donkey->findClientNo(cn);
	if (cl) {
	    switch (cl->clientState()) {
	    case ClientInfo::NotConnected:
	    case ClientInfo::NotConnected2:
		colgrp.setColor(QColorGroup::Text, KMLDonkey::App->colorSourceNotConnected);
		break;
	    case ClientInfo::Connecting:
	    case ClientInfo::Initiating:
		colgrp.setColor(QColorGroup::Text, KMLDonkey::App->colorSourceConnecting);
		break;
	    case ClientInfo::Downloading:
		colgrp.setColor(QColorGroup::Text, KMLDonkey::App->colorSourceDownloading);
		break;
	    case ClientInfo::Connected:
	    case ClientInfo::Connected2:
		colgrp.setColor(QColorGroup::Text, KMLDonkey::App->colorSourceQueued);
		break;
	    case ClientInfo::Blacklisted:
		colgrp.setColor(QColorGroup::Text, KMLDonkey::App->colorSourceBlacklisted);
		break;
	    default:
		break;
	    }
	}
    }

    p->save();
    KListViewItem::paintCell(p, colgrp, col, w, align);
    p->restore();
}

int SourceItem::width(const QFontMetrics& fm, const QListView* lv, int c) const
{
    if (c == 5) return (chunkNo > 100) ? 100 : chunkNo;
    return KListViewItem::width(fm, lv, c);
}



ClientList::ClientList(int fileno, QWidget* parent, const char* name)
    : KListView(parent, name)
{
    sources.setAutoDelete(true);
    fn = fileno;
    showsources = true;

    setSelectionModeExt(KListView::Extended);
    setAllColumnsShowFocus(true);
    setShowSortIndicator(true);
    setResizeMode(KListView::NoColumn);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setMinimumSize(1,1);
    setFont(KMLDonkey::App->listFont);

    setColumnWidthMode(addColumn(i18n("Name")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("Network")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("Type")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("Location")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("State")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("Availability")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("Software")), QListView::Manual);
    setColumnWidthMode(addColumn(i18n("Currently downloading")), QListView::Manual);
}

void ClientList::contextSource(KListView*, QListViewItem* item, const QPoint& pt)
{
    if (!item) return;
    ClientInfo* cl = KMLDonkey::App->donkey->findClientNo(((SourceItem*)item)->clientNo());
    if (!cl) return;
    KIconLoader* icons = KGlobal::iconLoader();
    KPopupMenu* pop = new KPopupMenu(this);
    pop->insertTitle(i18n("Sources"));
    pop->insertItem(icons->loadIconSet("edit_add", KIcon::Small), i18n("&Add to Friends"), this, SLOT(addToFriends()));
    pop->popup(pt);
}

void ClientList::addToFriends()
{
    QPtrList<QListViewItem> list = selectedItems();
    SourceItem* it;
    for (it = (SourceItem*)list.first(); it; it = (SourceItem*)list.next())
	KMLDonkey::App->donkey->addClientFriend(it->clientNo());
}

void ClientList::showEvent(QShowEvent*)
{
    if (! showsources) return;
    showsources = false;

    FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo(fn);
    if (fi) {
	int sortcol = sortColumn(), i = 0;
	setUpdatesEnabled(false);
	setSorting(-1);
	const QMap<int,QString>& src = fi->fileSources();
	QMap<int,QString>::ConstIterator it = src.begin();
	for ( ; it != src.end(); ++it) {
	    i++;
	    while (sources.remove(it.key()));
	    sources.insert(it.key(), new SourceItem(this, fn, it.key()));
	}
	setSorting(sortcol);
	setUpdatesEnabled(true);
    }

    connect(this, SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint&)), this, SLOT(contextSource(KListView*,QListViewItem*,const QPoint&)));

    connect(KMLDonkey::App->donkey, SIGNAL(fileSourceUpdated(int,int)), this, SLOT(fileSourceUpdated(int,int)));
    connect(KMLDonkey::App->donkey, SIGNAL(fileSourceRemoved(int,int)), this, SLOT(fileSourceRemoved(int,int)));
    connect(KMLDonkey::App->donkey, SIGNAL(clientUpdated(int)), this, SLOT(clientUpdated(int)));
    connect(KMLDonkey::App->donkey, SIGNAL(clientRemoved(int)), this, SLOT(clientRemoved(int)));
}

void ClientList::fileSourceUpdated(int fileno, int source)
{
    if (fileno != fn) return;
    SourceItem* cl = sources[source];
    if (!cl) {
	while (sources.remove(source));
	sources.insert(source, new SourceItem(this, fn, source));
    } else
	cl->repaint();
}

void ClientList::fileSourceRemoved(int fileno, int source)
{
    if (fileno != fn) return;
    while (sources.remove(source));
}

void ClientList::clientUpdated(int client)
{
    if (!sources[client]) return;
    ClientInfo* cl = KMLDonkey::App->donkey->findClientNo(client);
    switch (cl->clientState()) {
    case ClientInfo::Removed:
	while (sources.remove(client));
	break;
    default:
	sources[client]->repaint();
	break;
    }
}

void ClientList::clientRemoved(int client)
{
    while (sources.remove(client));
}

void ClientList::loseCache()
{
    QListViewItemIterator it(this);
    for (; it.current(); ++it) {
	SourceItem* cl = dynamic_cast<SourceItem*>(it.current());
	if (cl) cl->loseCache();
    }
}
