/*	$Id: gbnclient.c,v 1.16 2005/06/24 04:49:45 jlanawalt Exp $	*/
/*
 * Gnome Batalla Naval
 * Gnome client
 * 
 * (c) 1998-2000 Ricardo Calixto Quesada
 * mailto: 
 *         riq@core-sdi.com
 *
 * surf to:
 * 	http://batnav.sourceforge.net
 *         
 */

/* ---- Includes Generales ---- */
#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 "cliente.h"
#include "proceso.h"
#include "g_interface.h"
#include "pantalla.h"
#include "gbnclient.h"
#include "sendmsg.h"
#include "configure.h"
#include "bnwrite.h"
#include "version.h"
#include "g_connect.h"

/* This describes all the arguments we understand.  */

static char *server_tmp;
static char *nombre_tmp;
static struct poptOption options[] =
{
	{ "port", 'p', POPT_ARG_INT, &usuario.port, 0, N_("Port number. Default is 1995"),NULL},
	{ "server", 's', POPT_ARG_STRING, &server_tmp, 0, N_("Server name. Default is localhost"),"SERVER" },
	{ "player", 'n', POPT_ARG_STRING, &nombre_tmp, 0, N_("Player name. Default is your login name"),"PLAYERNAME"},
#ifdef WITH_GGZ
	{ "ggz", 0, POPT_ARG_NONE, &usuario.with_ggz, 0, N_("Enable GGZ mode"),NULL },
#endif /* WITH_GGZ */
	{ NULL, '\0',  0, NULL }
};


/* Funcion que carga las variables */
/* Function that loads the variables */
static void init_args()
{
	gchar temporal[100];
	sprintf(temporal,"/gbnclient/data/playername=%s",getenv("LOGNAME"));
	strncpy(usuario.nombre,gnome_config_get_string_with_default(temporal,NULL),MAXNAMELEN);

	strncpy( usuario.server,gnome_config_get_string_with_default("/gbnclient/data/servername=localhost",NULL),MAXSERVERNAME);
	
	usuario.port = gnome_config_get_int_with_default("/gbnclient/data/port=1995",NULL);
	usuario.random = gnome_config_get_int_with_default("/gbnclient/data/random=1995",NULL);
	
	gnome_config_set_int   ("/gbnclient/data/port",  usuario.port);
	gnome_config_set_string("/gbnclient/data/servername",usuario.server);
	gnome_config_set_string("/gbnclient/data/playername",usuario.nombre);
	gnome_config_sync();
}

/* Funcion que saca a un usuario */
/* Function that removes a user */
int sacar_usrpage( int jugador )
{
	gint i,j,k;
  
   	j=-1;

	for(i=0;i<MAXPLAYER;i++) {
		if (usuario.pages[i]==jugador) {
			j=i;
			for( k=i; k < (MAXPLAYER-1); k++ )
				usuario.pages[k]=usuario.pages[k+1];
			usuario.pages[MAXPLAYER-1]=-1;
			break;
		}
	}
	return j;
}

/* Funcion que busca un usuario en una page */
/* Function that a user in one looks for page */
int buscar_usr( int usr )
{
	gint i;

	for(i=0;i<MAXPLAYER;i++) {
		if(usuario.pages[i]==usr)
			return i;	
	}
	printf("gbnclient: Error in buscar_usr: usr=%i\n",usr);
	return -1;
}

/* Mini ventanida de help */
/* Quick Help tab */
void bn_help( void )
{
	gtk_text_freeze(GTK_TEXT(text_help));
	gtk_widget_realize(text_help);
	gtk_text_insert( GTK_TEXT(text_help),NULL,NULL,NULL
		,_("Batnav Quick Help -\n"
		"Use this to hide your ships\n"
		"Fill the board with:\n"
		"  4 ships of 1 unit\n"
		"  3 ships of 2 units\n"
		"  2 ships of 3 units\n"
		"  1 ship of 4 units\n"
		"  or press 'Random'\n"
		"Then press 'Send ships' and 'Start'\n"
		"Send bugs,comments, etc to:\n"
		"  riq@core-sdi.com\n"
		) ,-1 );
	
	gtk_text_thaw(GTK_TEXT(text_help));
   
}
/****************************************************************************
 *                     FUNCIONES DE LOS EVENTOS DEL MOUSE
 *                     FUNCTIONS OF THE EVENTS OF THE MOUSE
 ****************************************************************************/

