// Copyright (c) 2002-2004 Rob Kaper <cap@capsi.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation.
//
// 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; see the file COPYING.  If not, write to
// the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
// Boston, MA 02110-1301, USA.

#include <errno.h>

#include <tqcolor.h>
#include <tqdatetime.h>
#include <tqlineedit.h>
#include <tqscrollview.h>
#include <tqpopupmenu.h>

#include <tdeaboutapplication.h>
#include <tdeaction.h>
#include <tdeapplication.h>
#include <tdecmdlineargs.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <knotifyclient.h>
#include <knotifydialog.h>
#include <kstatusbar.h>
#include <kstdgameaction.h>
#include <kstdaction.h>
#include <tdetoolbar.h>

#include <tdeversion.h>
#undef KDE_3_2_FEATURES
#if defined(TDE_MAKE_VERSION)
#if TDE_VERSION >= TDE_MAKE_VERSION(3,2,0)
	#define KDE_3_2_FEATURES
#endif
#endif

#include <kdebug.h>

#include <atlantic_core.h>
#include <auction.h>
#include <estate.h>
#include <player.h>
#include <trade.h>
#include "atlantik.moc"

#include <atlantik_network.h>

#include <board.h>
#include <trade_widget.h>

#include "eventlogwidget.h"
#include "main.h"
#include "selectserver_widget.h"
#include "selectgame_widget.h"
#include "selectconfiguration_widget.h"

LogTextEdit::LogTextEdit( TQWidget *parent, const char *name ) : TQTextEdit( parent, name )
{
#ifdef KDE_3_2_FEATURES
	m_clear = KStdAction::clear( this, TQ_SLOT( clear() ), 0 );
#else
	m_clear = new TDEAction( i18n("Clear"), "clear", NULL, this, TQ_SLOT( clear() ), static_cast<TDEActionCollection *>(0), "clear" );
#endif
	m_selectAll = KStdAction::selectAll( this, TQ_SLOT( selectAll() ), 0 );
	m_copy = KStdAction::copy( this, TQ_SLOT( copy() ), 0 );
}

LogTextEdit::~LogTextEdit()
{
	delete m_clear;
	delete m_selectAll;
	delete m_copy;
}

TQPopupMenu *LogTextEdit::createPopupMenu( const TQPoint & )
{
	TQPopupMenu *rmbMenu = new TQPopupMenu( this );
	m_clear->plug( rmbMenu );
	rmbMenu->insertSeparator();
	m_copy->setEnabled( hasSelectedText() );
	m_copy->plug( rmbMenu );
	m_selectAll->plug( rmbMenu );

	return rmbMenu;
}

