/*	$Id: proceso.c,v 1.10 2002/04/19 04:12:18 riq Exp $	*/
/****************************************************************************
			Funcion que lee el SOCKET
		y a partir de ahi hace lo que debe hacer 
****************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>

#include <config.h>
#include <gnome.h>

#include "protocol.h"
#include "parser.h"
#include "net.h"
#include "gbnclient.h"
#include "cliente.h"
#include "g_interface.h"
#include "pantalla.h"
#include "bnwrite.h"
#include "proceso.h"
#include "version.h"

char *estado[] = {
	N_("Disconnected"),
	N_("Connected"),
	N_("Ready to play"),
	N_("Playing"),
	N_("Playing & Turn"),
	N_("Game Over"),
};

/************************************************************
	funciones auxiliares nada que ver con token
************************************************************/
void poner_proximo_jugador( void )
{
	int i,j;
	i = buscar_usr( usuario.numjug );
	if(i==-1) {
		textfill(1,"Error: poner_proximo_jugador");
		return;
	}
	gtk_notebook_set_page( GTK_NOTEBOOK( notebook_right ),i );
	gtk_notebook_next_page( GTK_NOTEBOOK(notebook_right));
	j = gtk_notebook_current_page( GTK_NOTEBOOK( notebook_right ));
	if(j==i) {
		j=0;
		gtk_notebook_set_page( GTK_NOTEBOOK( notebook_right ),j );
	}
	usuario.usrfrom = usuario.pages[ j ];
}

/*************************************************************
		funciones
		token_*
*************************************************************/

static void token_ggz()
{
	bnwrite(usuario.sock,BN_NUMJUG);
}

