/****************************************************************
**
** Attal : Lords of Doom
**
** clientInterface.cpp
** Manages the whole game
**
** Version : $Id: clientInterface.cpp,v 1.26 2004/12/11 13:39:04 lusum Exp $
**
** Author(s) : Pascal Audoux - Sardi Carlo
**
** Date : 17/08/2000
**
** Licence :
**	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, 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.
**
****************************************************************/


#include "clientInterface.h"

// generic include files
#include <unistd.h>
// include files for QT
#include <qaction.h>
#include <qapplication.h>
#include <qcanvas.h>
#include <qkeysequence.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpopupmenu.h>
#include <qpushbutton.h>
#include <qsignalmapper.h>
#include <qstatusbar.h>
// application specific includes
#include "conf.h"
#include "libCommon/attalSocket.h"
#include "libCommon/log.h"
#include "libCommon/skill.h"
#include "libCommon/unit.h"
#include "libCommon/dataTheme.h"

#include "libClient/attalStyle.h"
#include "libClient/building.h"
#include "libClient/gainLevel.h"
#include "libClient/game.h"
#include "libClient/chatWidget.h"
#include "libClient/attalStyle.h"
#include "libClient/displayLord.h"
#include "libClient/displayBase.h"
#include "libClient/gui.h"
#include "libClient/imageTheme.h"

#include "libFight/fight.h"
#include "libFight/fightResult.h"

extern QString DATA_PATH;
extern QString IMAGE_PATH;
extern QString THEME;

extern DataTheme DataTheme;
extern ImageTheme ImageTheme;


ClientInterface::ClientInterface()
{
	_socket = 0;
	_fight = 0;
	_level = 0;
	_base = 0;
	_config = 0;
	_state = SG_MAP;
	_mini = true;
	_tab = true;
	_full = true;
	_help = 0;

	qApp->setStyle( new AttalStyle( DATA_PATH + "style.dat" ) );

	setCaption( tr( "Attal - Lords of Doom" ) );
	initActions();
	initMenuBar();
	initStatusBar();

	if( DataTheme.init() && ImageTheme.init() ) {
		_game = new Game( this );
		setCentralWidget( _game );

		connect( _game, SIGNAL( sig_statusMsg( const QString & ) ), SLOT( slot_status( const QString & ) ) );
		connect( _game, SIGNAL( sig_base( GenericBase * ) ), SLOT( slot_base( GenericBase * ) ) );
		connect( _game, SIGNAL( sig_fight( GenericLord *, CLASS_FIGHTER ) ), SLOT( slot_fight( GenericLord *, CLASS_FIGHTER ) ) );
		connect( _game, SIGNAL( sig_endGame() ), SLOT( slot_endGame() ) );
		connect( _game, SIGNAL( sig_exchange() ), SLOT( slot_exchange() ) );
	} else {
		/// XXX: we could manage this better (later :) )
		QMessageBox::critical( this, tr( "Can't load theme" ), tr( "Theme " ) + THEME + tr( " has not been loaded successfully" ) );
	}
}

ClientInterface::~ClientInterface()
{
	if( _socket ) {
		actionDisconnect(QUIT_GAME);
		delete _socket;
	}
	if( _config ) {
		delete _config;
	}
	
	delete _game;
	
	if( _fight ) {
		delete _fight;
	}
	if( _base ) {
		delete _base;
	}
}

void ClientInterface::closeEvent( QCloseEvent * event )
{
	actionQuit();
	event->accept();
}