Atlantik::Atlantik ()
 :	TDEMainWindow (),
 	m_runningGame( false )
{
	// Read application configuration
	readConfig();

	// Toolbar: Game
//	KStdGameAction::gameNew(this, TQ_SLOT(slotNewGame()), actionCollection(), "game_new");
        m_showEventLog = new TDEAction(i18n("Show Event &Log")/*, "atlantik_showeventlog"*/, CTRL+Key_L, this, TQ_SLOT(showEventLog()), actionCollection(), "showeventlog");
	KStdGameAction::quit(kapp, TQ_SLOT(closeAllWindows()), actionCollection(), "game_quit");

	// Toolbar: Settings
	KStdAction::preferences(this, TQ_SLOT(slotConfigure()), actionCollection());
	KStdAction::configureNotifications(this, TQ_SLOT(configureNotifications()), actionCollection());

	// Initialize pointers to 0L
	m_configDialog = 0;
	m_board = 0;
	m_eventLogWidget = 0;
	m_selectServer = 0;
	m_selectGame = 0;
	m_selectConfiguration = 0;
	m_atlantikNetwork = 0;

	// Game and network core
	m_atlanticCore = new AtlanticCore(this, "atlanticCore");
	connect(m_atlanticCore, TQ_SIGNAL(createGUI(Player *)), this, TQ_SLOT(newPlayer(Player *)));
	connect(m_atlanticCore, TQ_SIGNAL(removeGUI(Player *)), this, TQ_SLOT(removeGUI(Player *)));
	connect(m_atlanticCore, TQ_SIGNAL(createGUI(Trade *)), this, TQ_SLOT(newTrade(Trade *)));
	connect(m_atlanticCore, TQ_SIGNAL(removeGUI(Trade *)), this, TQ_SLOT(removeGUI(Trade *)));

	initEventLog();
	initNetworkObject();

	// Menu,toolbar: Move
	m_roll = KStdGameAction::roll(this, TQ_SIGNAL(rollDice()), actionCollection());
	m_roll->setEnabled(false);
	m_buyEstate = new TDEAction(i18n("&Buy"), "atlantik_buy_estate", CTRL+Key_B, this, TQ_SIGNAL(buyEstate()), actionCollection(), "buy_estate");
	m_buyEstate->setEnabled(false);
	m_auctionEstate = new TDEAction(i18n("&Auction"), "auction", CTRL+Key_A, this, TQ_SIGNAL(auctionEstate()), actionCollection(), "auction");
	m_auctionEstate->setEnabled(false);
	m_endTurn = KStdGameAction::endTurn(this, TQ_SIGNAL(endTurn()), actionCollection());
	m_endTurn->setEnabled(false);
        m_jailCard = new TDEAction(i18n("Use Card to Leave Jail")/*, "atlantik_move_jail_card"*/, 0, this, TQ_SIGNAL(jailCard()), actionCollection(), "move_jailcard");
	m_jailCard->setEnabled(false);
	m_jailPay = new TDEAction(i18n("&Pay to Leave Jail"), "jail_pay", CTRL+Key_P, this, TQ_SIGNAL(jailPay()), actionCollection(), "move_jailpay");
	m_jailPay->setEnabled(false);
        m_jailRoll = new TDEAction(i18n("Roll to Leave &Jail")/*, "atlantik_move_jail_roll"*/, CTRL+Key_J, this, TQ_SIGNAL(jailRoll()), actionCollection(), "move_jailroll");
	m_jailRoll->setEnabled(false);

	// Mix code and XML into GUI
	TDEMainWindow::createGUI();
	applyMainWindowSettings( TDEGlobal::config(), "AtlantikMainWindow" );
	TDEMainWindow::statusBar()->insertItem("Atlantik " ATLANTIK_VERSION_STRING, 0);
	TDEMainWindow::statusBar()->insertItem(TQString(), 1);
	connect(statusBar(), TQ_SIGNAL(released(int)), this, TQ_SLOT(statusBarClick(int)));

	// Main widget, containing all others
 	m_mainWidget = new TQWidget(this, "main");
	m_mainWidget->show();
	m_mainLayout = new TQGridLayout(m_mainWidget, 3, 2);
	setCentralWidget(m_mainWidget);

	// Vertical view area for portfolios.
	m_portfolioScroll = new TQScrollView(m_mainWidget, "pfScroll");
	m_mainLayout->addWidget( m_portfolioScroll, 0, 0 );
	m_portfolioScroll->setHScrollBarMode( TQScrollView::AlwaysOff );
	m_portfolioScroll->setResizePolicy( TQScrollView::AutoOneFit );
	m_portfolioScroll->setFixedHeight( 200 );
	m_portfolioScroll->hide();

	m_portfolioWidget = new TQWidget( m_portfolioScroll->viewport(), "pfWidget" );
	m_portfolioScroll->addChild( m_portfolioWidget );
	m_portfolioWidget->show();

	m_portfolioLayout = new TQVBoxLayout(m_portfolioWidget);
	m_portfolioViews.setAutoDelete(true);

	// Nice label
//	m_portfolioLabel = new TQLabel(i18n("Players"), m_portfolioWidget, "pfLabel");
//	m_portfolioLayout->addWidget(m_portfolioLabel);
//	m_portfolioLabel->show();

	// Text view for chat and status messages from server.
	m_serverMsgs = new LogTextEdit(m_mainWidget, "serverMsgs");
	m_serverMsgs->setTextFormat(TQTextEdit::PlainText);
	m_serverMsgs->setReadOnly(true);
	m_serverMsgs->setHScrollBarMode(TQScrollView::AlwaysOff);
	m_serverMsgs->setMinimumWidth(200);
	m_mainLayout->addWidget(m_serverMsgs, 1, 0);

	// LineEdit to enter commands and chat messages.
	m_input = new TQLineEdit(m_mainWidget, "input");
	m_mainLayout->addWidget(m_input, 2, 0);

	m_serverMsgs->setFocusProxy(m_input);

	connect(m_input, TQ_SIGNAL(returnPressed()), this, TQ_SLOT(slotSendMsg()));

	// Set stretching where we want it.
	m_mainLayout->setRowStretch(1, 1); // make m_board+m_serverMsgs stretch vertically, not the rest
	m_mainLayout->setColStretch(1, 1); // make m_board stretch horizontally, not the rest

	// Check command-line args to see if we need to connect or show Monopigator window
	TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();

	TQCString host = args->getOption("host");
	TQCString port = args->getOption("port");
	if (!host.isNull() && !port.isNull())
		m_atlantikNetwork->serverConnect(host, port.toInt());
	else
		showSelectServer();
}