static void token_ignore()
{
}
static void token_ser_full()
{
	textfill(0,_("Server is full. Try later"));
	send_disconnect();
}
static void token_sol()
{
	textfill(0,_("You can't play alone. Start a robot"));
}
static void token_wait()
{
	textfill(0,_("People are playing. Try later"));
}
static void token_discon( char *str )
{
	int j,x;
	
	x=atoi(str);

	if(x<0 || x>=MAXPLAYER)
		return;
	
	usuario.names[x][0]=0;
	textfill(0,_("Player %i quit the game"),x);
	
	if( (usuario.play>=BOARD) ){ /* bug fix */
		if(x==usuario.numjug) { /* esto quiere decir que se colgo el server */
			j = g_list_length( GTK_NOTEBOOK(notebook_right)->children);
			for (x = 1; x < j; x++)
				gtk_notebook_remove_page ( GTK_NOTEBOOK( notebook_right), 1);
			for(j=0;j<MAXPLAYER;j++)
				usuario.names[j][0]=0;		/* clear all names */
			textfill(0,_("Ummm... perhaps the server crashed :-("));
		} else {
			if(x==usuario.usrfrom) {
				poner_proximo_jugador();
				if(usuario.usrfrom==usuario.numjug) 
					poner_proximo_jugador();
				bnwrite(usuario.sock,BN_READ"=%i",usuario.usrfrom);
			}
			/**/
			j=sacar_usrpage(x);
			if(j==-1)  {
				textfill(1,"token_discon: sacar_usrpage(%i) error",x);
				return;
			}
			remove_page( j );
		}
	}
}
static void token_lost( char *str )
{
	int j,x;
	
	x=atoi(str);

	if(x<0 || x>=MAXPLAYER)
		return;

	if(x==usuario.numjug) {
		usuario.play=PERDIO;

		textfill(0,_("You LOST the game!"));
		g_box_lost();			/* Esta en g_interface.c */
		return;
	}
	usuario.names[x][0]=0;
	textfill(0,_("Player %i lost the game"),x);
	
	/**/
	if(x==usuario.usrfrom) {
		poner_proximo_jugador();

		if(usuario.usrfrom==usuario.numjug) 
			poner_proximo_jugador();
		bnwrite(usuario.sock,BN_READ"=%i",usuario.usrfrom);
	}
	/**/
	j=sacar_usrpage(x);
	if(j==-1) {
		textfill(1,"token_lost: sacar_usrpage(%i) error",x);
		return;
	}
	remove_page( j );
	return;
}
static void token_game_over()
{
	int i,j;

	usuario.play=CONNEC;			/* Game Over */
	/* gtk v1.2 no me actualiza este evento. forzarlo */
	expose_event( drawing_left, NULL );

	for(i=0;i<MAXPLAYER;i++)
		usuario.names[i][0]=0;		/* clear all names */
	textfill(0,_("Game Over"));
	
	j = g_list_length( GTK_NOTEBOOK(notebook_right)->children);
	for (i = 1; i < j; i++)
		gtk_notebook_remove_page ( GTK_NOTEBOOK( notebook_right), 1);

	update_sensi();

	return;
}
static void token_win(char *str)
{
	int a;

	a=atoi(str);

	if(a<0 || a>=MAXPLAYER)
		return;


	if(a==usuario.numjug) {
		usuario.play=PERDIO;

		textfill(0,_("You are the WINNER"));
		g_box_win();			/* Esta en g_interface.c */
	} else {
		textfill(0,_("Player %s[%i] is the WINNER"),usuario.names[a],a);
	}

	update_sensi();
	return;
}
static void token_read(char *str)
{
	int i,j,l;
	char buf[100];
	PARSER p;
	DELIM igualador={ '=','=','=' };
	DELIM separador={ '/',',','/' };
	
	if(usuario.play<PLAY) {
		textfill(1,_("'%s' Error. I'm not playing"),BN_READ);
		return;
	}

	p.igualador = &igualador;
	p.separador = &separador;
	strncpy(p.sig,str,sizeof(p.sig) );
	j=0;
	do{
		i=parser_init( &p );
		if(p.status && j==0)		/* numero de jugador */
			l=atoi(p.token);

		else if(p.status && j==1)	/* board del jugador */
			strncpy(buf,p.token,10*10);
		j++;
	} while(i);
	if(j!=2) {
		textfill(1,_("Error parsing in '"BN_READ"'"));
		return;
	}
	if(l==-1) {
		textfill(1,_("Reading error"));
		return;
	}
	/* FIXME: Hoy por hoy, no le doy bola al dueño del board */
	putintemp(buf);
	fillboard(inteliclient(buf),1);
}
static void token_fire(char *str)
{
	int i,j,x,y,z;
	PARSER p;
	DELIM igualador={ '=','=','=' };
	DELIM separador={ '/',',','/' };
	
	if(usuario.play<PLAY) {
		textfill(1,_("'%s': I'm not playing"),BN_FIRE);
		return;
	}

	p.igualador = &igualador;
	p.separador = &separador;
	strncpy(p.sig,str,sizeof(p.sig) );
	j=0;
	do{
		i=parser_init( &p );
		if(p.status && j==0)		/* X */
			x=atoi(p.token);

		else if(p.status && j==1)	/* Y */
			y=atoi(p.token);	
	
		else if(p.status && j==2)	/* Tocado, hundio, etc */
			z=atoi(p.token);	
		j++;
	} while(i);
	if(j!=3) {
		textfill(1,_("Error parsing in '"BN_FIRE"'"));
		return;
	}

	if(x<0||x>9 ||y<0||y>9)
		return;

	usuario.mitabla[x][y]=z;
	{
		char buf[100];
		iwtable( buf );
		fillboard( inteliclient( (char*)buf ), 0 );
	}
	bnwrite(usuario.sock,BN_READ"=%i",usuario.usrfrom);
}
static void token_turn(char *str)
{
	char buf[100];

	int j;
	j = atoi( str );
	if(j==usuario.numjug){
		usuario.play=TURN; 
		textfill(1,_("It's my turn"));
		foot_right(_("It's my turn"));
	} else {
		textfill(1,_("It's player %i turn"),j);
		sprintf(buf,_("It's player %i turn"),j);
		foot_right(buf);
	}
}
static void token_ready_to_play( char *str )
{
	int j;
	j = atoi( str );
	textfill(0,_("Player %i is ready to play"),j);
	update_sensi();
}
static void token_status( char *str)
{
	int i,j,k,l;
	PARSER p;
	DELIM igualador={ '=','=','=' };
	DELIM separador={ '/',',','/' };

	p.igualador = &igualador;
	p.separador = &separador;

	strncpy(p.sig,str,sizeof(p.sig) );
	

	j=0;k=0;l=0;
	do{
		i=parser_init( &p );
		if(p.status && j==0)	/* numero de jugador */
			l=atoi(p.token);

		else if(p.status && j==1) /* estado */
			k=atoi(p.token);

		else if(p.status && j==2 ) { /* nombre del jugador */
			strncpy(usuario.names[l],p.token,sizeof(usuario.names[l]));
			textfill(0,_("%i [%s] %s"),l,_(estado[k]),p.token);	       
		}
		j++;
		j=j%3;
	} while(i);
}
static void token_numjug( char *str )
{
	usuario.numjug=atoi(str);
	textfill(0,_("You are player %s[%i]"),usuario.nombre,usuario.numjug);
	bnwrite(usuario.sock,BN_NAME"=%s;"BN_CLI_VER"="BATVER";"BN_SER_VER";"BN_PROTOCOL,usuario.nombre);
	update_sensi();
}
static void token_start_aux( char *str)
{
	int i,j,k,l;
	PARSER p;
	DELIM igualador={ '=','=','=' };
	DELIM separador={ '/',',','/' };

	p.igualador = &igualador;
	p.separador = &separador;

	strncpy(p.sig,str,sizeof(p.sig));
	

	j=0;k=0;l=0;
	do{
		i=parser_init( &p );
		
		if(p.status && j==0) /* number of player */
			l=atoi(p.token);

		else if(p.status && j==1) /* estado */
			k=atoi(p.token);

		else if(p.status && j==2)  { /* nombre del jugador */
			if(k==BOARD) { 
				strncpy(usuario.names[l],p.token, sizeof(usuario.names[l]));
				textfill(0,_("\t%i, %s"),l,p.token);	       
				label_right[l] = gtk_label_new( usuario.names[l] );
				label_right2[l] = gtk_label_new( usuario.names[l] );		       
				drawing_right[l] = gtk_drawing_area_new();
				gtk_drawing_area_size(GTK_DRAWING_AREA(drawing_right[l]),200,200);
				gtk_signal_connect (GTK_OBJECT (drawing_right[l]), "expose_event",
			   		(GtkSignalFunc) expose_event_right, NULL);
				gtk_signal_connect (GTK_OBJECT (drawing_right[l]), "button_press_event",
			   		(GtkSignalFunc) button_press_event_right, NULL);
				gtk_widget_set_events (drawing_right[l], GDK_EXPOSURE_MASK
			      		|GDK_BUTTON_PRESS_MASK);
	
				gtk_widget_show( label_right[l] );
				gtk_widget_show( label_right2[l] );
				gtk_widget_show( drawing_right[l] );
			       	gtk_notebook_append_page_menu ( GTK_NOTEBOOK(notebook_right),
					drawing_right[l],
					label_right[l],
					label_right2[l] );
			} else sacar_usrpage(l);
		}
		j++;
		j=j%3;
	} while(i);
}
static void token_start( char *str)
{
	int i,j;
	if(usuario.play!=BOARD)
		return;

	textfill(0,_("Available players:")); 

	for(i=0;i<MAXPLAYER;i++)
		usuario.pages[i]=i;
	     
	for(i=0;i<100;i++)	/* tempclit es un 'cache' */
		usuario.tempclit[i]=NOBARCO;

	j = g_list_length( GTK_NOTEBOOK(notebook_right)->children);
	for (i = 0; i < j; i++)
		gtk_notebook_remove_page ( GTK_NOTEBOOK( notebook_right), 0);
	
	token_start_aux( str );
	
	usuario.play=PLAY;
	update_sensi();

	foot_left(usuario.names[usuario.numjug]);
	
	/*
	* pone automaticamente al proximo jugador 
	*/
	poner_proximo_jugador();
}