/* Left map (My Board)*/
int expose_event( GtkWidget *widget, GdkEventExpose *event )
{
	gint i,j;
   
	for(i=0;i<10;i++) {
		for(j=0;j<10;j++)
			pmicell( i,j, usuario.mitabla[i][j] );
	}
   

	draw_grid_left();
	return FALSE;
}


/* Seņal PRESS_BUTTON */
/* Signal PRESS_BUTTON on left map (My Board) */
int button_press_event (GtkWidget *widget, GdkEventButton *event)
{
	gint x,y;
   
	x=event->x / ANCHO; /* Wide */
	y=event->y / LARGO; /* Length */
   
	if( usuario.play==BOARD ) {
		textfill(0,_("You've already sent your board to the server. You can't modify it"));
		return TRUE;
	} else if( usuario.play==PLAY || usuario.play==TURN) { 
		/* de esta manero acepto que lo que hayan perdido modifiquen su board */
		/* of this manero acceptance that what there are lost modifies his board */
		textfill(0,_("You can't modify your board while playing"));
		return TRUE;
	}
	if ( event->button == 1 ) { /* Boton izquierdo */
		/* Left button */
		gdk_draw_pixmap( widget->window,
			widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
			barco1,
			0,0,
			x*ANCHO+1,y*LARGO+1,
			ANCHO-1,LARGO-1);
		/* set boat at user.mytable[x][y] */
		usuario.mitabla[x][y]=BARCO;
	} else if ( event->button == 3 ) { /* Boton derecho */
		/* Right button */
		gdk_draw_pixmap( widget->window,
			widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
			fondo,
			x*ANCHO+1,y*LARGO+1,
			x*ANCHO+1,y*LARGO+1,
			ANCHO-1,LARGO-1);				  
		/* clear boat at user.mytable[x][y] */
		usuario.mitabla[x][y]=NOBARCO;
	}		
	return TRUE;
}

/* (Left? Right?) About */
int expose_event_about (GtkWidget *widget, GdkEventExpose *event)
{
	gdk_draw_pixmap( widget->window,
		widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
		about_pix,
		0,0,
		0,0,
		200,200
	);
	return FALSE;
}

/* Right, page switch */
int page_switch( GtkWidget *widget, GtkNotebookPage *page, gint page_num )
{
	if( usuario.play>=PLAY ) {
		usuario.usrfrom = usuario.pages[ page_num ];
		bnwrite(usuario.sock,BN_READ"=%i",usuario.usrfrom);
	}
	return TRUE;
}

/* Right panel */
int expose_event_right( GtkWidget *widget, GdkEventExpose *event )
{
	/* Fill the right (enemy) board */
	fillboard( inteliclient(usuario.tempclit),1);

	draw_grid_right();
	
	return FALSE;
}

int button_press_event_right( GtkWidget *widget, GdkEventButton *event )
{
	int x,y;
   
	x=event->x / ANCHO;
	y=event->y / LARGO;
   
	if(usuario.play < PLAY) {
		textfill(0,_("First try to start the game"));
		return TRUE;
	} else if(usuario.play==PLAY) {
		textfill(0,_("Wait for your turn"));
		return TRUE;
	} else if(usuario.play==PERDIO) {
		textfill(0,_("The game is over for you"));
		return TRUE;
	}
   
	if ( event->button == 1 ) { /* Boton Izquierdo */
		/* Left button */
		usuario.play=PLAY;
		bnwrite(usuario.sock,BN_FIRE"=%i,%i;"BN_READ"=%i",x,y,usuario.usrfrom);
	}
	return TRUE;
}