void ClientInterface::initActions()
{
	_actions.resize( NB_ACTIONS );
	
	QAction * action;
	QSignalMapper * sigmap = new QSignalMapper( this );

	action = new QAction( tr( "Connect to server" ), tr( "&Connect to server" ), QKeySequence( tr( "CTRL+C" ) ), this );
	_actions.insert( ACTION_CONNECT, action );
	sigmap->setMapping( action, ACTION_CONNECT );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );
	
	action = new QAction( tr( "Fast Server " ), tr( "Fast &Server" ), QKeySequence( tr( "CTRL+S" ) ), this );
	_actions.insert( ACTION_FASTCONNECT, action );
	sigmap->setMapping( action, ACTION_FASTCONNECT );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );

	action = new QAction( tr( "Disconnect" ), tr( "&Disconnect" ), QKeySequence( tr( "CTRL+D" ) ), this );
	action->setEnabled( false );
	_actions.insert( ACTION_DISCONNECT, action );
	sigmap->setMapping( action, ACTION_DISCONNECT );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );

	action = new QAction( tr( "Mini map" ), tr( "&Mini map" ), QKeySequence( tr( "CTRL+M" ) ), this, 0, true );
	action->setOn( true );
	_actions.insert( ACTION_MINIMAP, action );
	sigmap->setMapping( action, ACTION_MINIMAP );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );
	
	action = new QAction( tr( "Tab window" ), tr( "&Tab Window" ), QKeySequence( tr( "CTRL+T" ) ), this, 0, true );
	action->setOn( true );
	_actions.insert( ACTION_TAB, action );
	sigmap->setMapping( action, ACTION_TAB );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );
	
	action = new QAction( tr( "Fullscreen" ), tr( "&Fullscreen" ), QKeySequence( tr( "CTRL+F" ) ), this, 0, true );
	action->setOn( true );
	_actions.insert( ACTION_FULL, action );
	sigmap->setMapping( action, ACTION_FULL );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );
	
	action = new QAction( tr( "Help" ), tr( "&Help" ), QKeySequence( tr( "Key_F1" ) ), this );
	_actions.insert( ACTION_HELP, action );
	sigmap->setMapping( action, ACTION_HELP );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );

	action = new QAction( tr( "Quit" ), tr( "&Quit" ), QKeySequence( tr( "CTRL+Q" ) ), this );
	_actions.insert( ACTION_QUIT, action );
	sigmap->setMapping( action, ACTION_QUIT );
	connect( action, SIGNAL( activated() ), sigmap, SLOT( map() ) );

	connect( sigmap, SIGNAL( mapped( int ) ), SLOT( slot_action( int ) ) );
}

void ClientInterface::initMenuBar()
{
	QPopupMenu * menuFile = new QPopupMenu();
	_actions[ ACTION_CONNECT ]->addTo( menuFile );
	_actions[ ACTION_FASTCONNECT ]->addTo( menuFile );
	_actions[ ACTION_DISCONNECT ]->addTo( menuFile );
	_actions[ ACTION_QUIT ]->addTo( menuFile );

	QPopupMenu * menuGame = new QPopupMenu();
	_actions[ ACTION_MINIMAP ]->addTo( menuGame );
	_actions[ ACTION_TAB ]->addTo( menuGame );
	_actions[ ACTION_FULL ]->addTo( menuGame );
	
	QPopupMenu * menuHelp = new QPopupMenu();
	_actions[ ACTION_HELP ]->addTo( menuHelp );

	menuBar()->insertItem( tr( "&File" ), menuFile );
	menuBar()->insertItem( tr( "&Game" ), menuGame );
	menuBar()->insertItem( tr( "&Help" ), menuHelp );
}

void ClientInterface::slot_action( int num )
{
	switch( num ) {
	case ACTION_CONNECT:
		actionConnect(false);
		break;
	case ACTION_FASTCONNECT:
		actionFastConnect();
		break;
	case ACTION_DISCONNECT:
		actionDisconnect(END_GAME);
		break;
	case ACTION_MINIMAP:
		actionMinimap();
		break;
	case ACTION_TAB:
		actionTab();
		break;
	case ACTION_FULL:
		actionFullScreen();
		break;
	case ACTION_HELP:
		actionHelp();
		break;
	case ACTION_QUIT:
		actionQuit();
		break;
	}
}

void ClientInterface::slot_exchange()
{
	if(_base)
		_base->reinit();
}

void ClientInterface::slot_endGame()
{
	static int count = 0;
	_state = SG_MAP;
	_game->show();
	
	if(_fight){
		_fight->hide();
		delete _fight;
		_fight = 0;
	}
	if(_base){
		_base->hide();
		delete _base;
		_base = 0;
	}
}

void ClientInterface::actionFastConnect()
{
	int pid; 

	if((pid = fork())<0)
		actionQuit();
	if(!pid){
		execl("./attal-server","attal-server", "-fast",NULL);
	}
	sleep(2);
	actionConnect(true);
}