static void token_board_not_ok( void )
{
	textfill(0,_("You sent an invalid board. Try with 'Random Board'"));
}
static void token_board_ok( void )
{
	textfill(0,_("The board's OK. Press 'Start' and enjoy the game"));
	usuario.play=BOARD;
	update_sensi();

	/* gtk v1.2 no me actualiza este evento. forzarlo */
	expose_event( drawing_left, NULL );
}

static void token_message( char *str )
{
	textfill(0,"%s",str);
}

static void token_server_version( char *str)
{
	textfill(0,str);
}

/**********************************************************************
		lookup token, etc
**********************************************************************/
static int lookup_funcion( int fd,PARSER *p )
{
	int i;

	struct {
		char *label;
		void (*func) ();
	} tokens[] = {
		{ BN_BOARD_NOT_OK,	token_board_not_ok },
		{ BN_BOARD_OK,		token_board_ok },
		{ BN_DISCON,		token_discon },
		{ BN_FIRE,		token_fire },
		{ BN_GAME_OVER,		token_game_over },
		{ BN_LOST,		token_lost },
		{ BN_MESSAGE,		token_message },
		{ BN_NAME,		NULL },
		{ BN_NUMJUG,		token_numjug },
		{ BN_PROTOCOL,		NULL },
		{ BN_QUMM,		NULL },
		{ BN_READ,		token_read },
		{ BN_READY_TO_PLAY,	token_ready_to_play },
		{ BN_REM,		token_ignore },
		{ BN_SCORES,		NULL },
		{ BN_SER_FULL,		token_ser_full },
		{ BN_SER_VER,		token_server_version },
		{ BN_SOL,		token_sol },
		{ BN_START,		token_start },
		{ BN_STATUS,		token_status },
		{ BN_TEST,		NULL },
		{ BN_TURN,		token_turn },
		{ BN_WAIT,		token_wait },
		{ BN_WIN,		token_win },
		{ BN_GGZ,		token_ggz }
	};
	int ntokens = sizeof (tokens) / sizeof (tokens[0]);

	for (i = 0; i < ntokens; i++) {
		if (strcmp( p->token, tokens[i].label )==0 ){
			if (tokens[i].func)
				(tokens[i].func)(p->value);
			else {
				textfill(1,_("Function '%s' is not implemented yet!"),tokens[i].label);
			}
			return TRUE;
		}
	}
	return FALSE;
}


int
proceso( gpointer data, int sock, GdkInputCondition GDK_INPUT_READ )
{
	int i,j;
	PARSER p;
	DELIM igualador={ '=', ':', '=' };
	DELIM separador={ ';', ';', ';' };

	char str[PROT_MAX_LEN];

	p.igualador = &igualador;
	p.separador = &separador;
	str[0]=0;

	j=net_readline( sock, str, PROT_MAX_LEN );
	if(j<1) {
		send_disconnect();				
		return -1;
	}
	
	strncpy(p.sig,str,sizeof(p.sig) );
	
	do{
		i=parser_init( &p );
		if(p.status) {
			if( !lookup_funcion( sock,&p ) )
				textfill(1,_("Token '%s' not found"),p.token);
		}
	} while(i);
	return 0;
}