void remove_page( gint page_num )
{
	gtk_notebook_remove_page( GTK_NOTEBOOK( notebook_right ), page_num );
}

/*************************************************************************
 * 
 *                    CODIGO GENERICO
 *                   ( mentira !!!!! )
 *                    I COSAY GENERICO (?)
 *                    ( lie !!!!!!) (?)
 * 
 *************************************************************************/

/* convierte un char[10][10] a un char[100] */
/* Convert a two dimensional array (char[10][10]) into a on dimensional one */
void iwtable( char *dest)
{
	gint i,x,y;
	x=0;
	y=0;

	for(i=0;i<100;i++) {
		dest[i]=usuario.mitabla[x][y];
		x++;
		if(x>=10) { 
			x=0;
			y++;
		}
	}
}

/* pone por default la misma tabla que jugue antes */
/* it puts by default the same table that jugue before */
void filtermiboard()  
{
	gint x,y;
   
	for(x=0;x<10;x++) {
		for(y=0;y<10;y++) {
			if( usuario.mitabla[x][y] >= BARCO ) 
				usuario.mitabla[x][y]=BARCO;
			else if( usuario.mitabla[x][y] <= NOBARCO ) 
				usuario.mitabla[x][y]=NOBARCO;
		}
	}
}


/*
 * Pone en un temporal datos ( Usados ppalmente por Cli GTK )
 */
/* It puts in a weather (?temporary?) data (Used ppalmente by Cli GTK) */
void putintemp( char *table )
{
	gint i;
	for(i=0;i<100;i++)
		usuario.tempclit[i]=table[i];
}

void showboard( GdkPixmap *pixmap )
{
	int i;
   
	i = gtk_notebook_current_page( GTK_NOTEBOOK( notebook_right ) );
	i = usuario.pages[ i ]; 
   
	gdk_draw_pixmap( drawing_right[i]->window,
		drawing_right[i]->style->fg_gc[GTK_WIDGET_STATE(drawing_right[i])],
		pixmap,
		0,0,
		0,0,
		200,200
	);
}


/* funcion que rellena los tableros
 * function that fills up boards
 * IN: char * - relleno / stuffed
 * IN: int - 0 - left board
 *         - 1 - right board
 */
void fillboard( char *filltable, int a )
{
	gint i,j;
	gint k;
   
	i=0;j=0;
   
	for(k=0;k<100;k++) {
		if(a==0) /* izquierda / left*/
			pmicell( i,j, filltable[k]);
		else 	/* a==1 (derecha / right) */
		{
			ptucell( i,j, filltable[k]);
		}
	
		i++;
		if (i==10) {
			j++;
			i=0;
		}
	}

	if( a==0 )
		draw_grid_left();
	else
		draw_grid_right();
}

/* If the cell is in bounds, apply color to the cell
 * (translating x/y coordinates into the linear table)
 */
void int_cell( char *table, int x, int y, int color )
{
   	if(!(x<0 || x>9 || y<0 || y>9)) 
		table[x+y*10]=color;
}

/* Auto-set AGUA/WATER flag on appropriate squares */
char* inteliclient( char *table)
{
	int i,x,y;
   
	x=0;
	y=0;
   
	for(i=0;i<100;i++) {
		switch(table[i]) {
		case HUNDIDO: /* SUNK */
		case TOCADO:  /* TOUCHED */
			/* Set WATER all around grid square*/
			int_cell(table,x-1,y-1,AGUA);
			int_cell(table,x-1,y+1,AGUA);
			int_cell(table,x+1,y-1,AGUA);							
			int_cell(table,x+1,y+1,AGUA);
			break;
		case NOBARCO: /* NO BOAT */
			/* If the grid squares nearby is in bounds
			 * and SUNK, set it to WATER.
			 * TODO: maybe always use the linear table
			 * and have a translate function so we 
			 * always reference it the same way
			 */
			if(x<9 && table[i+1]==HUNDIDO)
				int_cell(table,x,y,AGUA);
     
			if(x>0 && table[i-1]==HUNDIDO)
				int_cell(table,x,y,AGUA);
     
			if(y<9 && table[i+10]==HUNDIDO)
				int_cell(table,x,y,AGUA);
     
			if(y>0 && table[i-10]==HUNDIDO)
				int_cell(table,x,y,AGUA);
			break;
		default:
			break;
		}
		x++;
		if(x==10) {
			x=0;
			y++;
		}
	}
	return table;
}