void Atlantik::readConfig()
{
	// Read configuration settings
	TDEConfig *config = kapp->config();

	// General configuration
	config->setGroup("General");
	m_config.chatTimestamps = config->readBoolEntry("ChatTimeStamps", false);

	// Personalization configuration
	config->setGroup("Personalization");
	m_config.playerName = config->readEntry("PlayerName", "Atlantik");
	m_config.playerImage = config->readEntry("PlayerImage", "cube.png");

	// Board configuration
	config->setGroup("Board");
	m_config.indicateUnowned = config->readBoolEntry("IndicateUnowned", true);
	m_config.highliteUnowned = config->readBoolEntry("HighliteUnowned", false);
	m_config.darkenMortgaged = config->readBoolEntry("DarkenMortgaged", true);
	m_config.animateTokens = config->readBoolEntry("AnimateToken", false);
	m_config.quartzEffects = config->readBoolEntry("QuartzEffects", true);

	// Meta server configuation
	config->setGroup("Monopigator");
	m_config.connectOnStart = config->readBoolEntry("ConnectOnStart", false);
	m_config.hideDevelopmentServers = config->readBoolEntry("HideDevelopmentServers", true);

	// Portfolio colors
	config->setGroup("WM");
	TQColor activeDefault(204, 204, 204), inactiveDefault(153, 153, 153);
	m_config.activeColor = config->readColorEntry("activeBackground", &activeDefault);
	m_config.inactiveColor = config->readColorEntry("inactiveBlend", &inactiveDefault);
}

void Atlantik::newPlayer(Player *player)
{
	initBoard();
	m_board->addToken(player);
	addPortfolioView(player);

	// Player::changed() is not connected until later this method, so
	// we'd better force an update.
	playerChanged(player);

	connect(player, TQ_SIGNAL(changed(Player *)), this, TQ_SLOT(playerChanged(Player *)));
	connect(player, TQ_SIGNAL(gainedTurn()), this, TQ_SLOT(gainedTurn()));
	connect(player, TQ_SIGNAL(changed(Player *)), m_board, TQ_SLOT(playerChanged(Player *)));

	KNotifyClient::event(winId(), "newplayer");
}

void Atlantik::newEstate(Estate *estate)
{
	initBoard();
	m_board->addEstateView(estate, m_config.indicateUnowned, m_config.highliteUnowned, m_config.darkenMortgaged, m_config.quartzEffects);
}

void Atlantik::newTrade(Trade *trade)
{
	TradeDisplay *tradeDisplay = new TradeDisplay(trade, m_atlanticCore, 0, "tradeDisplay");
	m_tradeGUIMap[trade] = tradeDisplay;
	tradeDisplay->show();
}

void Atlantik::newAuction(Auction *auction)
{
	initBoard();
	m_board->addAuctionWidget(auction);
}

void Atlantik::removeGUI(Player *player)
{
	// Find and remove portfolioview
	PortfolioView *portfolioView = findPortfolioView(player);
	if (portfolioView)
		m_portfolioViews.remove(portfolioView);

	if (m_board)
		m_board->removeToken(player);
}

void Atlantik::removeGUI(Trade *trade)
{
	if (TradeDisplay *tradeDisplay = m_tradeGUIMap[trade])
		delete tradeDisplay;
}