void ClientInterface::actionConnect(bool fast)
{
	if( !_socket ) {
		if( _config == 0 ) {
			_config = new ConfigConnection( this );
		}
		_config->setHost( "localhost" );
		_config->setPort( ATTAL_PORT );
		_config->setPlayerName( _game->getGamePlayer()->getName() );
		if(fast){
			_config->accept();
		} else { 
			_config->exec();
		}
		if( _config->result() == QDialog::Accepted ) {
			_socket = new AttalSocket();
			_game->setSocket( _socket );
			_game->setPlayerName( _config->getPlayerName() );
			_socket->connectToHost( _config->getHost(), _config->getPort() );
			connect( _socket, SIGNAL( readyRead() ), SLOT( slot_readSocket() ) );
			connect( _socket, SIGNAL( hostFound() ), SLOT( slot_hostfound() ) );
			connect( _socket, SIGNAL(connectionClosed()),SLOT(slot_connectionClosed()) );
			connect( _socket, SIGNAL(error(int)),SLOT(slot_error(int)) );
			_actions[ ACTION_CONNECT ]->setEnabled( false );
			_actions[ ACTION_DISCONNECT ]->setEnabled( true );
		}
	} else {
		QMessageBox::critical( this, tr( "Can't connect" ),
			tr( "You're already connected to a server. Please disconnect first." ) );
	}
}

void ClientInterface::slot_hostfound()
{
	if(_game && _game->getChat()){	
		_game->getChat()->newMessage(QString ("Host found , connecting... "));
	}	
}

void ClientInterface::slot_error(int e)
{
	logEE("Cannot connect to server");
	switch (e){
		case QSocket::ErrConnectionRefused: 
			logEE("Connection Refused");
			if(_game && _game->getChat()){	
				_game->getChat()->newMessage(QString ("Connection Refused "));
			}	
			break;
		case QSocket::ErrHostNotFound:
			logEE("Host not found");
			if(_game && _game->getChat()){	
				_game->getChat()->newMessage(QString ("Host not found"));
			}	
			break;
		case QSocket::ErrSocketRead: 
			logEE("Read from the socket failed");
			if(_game && _game->getChat()){	
				_game->getChat()->newMessage(QString ("Read from the socket failed "));
			}	
			break;
	}
	actionDisconnect(QUIT_GAME);
}


void ClientInterface::slot_connectionClosed()
{
	actionDisconnect(QUIT_GAME);
	if(_game && _game->getChat()){	
		_game->getChat()->newMessage(QString ("Server Disconnect "));
	}	
}

void ClientInterface::actionDisconnect(int choice)
{
	if(choice==END_GAME){
		QMessageBox msb( tr( "Match" ), tr( "Do you want abandon the match ?" ), QMessageBox::Warning, QMessageBox::Yes | 			QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, 0, this );
		if( msb.exec() == QMessageBox::Yes){
			choice=QUIT_GAME;
		}
	}
	if(choice==QUIT_GAME) {
		_game->endGame();
		if( _socket ) {
			_game->setSocket( 0 );
			_socket->close();
			delete _socket;
			_socket = 0;
			_actions[ ACTION_CONNECT ]->setEnabled( true );
			_actions[ ACTION_DISCONNECT ]->setEnabled( false );
		}
		slot_map();
		_game->getChat()->newMessage(QString ("Disconnect from server"));
	}
}

void ClientInterface::actionMinimap()
{
	if( _game ) {
		_mini = ! _mini;
		_game->displayMiniMap( _mini );
		_actions[ ACTION_MINIMAP ]->setOn( _mini );
		_actions[ ACTION_TAB ]->setEnabled( _mini );
		_actions[ ACTION_FULL ]->setEnabled( _mini );
	}
}

void ClientInterface::actionTab()
{
	if( _game ) {
		_tab = ! _tab;
		_game->displayTab( _tab );
		_actions[ ACTION_TAB ]->setOn( _tab );
		_actions[ ACTION_MINIMAP ]->setEnabled(_tab );
		_actions[ ACTION_FULL ]->setEnabled( _tab );
	}
}

void ClientInterface::actionFullScreen()
{
	if( _game ) {
		_full = ! _full;
		_game->displayFullScreen( _full );
		_actions[ ACTION_FULL ]->setOn( _full );
		_actions[ ACTION_MINIMAP ]->setEnabled( _full );
		_actions[ ACTION_TAB ]->setEnabled( _full );
	}
}

void ClientInterface::actionHelp()
{
	if( ! _help ) {
		_help = new DisplayHelp( this );
	}
	_help->show();
}


void ClientInterface::actionQuit()
{
	_game->endGame();
	if( _socket ) {
		_game->setSocket( 0 );
		_socket->close();
		delete _socket;
		_socket = 0;
	}
	qApp->quit();
}

void ClientInterface::slot_status( const QString & text )
{
	statusBar()->message( text, 0 );
}

void ClientInterface::initStatusBar()
{
	statusBar()->message( tr( "Status Bar" ), 0 );
}

