/*
    This file is part of the TDE games library
    Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
    Copyright (C) 2001 Martin Heni (martin@heni-online.de)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "kgamedebugdialog.h"

#include "kgamemessage.h"
#include "kgame.h"
#include "kplayer.h"
#include "kgamepropertyhandler.h"

#include <tdelistview.h>
#include <tdelistbox.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <kpushbutton.h>
#include <kstdguiitem.h>

#include <tqlayout.h>
#include <tqstring.h>
#include <tqintdict.h>
#include <tqlabel.h>
#include <tqdatetime.h>

#include <typeinfo>


class KGameDebugDialogPrivate
{
public:
	KGameDebugDialogPrivate()
	{
		mGame = 0;

		mGamePage = 0;
		mGameProperties = 0;
		mGameAddress = 0;
		mGameId = 0;
		mGameCookie = 0;
		mGameMaster = 0;
		mGameAdmin = 0;
		mGameOffering = 0;
		mGameStatus = 0;
		mGameRunning = 0;
		mGameMaxPlayers = 0;
		mGameMinPlayers = 0;
		mGamePlayerCount = 0;

		mPlayerPage = 0;
		mPlayerList = 0;
		mPlayerProperties = 0;
		mPlayerAddress = 0;
		mPlayerId = 0;
		mPlayerName = 0;
		mPlayerGroup = 0;
		mPlayerUserId = 0;
		mPlayerMyTurn = 0;
		mPlayerAsyncInput= 0;
		mPlayerKGameAddress = 0;
		mPlayerVirtual = 0;
		mPlayerActive = 0;
		mPlayerRtti = 0;
		mPlayerNetworkPriority = 0;

		mMessagePage = 0;
		mMessageList = 0;
		mHideIdList = 0;
	}

	const KGame* mGame;

	TQFrame* mGamePage;
	TDEListView* mGameProperties;
	TQListViewItem* mGameAddress;
	TQListViewItem* mGameId;
	TQListViewItem* mGameCookie;
	TQListViewItem* mGameMaster;
	TQListViewItem* mGameAdmin;
	TQListViewItem* mGameOffering;
	TQListViewItem* mGameStatus;
	TQListViewItem* mGameRunning;
	TQListViewItem* mGameMaxPlayers;
	TQListViewItem* mGameMinPlayers;
	TQListViewItem* mGamePlayerCount;
	
	TQFrame* mPlayerPage;
	TDEListBox* mPlayerList;
	TDEListView* mPlayerProperties;
	TQListViewItem* mPlayerAddress;
	TQListViewItem* mPlayerId;
	TQListViewItem* mPlayerName;
	TQListViewItem* mPlayerGroup;
	TQListViewItem* mPlayerUserId;
	TQListViewItem* mPlayerMyTurn;
	TQListViewItem* mPlayerAsyncInput;
	TQListViewItem* mPlayerKGameAddress;
	TQListViewItem* mPlayerVirtual;
	TQListViewItem* mPlayerActive;
	TQListViewItem* mPlayerRtti;
	TQListViewItem* mPlayerNetworkPriority;

	TQFrame* mMessagePage;
	TDEListView* mMessageList;
	TDEListBox* mHideIdList;
};

KGameDebugDialog::KGameDebugDialog(KGame* g, TQWidget* parent, bool modal) :
		KDialogBase(Tabbed, i18n("KGame Debug Dialog"), Close, Close, 
		parent, 0, modal, true)
{
 d = new KGameDebugDialogPrivate;

 initGamePage();
 initPlayerPage();
 initMessagePage();

 setKGame(g);
}

KGameDebugDialog::~KGameDebugDialog()
{
 delete d;
}

void KGameDebugDialog::initGamePage()
{
 d->mGamePage = addPage(i18n("Debug &KGame"));
 TQVBoxLayout* topLayout = new TQVBoxLayout(d->mGamePage, marginHint(), spacingHint());
 TQHBoxLayout* layout = new TQHBoxLayout(topLayout);

 TDEListView* v = new TDEListView(d->mGamePage);
 v->addColumn(i18n("Data"));
 v->addColumn(i18n("Value"));
 layout->addWidget(v);

 d->mGameProperties = new TDEListView(d->mGamePage);
 d->mGameProperties->addColumn(i18n("Property"));
 d->mGameProperties->addColumn(i18n("Value"));
 d->mGameProperties->addColumn(i18n("Policy"));
 layout->addWidget(d->mGameProperties);
 
 TQPushButton* b = new TQPushButton(i18n("Update"), d->mGamePage);
 connect(b, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotUpdateGameData()));
 topLayout->addWidget(b);

// game data
 d->mGameAddress = new TQListViewItem(v, i18n("KGame Pointer"));
 d->mGameId = new TQListViewItem(v, i18n("Game ID"));
 d->mGameCookie = new TQListViewItem(v, i18n("Game Cookie"));
 d->mGameMaster = new TQListViewItem(v, i18n("Is Master"));
 d->mGameAdmin = new TQListViewItem(v, i18n("Is Admin"));
 d->mGameOffering = new TQListViewItem(v, i18n("Is Offering Connections"));
 d->mGameStatus = new TQListViewItem(v, i18n("Game Status"));
 d->mGameRunning = new TQListViewItem(v, i18n("Game is Running"));
 d->mGameMaxPlayers = new TQListViewItem(v, i18n("Maximal Players"));
 d->mGameMinPlayers = new TQListViewItem(v, i18n("Minimal Players"));
 d->mGamePlayerCount = new TQListViewItem(v, i18n("Players"));
}

void KGameDebugDialog::initPlayerPage()
{
 d->mPlayerPage = addPage(i18n("Debug &Players"));
 TQVBoxLayout* topLayout = new TQVBoxLayout(d->mPlayerPage, marginHint(), spacingHint());
 TQHBoxLayout* layout = new TQHBoxLayout(topLayout);

 //TODO: connect to the KGame signals for joined/removed players!!!
 TQVBoxLayout* listLayout = new TQVBoxLayout(layout);
 TQLabel* listLabel = new TQLabel(i18n("Available Players"), d->mPlayerPage);
 listLayout->addWidget(listLabel);
 d->mPlayerList = new TDEListBox(d->mPlayerPage);
 connect(d->mPlayerList, TQ_SIGNAL(executed(TQListBoxItem*)), this, TQ_SLOT(slotUpdatePlayerData(TQListBoxItem*)));
 listLayout->addWidget(d->mPlayerList);
 d->mPlayerList->setSizePolicy(TQSizePolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding));

 TDEListView* v = new TDEListView(d->mPlayerPage);
 layout->addWidget(v);
 v->addColumn(i18n("Data"));
 v->addColumn(i18n("Value"));
 
 d->mPlayerProperties = new TDEListView(d->mPlayerPage);
 d->mPlayerProperties->addColumn(i18n("Property"));
 d->mPlayerProperties->addColumn(i18n("Value"));
 d->mPlayerProperties->addColumn(i18n("Policy"));
 layout->addWidget(d->mPlayerProperties);
 
 TQPushButton* b = new TQPushButton(i18n("Update"), d->mPlayerPage);
 connect(b, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotUpdatePlayerList()));
 topLayout->addWidget(b);

 d->mPlayerAddress = new TQListViewItem(v, i18n("Player Pointer"));
 d->mPlayerId = new TQListViewItem(v, i18n("Player ID"));
 d->mPlayerName = new TQListViewItem(v, i18n("Player Name"));
 d->mPlayerGroup = new TQListViewItem(v, i18n("Player Group"));
 d->mPlayerUserId = new TQListViewItem(v, i18n("Player User ID"));
 d->mPlayerMyTurn = new TQListViewItem(v, i18n("My Turn"));
 d->mPlayerAsyncInput = new TQListViewItem(v, i18n("Async Input"));
 d->mPlayerKGameAddress = new TQListViewItem(v, i18n("KGame Address"));
 d->mPlayerVirtual = new TQListViewItem(v, i18n("Player is Virtual"));
 d->mPlayerActive = new TQListViewItem(v, i18n("Player is Active"));
 d->mPlayerRtti = new TQListViewItem(v, i18n("RTTI"));
 d->mPlayerNetworkPriority = new TQListViewItem(v, i18n("Network Priority"));
}

void KGameDebugDialog::initMessagePage()
{
 d->mMessagePage = addPage(i18n("Debug &Messages"));
 TQGridLayout* layout = new TQGridLayout(d->mMessagePage, 11, 7, marginHint(), spacingHint());
 d->mMessageList = new TDEListView(d->mMessagePage);
 layout->addMultiCellWidget(d->mMessageList, 0, 9, 0, 3);
 d->mMessageList->addColumn(i18n("Time"));
 d->mMessageList->addColumn(i18n("ID"));
 d->mMessageList->addColumn(i18n("Receiver"));
 d->mMessageList->addColumn(i18n("Sender"));
 d->mMessageList->addColumn(i18n("ID - Text"));

 TQPushButton* hide = new TQPushButton(i18n("&>>"), d->mMessagePage);
 connect(hide, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotHideId()));
 layout->addWidget(hide, 4, 4);
 
 TQPushButton* show = new TQPushButton(i18n("&<<"), d->mMessagePage);
 connect(show, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotShowId()));
 layout->addWidget(show, 6, 4);

 TQLabel* l = new TQLabel(i18n("Do not show IDs:"), d->mMessagePage);
 layout->addMultiCellWidget(l, 0, 0, 5, 6);
 d->mHideIdList = new TDEListBox(d->mMessagePage);
 layout->addMultiCellWidget(d->mHideIdList, 1, 8, 5, 6);

 TQPushButton* clear = new KPushButton(KStdGuiItem::clear(), d->mMessagePage);
 connect(clear, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotClearMessages()));
 layout->addMultiCellWidget(clear, 10, 10, 0, 6);
 //TODO: "show all but..." and "show nothing but..."
}

void KGameDebugDialog::clearPlayerData()
{
 d->mPlayerAddress->setText(1, "");
 d->mPlayerId->setText(1, "");
 d->mPlayerName->setText(1, "");
 d->mPlayerGroup->setText(1, "");
 d->mPlayerUserId->setText(1, "");
 d->mPlayerMyTurn->setText(1, "");
 d->mPlayerAsyncInput->setText(1, "");
 d->mPlayerKGameAddress->setText(1, "");
 d->mPlayerVirtual->setText(1, "");
 d->mPlayerActive->setText(1, "");
 d->mPlayerRtti->setText(1, "");
 d->mPlayerNetworkPriority->setText(1, "");

 d->mPlayerProperties->clear();
}

void KGameDebugDialog::clearGameData()
{
 d->mGameAddress->setText(1, "");
 d->mGameId->setText(1, "");
 d->mGameCookie->setText(1, "");
 d->mGameMaster->setText(1, "");
 d->mGameAdmin->setText(1, "");
 d->mGameOffering->setText(1, "");
 d->mGameStatus->setText(1, "");
 d->mGameRunning->setText(1, "");
 d->mGameMaxPlayers->setText(1, "");
 d->mGameMinPlayers->setText(1, "");

 d->mGameProperties->clear();
}

void KGameDebugDialog::slotUpdatePlayerData()
{
 if (!d->mGame || d->mPlayerList->currentItem() == -1) {
	return;
 }
 slotUpdatePlayerData(d->mPlayerList->item(d->mPlayerList->currentItem()));
}

void KGameDebugDialog::slotUpdatePlayerList()
{
 TQListBoxItem* i = d->mPlayerList->firstItem(); 
 for (; i; i = d->mPlayerList->firstItem()) {
	removePlayer(i);
 }

 TQPtrList<KPlayer> list = *d->mGame->playerList();
 for (KPlayer* p = list.first(); p; p = list.next()) {
	addPlayer(p);
 }
}

void KGameDebugDialog::slotUpdateGameData()
{
 if (!d->mGame) {
	d->mGameAddress->setText(1, i18n("NULL pointer"));
	return;
}

 clearGameData();

 TQString buf;
 buf.sprintf("%p", d->mGame);
 d->mGameAddress->setText(1, buf);
 d->mGameId->setText(1, TQString::number(d->mGame->gameId()));
 d->mGameCookie->setText(1, TQString::number(d->mGame->cookie()));
 d->mGameMaster->setText(1, d->mGame->isMaster() ? i18n("True") : i18n("False"));
 d->mGameAdmin->setText(1, d->mGame->isAdmin() ? i18n("True") : i18n("False"));
 d->mGameOffering->setText(1, d->mGame->isOfferingConnections() ? i18n("True") : i18n("False"));
 d->mGameStatus->setText(1, TQString::number(d->mGame->gameStatus()));
 d->mGameRunning->setText(1, d->mGame->isRunning() ? i18n("True") : i18n("False"));
 d->mGameMaxPlayers->setText(1, TQString::number(d->mGame->maxPlayers()));
 d->mGameMinPlayers->setText(1, TQString::number(d->mGame->minPlayers()));
 d->mGamePlayerCount->setText(1, TQString::number(d->mGame->playerCount()));

//TODO ios

 KGamePropertyHandler* handler = d->mGame->dataHandler();
 TQIntDictIterator<KGamePropertyBase> it(handler->dict());
 while (it.current()) {
	TQString policy;
	switch (it.current()->policy()) {
		case KGamePropertyBase::PolicyClean:
			policy = i18n("Clean");
			break;
		case KGamePropertyBase::PolicyDirty:
			policy = i18n("Dirty");
			break;
		case KGamePropertyBase::PolicyLocal:
			policy = i18n("Local");
			break;
		case KGamePropertyBase::PolicyUndefined:
		default:
			policy = i18n("Undefined");
			break;
	}
	(void) new TQListViewItem(d->mGameProperties,
			handler->propertyName(it.current()->id()),
			handler->propertyValue(it.current()), 
			policy);
//	kdDebug(11001) << k_funcinfo << ": checking for all game properties: found property name " << name << endl;
	++it;
 }
}

void KGameDebugDialog::slotUpdatePlayerData(TQListBoxItem* item)
{
 if (!item || !d->mGame) {
	return;
 }

 KPlayer* p = d->mGame->findPlayer(item->text().toInt());

 if (!p) {
	kdError(11001) << k_funcinfo << ": cannot find player" << endl;
	return;
 }

 clearPlayerData();

 TQString buf;
 buf.sprintf("%p", p);
 d->mPlayerAddress->setText(1, buf);
 d->mPlayerId->setText(1, TQString::number(p->id()));
 d->mPlayerName->setText(1, p->name());
 d->mPlayerGroup->setText(1, p->group());
 d->mPlayerUserId->setText(1, TQString::number(p->userId()));
 d->mPlayerMyTurn->setText(1, p->myTurn() ? i18n("True") : i18n("False"));
 d->mPlayerAsyncInput->setText(1, p->asyncInput() ? i18n("True") : i18n("False"));
 buf.sprintf("%p", p->game());
 d->mPlayerKGameAddress->setText(1, buf);
 d->mPlayerVirtual->setText(1, p->isVirtual() ? i18n("True") : i18n("False"));
 d->mPlayerActive->setText(1, p->isActive() ? i18n("True") : i18n("False"));
 d->mPlayerRtti->setText(1, TQString::number(p->rtti()));
 d->mPlayerNetworkPriority->setText(1, TQString::number(p->networkPriority()));

//TODO ios

// Properties
 KGamePropertyHandler * handler = p->dataHandler();
 TQIntDictIterator<KGamePropertyBase> it((handler->dict()));
 while (it.current()) {
	TQString policy;
	switch (it.current()->policy()) {
		case KGamePropertyBase::PolicyClean:
			policy = i18n("Clean");
			break;
		case KGamePropertyBase::PolicyDirty:
			policy = i18n("Dirty");
			break;
		case KGamePropertyBase::PolicyLocal:
			policy = i18n("Local");
			break;
		case KGamePropertyBase::PolicyUndefined:
		default:
			policy = i18n("Undefined");
			break;
	}
	(void)new TQListViewItem(d->mPlayerProperties,
			handler->propertyName(it.current()->id()),
			handler->propertyValue(it.current()),
			policy);
	++it;
 }
}

void KGameDebugDialog::clearPages()
{
 clearPlayerData();
 clearGameData();
 d->mPlayerList->clear();
 slotClearMessages();
}

void KGameDebugDialog::setKGame(const KGame* g)
{
 slotUnsetKGame();
 d->mGame = g;
 if (g) {
 //TODO: connect to the KGame signals for joined/removed players!!!
	connect(d->mGame, TQ_SIGNAL(destroyed()), this, TQ_SLOT(slotUnsetKGame()));
//	connect();

	TQPtrList<KPlayer> list = *d->mGame->playerList();
	for (KPlayer* p = list.first(); p; p = list.next()) {
		addPlayer(p);
	}

	slotUpdateGameData();

	connect(d->mGame, TQ_SIGNAL(signalMessageUpdate(int, TQ_UINT32, TQ_UINT32)), this, TQ_SLOT(slotMessageUpdate(int, TQ_UINT32, TQ_UINT32)));
 }
}

void KGameDebugDialog::slotUnsetKGame()
{
 if (d->mGame) {
	disconnect(d->mGame, 0, this, 0);
 }
 d->mGame = 0;
 clearPages();
}

void KGameDebugDialog::addPlayer(KPlayer* p)
{
 if (!p) {
	kdError(11001) << "trying to add NULL player" << endl;
	return;
 }

 (void) new TQListBoxText(d->mPlayerList, TQString::number(p->id()));
 //TODO connect to signals, like deleted/removed, ...
}

void KGameDebugDialog::removePlayer(TQListBoxItem* i)
{
 if (!i || !d->mGame) {
	return;
 }
 KPlayer* p = d->mGame->findPlayer(i->text().toInt());
 if (!p) {
	return;
 }
 disconnect(p, 0, this, 0);
 if (i->isSelected()) {
	clearPlayerData();
 }
 delete i;
}

void KGameDebugDialog::slotMessageUpdate(int msgid, TQ_UINT32 receiver, TQ_UINT32 sender)
{
 if (!showId(msgid)) {
	return;
 }
 TQString msgidText = KGameMessage::messageId2Text(msgid);
 if (msgidText.isNull()) {
	if (msgid > KGameMessage::IdUser) {
		emit signalRequestIdName(msgid-KGameMessage::IdUser, true, msgidText);
	} else {
		emit signalRequestIdName(msgid, false, msgidText);
	}
	if (msgidText.isNull()) {
		msgidText = i18n("Unknown");
	}
 }
 (void) new TQListViewItem( d->mMessageList, TQTime::currentTime().toString(), 
		TQString::number(msgid), TQString::number(receiver), 
		TQString::number(sender), msgidText);
}

void KGameDebugDialog::slotClearMessages()
{
 d->mMessageList->clear();
}

void KGameDebugDialog::slotShowId()
{
/* TQListBoxItem* i = d->mHideIdList->firstItem();
 for (; i; i = i->next()) {
	if (i->selected()) {
		d->mHideIdList->removeItem(i->);
	}
 }*/
 if (!d->mHideIdList->currentItem()) {
	return;
 }
 d->mHideIdList->removeItem(d->mHideIdList->currentItem());
}

void KGameDebugDialog::slotHideId()
{
 if (!d->mMessageList->currentItem()) {
	return;
 }
 int msgid = d->mMessageList->currentItem()->text(1).toInt();
 if (!showId(msgid)) {
	return;
 }
 (void)new TQListBoxText(d->mHideIdList, TQString::number(msgid));
}

bool KGameDebugDialog::showId(int msgid)
{
 TQListBoxItem* i = d->mHideIdList->firstItem();
 for (; i; i = i->next()) {
	if (i->text().toInt() == msgid) {
		return false;
	}
 }
 return true;
}


#include "kgamedebugdialog.moc"
