/***************************************************************************
                          apolloninfotab.cpp  -  description
                             -------------------
begin           : Dec 05 2003
copyright       : (C) 2002 by Bastiaan Naber, (C) 2002 by Robert Wittams
email           : bastiaan@ricardis.tudelft.nl
description     :

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <errno.h>
#include <unistd.h>

#include <qlabel.h>
#include <qhbox.h>
#include <qtextedit.h>
#include <qtimer.h>
#include <qregexp.h>
#include <qmime.h>

#include <klocale.h>
#include <kpushbutton.h>
#include <kiconloader.h>
#include <kicontheme.h>

#include "apolloninfotab.h"
#include "apollonutils.h"
#include "giftconnection.h"

// constructor
ApollonInfoTab::ApollonInfoTab(QWidget* parent, const char *name, giFTConnection* gcn) :
  ApollonTab(parent, name, gcn),
  m_numStatUpdates(0),
  m_tries(0)
{
	connect(m_gcn, SIGNAL(connected()),              this, SLOT(connected()) );
	connect(m_gcn, SIGNAL(disconnected()),           this, SLOT(disconnected()));
	connect(m_gcn, SIGNAL(socketError(int)),         this, SLOT(socketError(int)));
	connect(m_gcn, SIGNAL(giftStatusReply(QString)), this, SLOT(giftStatusReply(QString)));

	QHBox *box = new QHBox(this);
	//KIconLoader *loader = KGlobal::iconLoader();
	//new QLabel(loader->loadIcon("apollon", KIcon::MainToolbar));
	new QLabel("<H1>" + i18n("Apollon") + "</H1>", box);

	m_infoBox = new QTextEdit(this);
	m_infoBox->setReadOnly(TRUE);
	m_infoBox->setText(i18n("<h3>Connecting...</h3>"
	                        "<p>The connection is being established, please be patient...</p>"));

	m_timer = new QTimer(this);
}

// destructor
ApollonInfoTab::~ApollonInfoTab()
{
}

// starts the giFT daemon
void ApollonInfoTab::startDaemon()
{
 m_gcn->startgiFT();

	sleep(1); // this is necessary, giFT needs this time

	m_gcn->connectToServer();
}

// tries to connect to a remote gift daemon
void ApollonInfoTab::retryRemoteConnection()
{
	m_gcn->connectToServer();
}

// we've just been connected with the giFT daemon
void ApollonInfoTab::connected()
{
	// update stats and enable stats timer.
	requestStats();

	m_numStatUpdates = 0;
	m_tries = 0;
	m_timer->start(5 * 1000); // 5 seconds

	m_timer->disconnect(this, SLOT(retryRemoteConnection()));
	connect(m_timer, SIGNAL(timeout()), this, SLOT(requestStats()));
}

// we've just been disconnected from the giFT daemon
void ApollonInfoTab::disconnected()
{
	setStatus(i18n("Disconnected."));

	// disable stats timer
	m_timer->stop();

	if(m_gcn->remoteConnection())
	{
		m_infoBox->setText(i18n("<h3>Not connected</h3>") +
		                   i18n("<p>I lost the connection with the giFT daemon, which is responsible for connecting to the"
		                        "  various networks. The daemon needs to be restarted on the host it was running on in order"
		                        "  to be able to connect again.</p>") +
		                   i18n("<p>In the meantime, I'll try to reconnect once a minute to see whether the daemon"
		                        "  becomes available.</p>"));

		m_timer->start(60 * 1000); // 1 minute

		m_timer->disconnect(this, SLOT(requestStats()));
		connect(m_timer, SIGNAL(timeout()), this, SLOT(retryRemoteConnection()));
	}
	else
	{
		m_infoBox->setText(i18n("<h3>Not connected</h3>") +
		                   i18n("<p>A new connection is being established, please be patient...</p>"));

		startDaemon();
	}
}

// requests a stats update from giFT
void ApollonInfoTab::requestStats()
{
	m_gcn->makeStatsRequest();

	if(m_numStatUpdates < 20)
	{
		if(++m_numStatUpdates == 20) // after one minute the interval is changed to ...
		{
			m_timer->changeInterval(60 * 1000); // ... 1 minute
		}
	}
}

// displays new stats in the info box
void ApollonInfoTab::giftStatusReply(QString status)
{
	QString statustext;
	QString networkstatus;
	QString size;
	int pos = 0;
	int tbl_cnt = 0;
	unsigned long totalUsers = 0;
	unsigned long totalFiles = 0;
	unsigned long totalSize = 0;

	KIconLoader *loader = KGlobal::iconLoader();

	QRegExp rx("(\\w+) \\{ (?:users\\(([\\d]+)\\) )?files\\(([\\d]+)\\) size(.*)\\(([\\.\\d]+)\\) \\}");
	rx.setMinimal(true);

	while((pos = rx.search(status, pos)) != -1)
	{
		if(rx.cap(4).isEmpty())
			size = "GB";
		else
			size = rx.cap(4).remove("]").remove("[");

		if(rx.cap(1) == "giFT")
		{
			QMimeSourceFactory::defaultFactory()->setPixmap( "local",  loader->loadIcon("network_local", KIcon::MainToolbar));
			statustext += "<table width=\"100%\" border=\"0\">";
			statustext += "<tr>";
			statustext += "<td><h3><b><img source = \"local\"> &nbsp; " + i18n("Local:") + "</b></h3>";
			statustext += "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">";
		}
		else
		{
			if(tbl_cnt == 0)
				statustext += "<table width=\"100%\" border=\"0\">";

			if(rx.cap(2) != "0")
				networkstatus = i18n("Online");
			else
				networkstatus = i18n("Connecting...");

			if (rx.cap(1) == "OpenFT")
			{
				QMimeSourceFactory::defaultFactory()->setPixmap( "OpenFT",  loader->loadIcon("openft", KIcon::MainToolbar));

				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b><img source = \"OpenFT\"> &nbsp; " + QString(" ") + rx.cap(1) + ":</b></h3>";
			}
			else if (rx.cap(1) == "FastTrack")
			{
				QMimeSourceFactory::defaultFactory()->setPixmap( "FastTrack",  loader->loadIcon("kazaa", KIcon::MainToolbar));
				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b><img source = \"FastTrack\"> &nbsp; " + rx.cap(1) + ":</b></h3>";
			}
			else if (rx.cap(1) == "Gnutella")
			{
				QMimeSourceFactory::defaultFactory()->setPixmap( "Gnutella",  loader->loadIcon("gnutella", KIcon::MainToolbar));
				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b><img source = \"Gnutella\"> &nbsp; " + rx.cap(1) + ":</b></h3>";
			}
			else if (rx.cap(1) == "OpenNap")
			{
				QMimeSourceFactory::defaultFactory()->setPixmap( "OpenNap",  loader->loadIcon("napster", KIcon::MainToolbar));
				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b><img source = \"OpenNap\"> &nbsp; " + rx.cap(1) + ":</b></h3>";
			}
			else if (rx.cap(1) == "SoulSeek")
			{
				QMimeSourceFactory::defaultFactory()->setPixmap( "SoulSeek",  loader->loadIcon("soulseek", KIcon::MainToolbar));
				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b><img source = \"SoulSeek\"> &nbsp; " + rx.cap(1) + ":</b></h3>";
			}
			else if (rx.cap(1) == "Ares")
			{
				QMimeSourceFactory::defaultFactory()->setPixmap( "Ares",  loader->loadIcon("ares", KIcon::MainToolbar));
				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b><img source = \"Ares\"> &nbsp; " + rx.cap(1) + ":</b></h3>";
			}
			else
			{
				if(tbl_cnt % 2 == 0)
					statustext += "<tr>";
				tbl_cnt++;
				statustext += "<td><h3><b>" + rx.cap(1) + ":</b></h3>";
			}

			statustext += "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">";
			statustext += "  <tr><td align=\"right\"><i>" + i18n("Status:") + " </i></td><td><b>" + networkstatus + "</b></td></tr>";
			statustext += "  <tr><td align=\"right\"><i>" + i18n("Users:") + " </i></td><td><b>" + ApollonUtils::numberHuman(rx.cap(2).toULong()) + "</b></td></tr>";

			totalUsers += rx.cap(2).toULong();
			totalFiles += (unsigned long) rx.cap(3).toDouble();
			totalSize += (unsigned long) rx.cap(5).toDouble();
		}
		statustext += "  <tr><td align=\"right\"><i>" + i18n("Files Shared:") + " </i></td><td><b>" + ApollonUtils::numberHuman((unsigned long) rx.cap(3).toDouble()) + "</b></td></tr>";
		statustext += "  <tr><td align=\"right\"><i>" + i18n("Total Size Shared:") + " </i></td><td><b>" + ApollonUtils::numberHuman((unsigned long) rx.cap(5).toDouble()) + " " + size + "</b></td></tr>";
		statustext += "</table></td>";
		if(tbl_cnt % 2 != 0)
			statustext += "</tr>";
		if(rx.cap(1) == "giFT")
			statustext += "</tr></table><br>";

		pos += rx.matchedLength();
	}

	statustext += "</table>";
	m_infoBox->setText(statustext);

	// also update the statusbar
	statustext = i18n("Connected.");
	if(totalUsers)
	{
		statustext += i18n(" %1 users online, sharing %2 files with a total size of %3 GB.").
		              arg(ApollonUtils::numberHuman(totalUsers)).arg(ApollonUtils::numberHuman(totalFiles)).
		              arg(ApollonUtils::numberHuman(totalSize));
	}

	setStatus(statustext);
}

void ApollonInfoTab::socketError(int error)
{
	if(error == 0)
	{
		if(m_gcn->remoteConnection())
		{
			m_infoBox->setText(i18n("<h3>Connection error</h3>") +
			                   i18n("<p>I can't connect to the giFT daemon, which is responsible for connecting to the"
			                        "  various networks, on the remote host.</p>"
			                        "<p>This means the daemon either isn't running or is rejecting our connections"
			                        "  because we're not in the allowed hosts list. If the latter is the case, open the"
			                        "  ~/.giFT/giftd.conf file <i>on the remote host</i> and edit the hosts_allow"
			                        "  variable so that we are an allowed host.</p>") +
			                   i18n("<p>In the meantime, I'll try to reconnect once a minute to see whether the daemon"
			                        "  becomes available.</p>"));

			m_timer->start(60 * 1000); // 1 minute

			m_timer->disconnect(this, SLOT(requestStats()));
			connect(m_timer, SIGNAL(timeout()), this, SLOT(retryRemoteConnection()));
		}
		else
		{
			// connection refused, probably the daemon is down, so let's start it
			if(m_tries < 3)
			{
				m_tries++;
				startDaemon();
			}
			// okay, now I'm giving up
			else
			{
				QString statustext;

				statustext = i18n("<h3>Connection error</h3>") +
				             i18n("<p>The giFT daemon, which is responsible for connecting to the various networks,"
				                  "  appears to be down and I don't seem to able to start it.</p>"
				                  "<p>Probably your giFT installation is corrupted. Try starting giFT manually by"
				                  "  typing \"giftd\" on the command line. If this gives errors, there's likely"
				                  "  some internal error in giFT or in your giFT configuration. Refer to the giFT"
				                  "  homepage at <a href=\"http://giftproject.org\">http://giftproject.org</a>"
				                  "  for help.</p>");
				m_tries = 0;

				m_infoBox->setText(statustext);
			}
		}
	}
	else
	{
		QString statustext;

		statustext = i18n("<h3>Connection error</h3>") +
		             i18n("<p>An unhandled error was returned when trying to open a connection with the giFT"
		                  "  daemon, which is responsible for connecting to the various networks. The reported"
		                  "  error was:</p>"
		                  "<blockquote>"
		                  "  %1 (%2)"
		                  "</blockquote>").arg(strerror(error)).arg(error);

		m_infoBox->setText(statustext);
	}
}

#include "apolloninfotab.moc"