/***************************************************************************
                       funciones de los botones
		       functions of the bellboys (?)
***************************************************************************/

int send_start( void )
{
	if(usuario.play==BOARD) {
		bnwrite(usuario.sock,BN_START);
		return 0;
	}
	return -1;
}

int send_board( void )
{
	gchar temptable[101];

	if( usuario.play==CONNEC)  {
		filtermiboard();
		iwtable(temptable);
		temptable[100]=0;/* FIXME: Lo necesito? / I need it? */
		bnwrite(usuario.sock,BN_SEND"=%s",temptable);
		/* Fill the left (player) board */
		fillboard(temptable,0);
		return( TRUE );
 	} else
		return -1;

	return 0;
}

int send_status( )
{
	if( usuario.play<CONNEC)
		return -1;
	bnwrite(usuario.sock,BN_STATUS);
	return 0;
}

int send_robot( void )
{
	if( usuario.play>=CONNEC ) {
		/* 0=dont autostart */
		bnwrite(usuario.sock,BN_ROBOT"=Robot,0");	
		return 0;
	} 
	return(-1);
}

int send_connect()
{

	if( usuario.with_ggz ) {
#ifdef WITH_GGZ
		usuario.sock = ggzmod_connect();
#else
		usuario.sock = -1;
#endif /* ! WITH_GGZ */
	} else {
		usuario.sock = net_connect_tcp( usuario.server, usuario.port );
	}

	if(usuario.sock<0) {
		textfill(0,_("Error: Is the server running?"));
		perror("net_connect_tcp:");

		return -1;
	}
	usuario.tag = gdk_input_add( usuario.sock, GDK_INPUT_READ, (GdkInputFunction) proceso, (gpointer) NULL );
    
	usuario.play=CONNEC;

	if( ! usuario.with_ggz )
		bnwrite(usuario.sock,BN_NUMJUG);
    
	update_sensi();
	return 0;
}

int send_disconnect()
{
	int i;

	if( usuario.play==DISCON )
		return -1;

	textfill(0,_("Press 'Connect' again to join a game"));
	foot_right(_("Press 'Connect' again to join a game"));
	foot_left("Batalla Naval");
	for(i=0;i<MAXPLAYER;i++) {
		usuario.names[i][0]=0;
		usuario.pages[i]=i;
	}
	usuario.play=DISCON;
	gdk_input_remove( usuario.tag );

#if WITH_GGZ
	if( usuario.with_ggz )
		ggzmod_disconnect();
	else
#endif /* WITH_GGZ */
	{
		bnwrite(usuario.sock,BN_EXIT);
		close( usuario.sock );
	}
	
	/* gtk v1.2 no me actualiza este evento. forzarlo */
	/* it does not update east event to me to force it */
	expose_event( drawing_left, NULL );

	update_sensi();
	return 0;
}



/***************************************************************************
		funciones init
***************************************************************************/
void init_datos( void )
{
	gint i,j;

	usuario.play = DISCON;
	usuario.usrfrom=-1;
	usuario.debug_level=0;
	usuario.view_grid=1;

	for(i=0;i<10;i++) {          /* clean tabla */
		for(j=0;j<10;j++)
			usuario.mitabla[i][j]=NOBARCO;
	}

	for(i=0;i<MAXPLAYER;i++) {
		usuario.names[i][0]=0;       /* clear all names */
		usuario.pages[i]=i;
	}
	/*				 123456789012345 */
	usuario.hide=FALSE;
}