void Atlantik::showSelectServer()
{
	if (m_selectServer)
		return;

	m_selectServer = new SelectServer(m_config.connectOnStart, m_config.hideDevelopmentServers, m_mainWidget, "selectServer");
	m_mainLayout->addMultiCellWidget(m_selectServer, 0, 2, 1, 1);
	m_selectServer->show();

	if (m_selectGame)
	{
		delete m_selectGame;
		m_selectGame = 0;
	}

	m_atlanticCore->reset(true);
	initNetworkObject();

	connect(m_selectServer, TQ_SIGNAL(serverConnect(const TQString, int)), m_atlantikNetwork, TQ_SLOT(serverConnect(const TQString, int)));
	connect(m_selectServer, TQ_SIGNAL(msgStatus(const TQString &)), this, TQ_SLOT(slotMsgStatus(const TQString &)));

	m_selectServer->slotRefresh( m_config.connectOnStart );
}

void Atlantik::showSelectGame()
{
	if (m_selectGame)
		return;

	m_selectGame = new SelectGame(m_atlanticCore, m_mainWidget, "selectGame");
	m_atlanticCore->emitGames();

	m_mainLayout->addMultiCellWidget(m_selectGame, 0, 2, 1, 1);
	m_selectGame->show();

	// Reset core and GUI
	if (m_board)
	{
		m_board->hide();
		m_board->reset();
//		delete m_board;
//		m_board = 0;

		// m_portfolioViews.clear();
		m_atlanticCore->reset();
	}

	if (m_selectServer)
	{
		delete m_selectServer;
		m_selectServer = 0;
	}
	if (m_selectConfiguration)
	{
		delete m_selectConfiguration;
		m_selectConfiguration = 0;
	}

	connect(m_selectGame, TQ_SIGNAL(joinGame(int)), m_atlantikNetwork, TQ_SLOT(joinGame(int)));
	connect(m_selectGame, TQ_SIGNAL(newGame(const TQString &)), m_atlantikNetwork, TQ_SLOT(newGame(const TQString &)));
	connect(m_selectGame, TQ_SIGNAL(leaveServer()), this, TQ_SLOT(showSelectServer()));
	connect(m_selectGame, TQ_SIGNAL(msgStatus(const TQString &)), this, TQ_SLOT(slotMsgStatus(const TQString &)));
}

void Atlantik::showSelectConfiguration()
{
	if (m_selectConfiguration)
		return;

	if (m_selectGame)
	{
		delete m_selectGame;
		m_selectGame = 0;
	}

	m_selectConfiguration = new SelectConfiguration(m_atlanticCore, m_mainWidget, "selectConfiguration");
	m_mainLayout->addMultiCellWidget(m_selectConfiguration, 0, 2, 1, 1);
	m_selectConfiguration->show();

	connect(m_atlanticCore, TQ_SIGNAL(createGUI(ConfigOption *)), m_selectConfiguration, TQ_SLOT(addConfigOption(ConfigOption *)));
	connect(m_atlantikNetwork, TQ_SIGNAL(gameOption(TQString, TQString, TQString, TQString, TQString)), m_selectConfiguration, TQ_SLOT(gameOption(TQString, TQString, TQString, TQString, TQString)));
	connect(m_atlantikNetwork, TQ_SIGNAL(gameInit()), m_selectConfiguration, TQ_SLOT(initGame()));
	connect(m_selectConfiguration, TQ_SIGNAL(startGame()), m_atlantikNetwork, TQ_SLOT(startGame()));
	connect(m_selectConfiguration, TQ_SIGNAL(leaveGame()), m_atlantikNetwork, TQ_SLOT(leaveGame()));
	connect(m_selectConfiguration, TQ_SIGNAL(changeOption(int, const TQString &)), m_atlantikNetwork, TQ_SLOT(changeOption(int, const TQString &)));
	connect(m_selectConfiguration, TQ_SIGNAL(buttonCommand(TQString)), m_atlantikNetwork, TQ_SLOT(writeData(TQString)));
	connect(m_selectConfiguration, TQ_SIGNAL(iconSelected(const TQString &)), m_atlantikNetwork, TQ_SLOT(setImage(const TQString &)));
	connect(m_selectConfiguration, TQ_SIGNAL(statusMessage(const TQString &)), this, TQ_SLOT(slotMsgStatus(const TQString &)));
}