void ClientInterface::slot_base( GenericBase * base )
{
	_state = SG_BASE;
	if( !_base ) {
		_base = new DisplayBase( this );
		_base->setPlayer( _game->getGamePlayer() );
		_base->setSocket( _socket );
		_base->setGame( _game );
		_base->show();
		connect( _base, SIGNAL( sig_quit() ), SLOT( slot_map() ) );
	} else {
		_base->reinit();
		_base->show();
	}
	menuBar()->hide();
	statusBar()->hide();
	_base->setBase( base );
	setCentralWidget( _base );
	_game->hide();
	ImageTheme.playMusicBase( base->getRace() );
}

void ClientInterface::slot_map()
{
	switch( _state ) {
	case SG_MAP:
		break;
	case SG_FIGHT:
		_fight->hide();
		break;
	case SG_BASE:
		_base->hide();
		break;
	default:
		logEE( "Should not happen" );
		break;
	}
	_state = SG_MAP;
	menuBar()->show();
	statusBar()->show();
	setCentralWidget( _game );
	_game->show();
	ImageTheme.playMusicMap();
}

void ClientInterface::slot_fight( GenericLord * lord, CLASS_FIGHTER cla )
{
	if ( _fight == 0 ) {
		_fight = new Fight( this );
		_fight->setGame( _game );
		_fight->show();
		connect( _fight, SIGNAL( sig_quit() ), SLOT( slot_map() ) );
	} else {
		_fight->reinit();
		_fight->show();
	}
	_state = SG_FIGHT;
	setCentralWidget( _fight );
	_game->hide();
	menuBar()->hide();
	statusBar()->show();
	_fight->setSocket( _socket );
	_fight->setLord( lord, cla );
	ImageTheme.playMusicFight();
}


void ClientInterface::slot_readSocket()
{
	_socket->readData();
	switch( _state ) {
	case SG_MAP:
		_game->handleSocket();
		break;
	case SG_FIGHT:
		_fight->handleSocket();
		break;
	case SG_BASE:
		_base->handleSocket();
		break;
	}

	if( _socket->bytesAvailable() > 0 ) {
		slot_readSocket();
	}
}



//
// ----- ConfigConnection -----
//

ConfigConnection::ConfigConnection( QWidget * parent, const char * name )
	: QDialog( parent, name, true )
{
	setCaption( tr( "Connection to server" ) );
	QVBoxLayout * layout = new QVBoxLayout( this );

	QHBoxLayout * layH1 = new QHBoxLayout();
	layH1->addSpacing( 5 );
	QLabel * labHost = new QLabel( tr( "Host : " ), this );
	FIXEDSIZE( labHost );
	layH1->addWidget( labHost );
	layH1->addSpacing( 5 );
	_host = new QLineEdit( this );
	_host->setFixedSize( 160, 20 );
	layH1->addWidget( _host );
	layH1->addStretch( 1 );
	layout->addLayout( layH1, 1 );

	QHBoxLayout * layH2 = new QHBoxLayout();
	layH2->addSpacing( 5 );
	QLabel * labPort = new QLabel( tr( "Port : " ), this );
	FIXEDSIZE( labPort );
	layH2->addWidget( labPort );
	layH2->addSpacing( 5 );
	_port = new QLineEdit( this );
	_port->setFixedSize( 80, 20 );
	layH2->addWidget( _port );
	layH2->addStretch( 1 );
	layout->addLayout( layH2, 1 );

	QHBoxLayout * layH4 = new QHBoxLayout();
	layH4->addSpacing( 5 );
	QLabel * labName = new QLabel( tr( "Name : " ), this );
	FIXEDSIZE( labName );
	layH4->addWidget( labName );
	layH4->addSpacing( 5 );
	_name = new QLineEdit( this );
	_name->setFixedSize( 80, 20 );
	layH4->addWidget( _name );
	layH4->addStretch( 1 );
	layout->addLayout( layH4, 1 );

	QHBoxLayout * layH3 = new QHBoxLayout();
	QPushButton * pbOk = new QPushButton( this );
	pbOk->setText( tr( "Connect" ) );
	FIXEDSIZE( pbOk );
	layH3->addStretch( 1 );
	layH3->addWidget( pbOk );
	layH3->addStretch( 1 );
	QPushButton * pbCan = new QPushButton( this );
	pbCan->setText( tr( "Cancel" ) );
	FIXEDSIZE( pbCan );
	layH3->addWidget( pbCan );
	layH3->addStretch( 1 );
	layout->addLayout( layH3, 2 );

	layout->activate();

	connect( pbOk, SIGNAL( clicked() ), SLOT( accept() ) );
	connect( pbCan, SIGNAL( clicked() ), SLOT( reject() ) );

	setFixedSize( 250, 150 );
}
