/*
 * mainServer.cpp
 *
 * Gouverneur Th. - Cuisinier Gi.
 *
 * Main routine&calls for the server of RMP and RMPA
 * protocols.
 * 
 */
#include <sock_server.h>
#include <sock_udp.h>
#include <serverProtocol.h>
#include <rmpaProtocol.h>
#include <command.h>
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <Protocol.h>
#include "libs/mysql.h"
#include "mysqlQuery.h"

using namespace std;

void	thread_client	(void *);
void	thread_rmpa	(void *);

#ifdef TRU64
extern "C" 
{ 
#endif
int 	Arme 		(int, void (*)(int));
void	Handler		(int );
#ifdef TRU64
}
#endif

Sock_Server 	*serv;
Sock_Server 	*serv_admin;

int main(void)
{
	/* signal stuff */
	Arme(SIGINT, Handler);

	/* begining serious things ;) */
	try
	{
		serv = new Sock_Server(ADDRESS_BIND, PORT_CHAMBRE);
		serv->setConnFct(thread_client);
		serv->setMainThreaded(false);
		serv->setBlock(false);

		serv_admin = new Sock_Server(ADDRESS_BIND, PORT_ADMIN);
		serv_admin->setConnFct(thread_rmpa);
		serv_admin->setMainThreaded(false);
		serv_admin->setBlock(false);
		
		/* Init rooms, users & reservations */
		ServerProtocol::getRoomFromSql();
		ServerProtocol::getUserFromSql();
		ServerProtocol::refreshBooks();

		/*
		ServerProtocol::listRoom.Push(new Room("001", "S")); // 001 - Standard
		ServerProtocol::listRoom.Push(new Room("002", "L")); // 002 - Luxe
		ServerProtocol::listRoom.Push(new Room("003", "S")); // 003 - Standard
		ServerProtocol::listRoom.Push(new Room("004", "S")); // 004 - Standard
		ServerProtocol::listRoom.Push(new Room("005", "S")); // 005 - Standard

		ServerProtocol::listUser.Push(new User("wildcat", "pass"));
		ServerProtocol::listUser.Push(new User("hikage", "pass"));
		*/
			
		/* start */
		cout << "Starting main server" << endl;	
		serv->start();
		cout << "Starting Administration server" << endl;
		serv_admin->start();
		while(1) 
		{
			if (ServerProtocol::shutdown > -1)
			{
				if (time(0) > ServerProtocol::shutdown) // should shutdown now...
				{
					/* notify all client on udp port
					 * that the server shutdown
					 */
					Sock_Base::sConn *tmp;
					for (int i = 0; i < serv->getListConn()->Size(); i++)
					{
						tmp = (*(serv->getListConn()))[i];
						std::string ip = tmp->getIp();
						Sock_Udp *sudp = new Sock_Udp(ip, PORT_NOTIFY);

						sudp->startNoBind();
						*sudp << "SHUTDOWN\n";
						sudp->stop();
					}
					
					serv->stop();
					serv_admin->stop();
					ServerProtocol::cleanUpAll();
					delete serv;
					delete serv_admin;
					return 0;
				}
			}
		//	if (!ServerProtocol::suspended)
				serv->evolve();
			serv_admin->evolve();
		}
	}
	catch (Exception e)
	{
		cout << e << endl;
	}
}

void thread_rmpa(void *s)
{
	Sock_Base::sConn *sSock= (Sock_Base::sConn *)s;

	Parser *p = new Parser();
	p->setConn(*sSock);
	p->addCommand(Command("LCLIENTS", (void(*)(void*))RMPAProtocol::cmdLClients, 0)); 
	p->addCommand(Command("SUSPS", (void(*)(void*))RMPAProtocol::cmdSusps, 0)); 
	p->addCommand(Command("STOPS", (void(*)(void*))RMPAProtocol::cmdStops, 0)); 
	
	sSock->readLen = 1000; /* max read len by line */
#ifdef DEBUG
	cout << "Nouveau client RMPA" << endl;
#endif
	while (42)
	{
		try
		{
			string line;
			*sSock >> line;
			p->parseLine(line);
		}
		catch (Sock_Base::exRead e)
		{
			cout << e << endl;
		}
		catch (Sock_Base::exWrite e)
		{
			cout << e << endl;
		}
		catch (Sock_Base::exTimeout e)
		{
#ifdef DEBUG
			cout << "Other side leaved, closing RMPA connection..." << endl;
#endif
			ServerProtocol::cleanClient(sSock);
			delete sSock;
			pthread_exit(0);
			return;
		}
		catch (Exception e)
		{
			cout << e << endl;
		}
	}
}

void thread_client(void *s)
{
	Sock_Base::sConn *sSock= (Sock_Base::sConn *)s;

	Parser *p = new Parser();
	p->setConn(*sSock);
	p->addCommand(Command("LOGIN", (void(*)(void*))ServerProtocol::cmdLogin, 2)); /* args: nom, password */
	p->addCommand(Command("BROOM", (void(*)(void*))ServerProtocol::cmdBRoom, 5)); /* args: type de chambre, date arrivee, nombre de nuit, nom client */
	p->addCommand(Command("CROOM", (void(*)(void*))ServerProtocol::cmdCRoom, 2)); /* args: num chambre, nom client */
	p->addCommand(Command("LROOMS", (void(*)(void*))ServerProtocol::cmdLRooms, 0)); /* args: -- */
	
	sSock->readLen = 1000; /* max read len by line */
#ifdef DEBUG
	cout << "Nouveau client" << endl;
#endif
	while (42)
	{
		try
		{
		//	if (!ServerProtocol::suspended)
		//	{
				string line;
				*sSock >> line;
#ifdef DEBUG
				cout << "Ligne recue: " << line << "-" << endl;
#endif
		//		while (ServerProtocol::suspended) sleep(2); // if we were blocked in an I/O, now we wait here BEFORE parsing data received.
			if (!ServerProtocol::suspended)
				p->parseLine(line);
			else
				ServerProtocol::sendSusp(sSock); // tell client we are suspended..

		//	} else sleep(1); // we do NOT want to use all the CPU :)
		}
		catch (Sock_Base::exRead e)
		{
			cout << e << endl;
		}
		catch (Sock_Base::exWrite e)
		{
			cout << e << endl;
		}
		catch (Sock_Base::exTimeout e)
		{
			cout << "Other side leaved, closing connection..." << endl;
			ServerProtocol::cleanClient(sSock);
			delete sSock;
			pthread_exit(0);
			return;
		}
		catch (Exception e)
		{
			cout << e << endl;
		}
	}
}

#ifdef TRU64
extern "C"
{
#endif
int Arme 		(int s, void (*f)(int))
{
	struct sigaction a;
	a.sa_flags = 0;
	a.sa_handler = f;

	return sigaction(s, &a, NULL);
}

void	Handler		(int s)
{
	serv->stop();
	exit(0);
}

#ifdef TRU64
}
#endif