void Atlantik::initBoard()
{
	if (m_board)
		return;

	m_board = new AtlantikBoard(m_atlanticCore, 40, AtlantikBoard::Play, m_mainWidget, "board");
	m_board->setViewProperties(m_config.indicateUnowned, m_config.highliteUnowned, m_config.darkenMortgaged, m_config.quartzEffects, m_config.animateTokens);

	connect(m_atlantikNetwork, TQ_SIGNAL(displayDetails(TQString, bool, bool, Estate *)), m_board, TQ_SLOT(insertDetails(TQString, bool, bool, Estate *)));
	connect(m_atlantikNetwork, TQ_SIGNAL(addCommandButton(TQString, TQString, bool)), m_board, TQ_SLOT(displayButton(TQString, TQString, bool)));
	connect(m_atlantikNetwork, TQ_SIGNAL(addCloseButton()), m_board, TQ_SLOT(addCloseButton()));
	connect(m_board, TQ_SIGNAL(tokenConfirmation(Estate *)), m_atlantikNetwork, TQ_SLOT(tokenConfirmation(Estate *)));
	connect(m_board, TQ_SIGNAL(buttonCommand(TQString)), m_atlantikNetwork, TQ_SLOT(writeData(TQString)));
}

void Atlantik::showBoard()
{
	if (m_selectGame)
	{
		delete m_selectGame;
		m_selectGame = 0;
	}

	if (m_selectConfiguration)
	{
		delete m_selectConfiguration;
		m_selectConfiguration = 0;
	}

	if (!m_board)
		initBoard();

	m_runningGame = true;

	m_mainLayout->addMultiCellWidget(m_board, 0, 2, 1, 1);
	m_board->displayDefault();
	m_board->show();

	PortfolioView *portfolioView = 0;
	for (TQPtrListIterator<PortfolioView> it(m_portfolioViews); *it; ++it)
		if ((portfolioView = dynamic_cast<PortfolioView*>(*it)))
			portfolioView->buildPortfolio();
}

void Atlantik::freezeBoard()
{
	if (!m_board)
		showBoard();

	m_runningGame = false;
	// TODO: m_board->freeze();
}

void Atlantik::slotNetworkConnected()
{
}

void Atlantik::slotNetworkError(int errnum)
{
	TQString errMsg(i18n("Error connecting: "));

	switch (m_atlantikNetwork->status())
	{
		case IO_ConnectError:
			if (errnum == ECONNREFUSED)
				errMsg.append(i18n("connection refused by host."));
			else
				errMsg.append(i18n("could not connect to host."));
			break;

		case IO_LookupError:
			errMsg.append(i18n("host not found."));
			break;

		default:
			errMsg.append(i18n("unknown error."));
	}

	serverMsgsAppend(errMsg);

	// Re-init network object
	initNetworkObject();
}

void Atlantik::networkClosed(int status)
{
	switch( status )
	{
	case TDEBufferedIO::involuntary:
		slotMsgStatus( i18n("Connection with server %1:%2 lost.").arg(m_atlantikNetwork->host()).arg(m_atlantikNetwork->port()), TQString("connect_no") );
		showSelectServer();
		break;
	default:
		if ( !m_atlantikNetwork->host().isEmpty() )
			slotMsgStatus( i18n("Disconnected from %1:%2.").arg(m_atlantikNetwork->host()).arg(m_atlantikNetwork->port()), TQString("connect_no") );
		break;
	}
}

void Atlantik::slotConfigure()
{
	if (m_configDialog == 0)
		m_configDialog = new ConfigDialog(this);
	m_configDialog->show();

	connect(m_configDialog, TQ_SIGNAL(okClicked()), this, TQ_SLOT(slotUpdateConfig()));
}

void Atlantik::showEventLog()
{
	if (!m_eventLogWidget)
		m_eventLogWidget = new EventLogWidget(m_eventLog, 0);
	m_eventLogWidget->show();
}

void Atlantik::configureNotifications()
{
	KNotifyDialog::configure(this);
}