/* A little helper function.  */
static char *
nstr (int n)
{
	char buf[20];
	sprintf (buf, "%d", n);
	return strdup (buf);
}

static int
save_state (GnomeClient        *client,
	    gint                phase,
	    GnomeRestartStyle   save_style,
	    gint                shutdown,
	    GnomeInteractStyle  interact_style,
	    gint                fast,
	    gpointer            client_data)
{
	char *argv[20];
	int i = 0, j;
	gint xpos, ypos;

	gdk_window_get_origin (window->window, &xpos, &ypos);

	argv[i++] = (char *) client_data;
	argv[i++] = "-x";
	argv[i++] = nstr (xpos);
	argv[i++] = "-y";
	argv[i++] = nstr (ypos);

	gnome_client_set_restart_command (client, i, argv);
	/* i.e. clone_command = restart_command - '--sm-client-id' */
	gnome_client_set_clone_command (client, 0, NULL);

	for (j = 2; j < i; j += 2)
		free (argv[j]);

	return TRUE;
}

/****************************************************************************
 *                           MAIN * MAIN * MAIN
 ****************************************************************************/

int main (int argc, char *argv[])
{
	GnomeClient *client;
	int r;

	dont_run_as_root();

	bindtextdomain( PACKAGE, GNOMELOCALEDIR );
	textdomain( PACKAGE );
  
	usuario.with_ggz=0;

	init_args();
	
	gnome_init_with_popt_table("gbnclient", BNVERSION, argc, argv, options, 0, NULL);

	if(server_tmp) {
		strncpy(usuario.server,server_tmp,sizeof(usuario.server)-1);
		usuario.server[sizeof(usuario.server)-1]=0;
	}
	if(nombre_tmp) {
		strncpy(usuario.nombre,nombre_tmp,sizeof(usuario.nombre)-1);
		usuario.nombre[sizeof(usuario.nombre)-1]=0;
	}
	
	client = gnome_master_client ();
	
	gtk_signal_connect (GTK_OBJECT (client), "save_yourself",
   		GTK_SIGNAL_FUNC (save_state), argv[0]);

	init_datos();
	init_X();

	update_sensi();
	if( usuario.with_ggz ) {
		if( send_connect() < 0 ) {
			fprintf(stderr,"Only the GGZ client must call gbnclient with `--ggz'\n");
			return -1;
		}
	} else {
		conectar_view();
	}
	
	if( usuario.with_ggz )
		textfill(0,_("Batalla Naval is in GGZ mode"));
   
	gtk_main ();

	return 0;
}

void draw_grid_right()
{
	int i;
	GtkWidget *widget;
	i = gtk_notebook_current_page( GTK_NOTEBOOK( notebook_right ) );
	i = usuario.pages[ i ]; 
	widget = drawing_right[ i ];

	if( ! widget )
		return;

	/* draw the grid */
	if( usuario.view_grid ) {
		for(i=0;i<10;i++) {
			gdk_draw_line (widget->window,
				widget->style->black_gc,
				0,LARGO*i,
				ANCHO*10,LARGO*i);
			gdk_draw_line (widget->window,
				widget->style->black_gc,
				ANCHO*i,0,
				ANCHO*i,LARGO*10);
		}
	}
}

	/* draw the grid */
void draw_grid_left()
{
	int i;
	GtkWidget *widget = drawing_left;

	if( usuario.view_grid ) {
		for(i=0;i<10;i++) {
			gdk_draw_line (widget->window,
				widget->style->black_gc,
				0,LARGO*i,
				ANCHO*10,LARGO*i);
			gdk_draw_line (widget->window,
				widget->style->black_gc,
				ANCHO*i,0,
				ANCHO*i,LARGO*10);
		}
	}
}
   