void Atlantik::slotUpdateConfig()
{
	TDEConfig *config=kapp->config();
	bool optBool, configChanged = false;
	TQString optStr;

	optBool = m_configDialog->chatTimestamps();
	if (m_config.chatTimestamps != optBool)
	{
		m_config.chatTimestamps = optBool;
		configChanged = true;
	}

	optStr = m_configDialog->playerName();
	if (m_config.playerName != optStr)
	{
		m_config.playerName = optStr;
		m_atlantikNetwork->setName(optStr);
	}

	optStr = m_configDialog->playerImage();
	if (m_config.playerImage != optStr)
	{
		m_config.playerImage = optStr;
		m_atlantikNetwork->setImage(optStr);
	}

	optBool = m_configDialog->indicateUnowned();
	if (m_config.indicateUnowned != optBool)
	{
		m_config.indicateUnowned = optBool;
		configChanged = true;
	}

	optBool = m_configDialog->highliteUnowned();
	if (m_config.highliteUnowned != optBool)
	{
		m_config.highliteUnowned = optBool;
		configChanged = true;
	}

	optBool = m_configDialog->darkenMortgaged();
	if (m_config.darkenMortgaged != optBool)
	{
		m_config.darkenMortgaged = optBool;
		configChanged = true;
	}

	optBool = m_configDialog->animateToken();
	if (m_config.animateTokens != optBool)
	{
		m_config.animateTokens = optBool;
		configChanged = true;
	}

	optBool = m_configDialog->quartzEffects();
	if (m_config.quartzEffects != optBool)
	{
		m_config.quartzEffects = optBool;
		configChanged = true;
	}

	optBool = m_configDialog->connectOnStart();
	if (m_config.connectOnStart != optBool)
	{
		m_config.connectOnStart = optBool;
		configChanged = true;
	}

	optBool = m_configDialog->hideDevelopmentServers();
	if (m_config.hideDevelopmentServers != optBool)
	{
		m_config.hideDevelopmentServers = optBool;
		if (m_selectServer)
			m_selectServer->setHideDevelopmentServers(optBool);

		configChanged = true;
	}

	config->setGroup("General");
	config->writeEntry("ChatTimeStamps", m_config.chatTimestamps);

	config->setGroup("Personalization");
	config->writeEntry("PlayerName", m_config.playerName);
	config->writeEntry("PlayerImage", m_config.playerImage);

	config->setGroup("Board");
	config->writeEntry("IndicateUnowned", m_config.indicateUnowned);
	config->writeEntry("HighliteUnowned", m_config.highliteUnowned);
	config->writeEntry("DarkenMortgaged", m_config.darkenMortgaged);
	config->writeEntry("AnimateToken", m_config.animateTokens);
	config->writeEntry("QuartzEffects", m_config.quartzEffects);

	config->setGroup("Monopigator");
	config->writeEntry("ConnectOnStart", m_config.connectOnStart);
	config->writeEntry("HideDevelopmentServers", m_config.hideDevelopmentServers);

	config->sync();

	if (configChanged && m_board)
		m_board->setViewProperties(m_config.indicateUnowned, m_config.highliteUnowned, m_config.darkenMortgaged, m_config.quartzEffects, m_config.animateTokens);
}

void Atlantik::slotSendMsg()
{
	m_atlantikNetwork->cmdChat(m_input->text());
	m_input->setText(TQString());
}

void Atlantik::slotMsgInfo(TQString msg)
{
	serverMsgsAppend(msg);
}

void Atlantik::slotMsgError(TQString msg)
{
	serverMsgsAppend("Error: " + msg);
}

void Atlantik::slotMsgStatus(const TQString &message, const TQString &icon)
{
	TDEMainWindow::statusBar()->changeItem(message, 1);
	m_eventLog->addEvent(message, icon);
}

void Atlantik::slotMsgChat(TQString player, TQString msg)
{
	if (m_config.chatTimestamps)
	{
		TQTime time = TQTime::currentTime();
		serverMsgsAppend(TQString("[%1] %2: %3").arg(time.toString("hh:mm")).arg(player).arg(msg));
	}
	else
		serverMsgsAppend(player + ": " + msg);
	KNotifyClient::event(winId(), "chat");
}

void Atlantik::serverMsgsAppend(TQString msg)
{
	// Use append, not setText(old+new) because that one doesn't wrap
	m_serverMsgs->append(msg);
	m_serverMsgs->ensureVisible(0, m_serverMsgs->contentsHeight());
}

void Atlantik::playerChanged(Player *player)
{
	PortfolioView *portfolioView = findPortfolioView(player);
	if (!portfolioView)
		portfolioView = addPortfolioView(player);

	Player *playerSelf = m_atlanticCore->playerSelf();
	if (player == playerSelf)
	{
		// We changed ourselves..
		PortfolioView *portfolioView = 0;
		for (TQPtrListIterator<PortfolioView> it(m_portfolioViews); *it; ++it)
			if ((portfolioView = dynamic_cast<PortfolioView*>(*it)))
			{
				// Clear all portfolios if we're not in game
				if ( !player->game() )
					portfolioView->clearPortfolio();

				// Show players in our game, hide the rest
				Player *pTmp = portfolioView->player();
				if (pTmp->game() == playerSelf->game())
					portfolioView->show();
				else
					portfolioView->hide();
			}
		if (!player->game())
			showSelectGame();
		else
		{
			if ( !m_board || m_board->isHidden() )
				showSelectConfiguration();
		}

		m_roll->setEnabled(player->canRoll());
		m_buyEstate->setEnabled(player->canBuy());
		m_auctionEstate->setEnabled(player->canAuction());

		// TODO: Should be more finetuned, but monopd doesn't send can_endturn can_payjail can_jailroll yet
		m_endTurn->setEnabled(player->hasTurn() && !(player->canRoll() || player->canBuy() || player->inJail()));
		m_jailCard->setEnabled(player->canUseCard());
		m_jailPay->setEnabled(player->hasTurn() && player->inJail());
		m_jailRoll->setEnabled(player->hasTurn() && player->inJail());
	}
	else
	{
		// Another player changed, check if we need to show or hide
		// his/her portfolioView.
		if (playerSelf)
		{
			if (player->game() == playerSelf->game())
				portfolioView->show();
			else
				portfolioView->hide();
		}
		else if ( !player->game() )
			portfolioView->hide();
	}
}

void Atlantik::gainedTurn()
{
	KNotifyClient::event(winId(), "gainedturn", i18n("It is your turn now.") );
}

void Atlantik::initEventLog()
{
	m_eventLog = new EventLog();
}

void Atlantik::initNetworkObject()
{
	if (m_atlantikNetwork)
	{
		m_atlantikNetwork->reset();
		return;
	}

	m_atlantikNetwork = new AtlantikNetwork(m_atlanticCore);
	connect(m_atlantikNetwork, TQ_SIGNAL(msgInfo(TQString)), this, TQ_SLOT(slotMsgInfo(TQString)));
	connect(m_atlantikNetwork, TQ_SIGNAL(msgError(TQString)), this, TQ_SLOT(slotMsgError(TQString)));
	connect(m_atlantikNetwork, TQ_SIGNAL(msgStatus(const TQString &, const TQString &)), this, TQ_SLOT(slotMsgStatus(const TQString &, const TQString &)));
	connect(m_atlantikNetwork, TQ_SIGNAL(msgChat(TQString, TQString)), this, TQ_SLOT(slotMsgChat(TQString, TQString)));

	connect(m_atlantikNetwork, TQ_SIGNAL(connectionSuccess()), this, TQ_SLOT(slotNetworkConnected()));
	connect(m_atlantikNetwork, TQ_SIGNAL(connectionFailed(int)), this, TQ_SLOT(slotNetworkError(int)));
	connect(m_atlantikNetwork, TQ_SIGNAL(closed(int)), this, TQ_SLOT(networkClosed(int)));

	connect(m_atlantikNetwork, TQ_SIGNAL(receivedHandshake()), this, TQ_SLOT(sendHandshake()));

	connect(m_atlantikNetwork, TQ_SIGNAL(gameConfig()), this, TQ_SLOT(showSelectConfiguration()));
	connect(m_atlantikNetwork, TQ_SIGNAL(gameInit()), this, TQ_SLOT(initBoard()));
	connect(m_atlantikNetwork, TQ_SIGNAL(gameRun()), this, TQ_SLOT(showBoard()));
	connect(m_atlantikNetwork, TQ_SIGNAL(gameEnd()), this, TQ_SLOT(freezeBoard()));

	connect(m_atlantikNetwork, TQ_SIGNAL(newEstate(Estate *)), this, TQ_SLOT(newEstate(Estate *)));
	connect(m_atlantikNetwork, TQ_SIGNAL(newAuction(Auction *)), this, TQ_SLOT(newAuction(Auction *)));

	connect(m_atlantikNetwork, TQ_SIGNAL(clientCookie(TQString)), this, TQ_SLOT(clientCookie(TQString)));
	connect(m_atlantikNetwork, TQ_SIGNAL(networkEvent(const TQString &, const TQString &)), m_eventLog, TQ_SLOT(addEvent(const TQString &, const TQString &)));

	connect(this, TQ_SIGNAL(rollDice()), m_atlantikNetwork, TQ_SLOT(rollDice()));
	connect(this, TQ_SIGNAL(buyEstate()), m_atlantikNetwork, TQ_SLOT(buyEstate()));
	connect(this, TQ_SIGNAL(auctionEstate()), m_atlantikNetwork, TQ_SLOT(auctionEstate()));
	connect(this, TQ_SIGNAL(endTurn()), m_atlantikNetwork, TQ_SLOT(endTurn()));
	connect(this, TQ_SIGNAL(jailCard()), m_atlantikNetwork, TQ_SLOT(jailCard()));
	connect(this, TQ_SIGNAL(jailPay()), m_atlantikNetwork, TQ_SLOT(jailPay()));
	connect(this, TQ_SIGNAL(jailRoll()), m_atlantikNetwork, TQ_SLOT(jailRoll()));
}

void Atlantik::clientCookie(TQString cookie)
{
	TDEConfig *config = kapp->config();

	if (cookie.isNull())
	{
		if (config->hasGroup("Reconnection"))
			config->deleteGroup("Reconnection", true);
	}
	else if (m_atlantikNetwork)
	{
		config->setGroup("Reconnection");
		config->writeEntry("Host", m_atlantikNetwork->host());
		config->writeEntry("Port", m_atlantikNetwork->port());
		config->writeEntry("Cookie", cookie);
	}
	else
		return;

	config->sync();
}

void Atlantik::sendHandshake()
{
	m_atlantikNetwork->setName(m_config.playerName);
	m_atlantikNetwork->setImage(m_config.playerImage);

	// Check command-line args to see if we need to auto-join
	TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();

	TQCString game = args->getOption("game");
	if (!game.isNull())
		m_atlantikNetwork->joinGame(game.toInt());
}

void Atlantik::statusBarClick(int item)
{
	if ( item == 0 )
	{
		TDEAboutApplication dialog(kapp->aboutData(), this);
		dialog.exec();
	}
	else if ( item == 1)
		showEventLog();
}

PortfolioView *Atlantik::addPortfolioView(Player *player)
{
	PortfolioView *portfolioView = new PortfolioView(m_atlanticCore, player, m_config.activeColor, m_config.inactiveColor, m_portfolioWidget);
	m_portfolioViews.append(portfolioView);
	if ( m_portfolioViews.count() > 0 && m_portfolioScroll->isHidden() )
		m_portfolioScroll->show();

	connect(player, TQ_SIGNAL(changed(Player *)), portfolioView, TQ_SLOT(playerChanged()));
	connect(portfolioView, TQ_SIGNAL(newTrade(Player *)), m_atlantikNetwork, TQ_SLOT(newTrade(Player *)));
	connect(portfolioView, TQ_SIGNAL(kickPlayer(Player *)), m_atlantikNetwork, TQ_SLOT(kickPlayer(Player *)));
	connect(portfolioView, TQ_SIGNAL(estateClicked(Estate *)), m_board, TQ_SLOT(prependEstateDetails(Estate *)));

	m_portfolioLayout->addWidget(portfolioView);
	portfolioView->show();

	return portfolioView;
}

PortfolioView *Atlantik::findPortfolioView(Player *player)
{
	PortfolioView *portfolioView = 0;
	for (TQPtrListIterator<PortfolioView> it(m_portfolioViews); (portfolioView = *it) ; ++it)
		if (player == portfolioView->player())
			return portfolioView;

	return 0;
}

void Atlantik::closeEvent(TQCloseEvent *e)
{
	Game *gameSelf = m_atlanticCore->gameSelf();
	Player *playerSelf = m_atlanticCore->playerSelf();

	int result = KMessageBox::Continue;
	if ( gameSelf && !playerSelf->isBankrupt() && m_runningGame )
		result = KMessageBox::warningContinueCancel( this, i18n("You are currently part of an active game. Are you sure you want to close Atlantik? If you do, you forfeit the game."), i18n("Close & Forfeit?"), i18n("Close && Forfeit") );

	if ( result == KMessageBox::Continue )
	{
		if ( m_atlantikNetwork )
			m_atlantikNetwork->leaveGame();

		saveMainWindowSettings(kapp->config(), "AtlantikMainWindow");
		TDEMainWindow::closeEvent(e);
	}
}
