/*  load.l

    Copyright (C) 1994	Lambert Klasen & Detlef Steuer
			klasen@asterix.uni-muenster.de
			steuer@amadeus.statistik.uni-dortmund.de

    This file is free source code; you can redistribute it and/or modify
    it under the terms of the GNU General Public License 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
    COPYING for more details.
 */



%{
#include <stdlib.h>
#include <unistd.h>
#include <X11/Intrinsic.h>
#include <X11/Xaw/Label.h>
#include "xgammon.h"
#include "gammon.h"

/* for some irix */
#ifdef irix
#define usleep(a) sleep((a/10))
#endif

char	kind;
char 	*player[2];
int	games_replayed;

static float fval, *inarray;
static int   count = 0, endarray;
static int   found_black, found_white;
static int   have_tournament = 0;
static int   wraped = 0;

void replay_init_game ();
void print_move (MOVE *m);

extern float point_values[], prime_length_factor[];
extern int   replaying;
extern unsigned long   delaytime;
extern FILE  * protokol_file;


extern void ShowCompiMove     ();
extern void DrawEmptyBoard    ();
extern void DrawBoard         ();
extern void RedrawAllStones   ();
extern void RemoveStone       ();
extern void DrawDice          ();
extern void DrawDoubler       ();
extern void open_protokol     ();

%}

%s LOAD
%s LOAD_CONFIG
%s REPLAY
%s GETMOVE
%s FIBSLOAD

%%
<REPLAY>.*" and ".*" start a "[0-9]+" point match."\n {
		char *r = yytext;
		int i = 1;

		while (*(r+i) != ' ') i++;
		player[0] = malloc (i+1);
		strncpy (player[0], r, i);

		r = strstr (yytext, " and ") + 5;

		i = 1;
		while (*(r+i) != ' ') i++;
		player[1] = malloc (i+1);
		strncpy (player[1], r, i);

		r = r + i + 9;
		tournament.winning_point = atoi (r);

#ifdef DEBUG_REPLAY
			fprintf (stderr, "player: %s %s\n", player[0], player[1]);
			fprintf (stderr, "winning_point: %d\n", tournament.winning_point);
#endif

		AppendDialogText (LOWER, yytext);
	}

<REPLAY>[A-Za-z0-9]*" rolls "[1-6]" and "[1-6]"."\n	{
		AppendDialogText (LOWER, yytext); 

		roll[0] = *(yytext+yyleng-9) - '0';
		roll[1] = *(yytext+yyleng-3) - '0';

		if      (strncmp (player[1], yytext, strlen (player[1])) == 0) turn = BLACK; 
		else if (strncmp (player[0], yytext, strlen (player[0])) == 0) turn = WHITE;

#ifdef DEBUG_REPLAY
		fprintf (stderr,"roll %c %c turn %d\n", *(yytext+yyleng-9), *(yytext+yyleng-3), turn); 
#endif

		DrawDice (turn);

		XSync (Player[0].X11Set.dpy, 0);

		while(1) {
			XEvent event;
			XtAppNextEvent(app_con, &event);
			if      (event.type == ButtonRelease && event.xbutton.window == Player[0].X11Set.board.window) {
				XtDispatchEvent (&event);
				break;
			}
			else if (event.type == KeyRelease && event.xkey.window == Player[0].X11Set.board.window) {
				break;
			}
			XtDispatchEvent(&event);
		}
	}

<REPLAY>[A-Za-z0-9]*" rolled "[1-6]", "[A-Za-z0-9]*" rolled "[1-6]\n[a-zA-Z0-9]*" makes the first move."\n { 
			char *r = yytext;
			count = 0;
			AppendDialogText (LOWER, yytext);
			while (*r != ',') r++;
			roll[0] = *(r-1) - '0';
			while (*r != '\n') r++;
			roll[1] = *(r-1) - '0';

#ifdef DEBUG_REPLAY
			fprintf (stderr, "initial roll %s", yytext );
			fprintf (stderr, "roll %d %d\n", roll[0], roll[1]);
#endif
			if (games_replayed%2 == 0) {
				char *p;
				p = player[0];
				player[0] = player[1];
				player[1] = p;
			}
			games_replayed++;
			if (strncmp ((r+1), player[0], strlen (player[0])) == 0)
				turn = BLACK;
			else	turn = WHITE;
#ifdef DEBUG_REPLAY
			fprintf (stderr ,"turn %d\n", turn);
#endif
			replay_init_game ();
		}

<REPLAY>[a-zA-Z0-9]*" doubles."\n	{
			if      (strncmp (player[0], yytext, strlen(player[0])) == 0) {
				doubler.owner = BLACK;
			}
			else if (strncmp (player[1], yytext, strlen(player[1])) == 0) {
				doubler.owner = WHITE;
			}

			AppendDialogText (LOWER, yytext);

			XSync (Player[0].X11Set.dpy, 0);

			while(1) {
				XEvent event;
				XtAppNextEvent(app_con, &event);
				if      (event.type == ButtonRelease && event.xbutton.window == Player[0].X11Set.board.window) {
					XtDispatchEvent(&event);
					break;
				}
				else if (event.type == KeyRelease && event.xkey.window == Player[0].X11Set.board.window) {
					break;
				}
				XtDispatchEvent(&event);
			}
		}

<REPLAY>[a-zA-Z0-9]*" accepts the double."\n	{
			if (strncmp (player[0], yytext, strlen(player[0])) == 0 ||
			    strncmp (player[1], yytext, strlen(player[1])) == 0) {
				doubler.value *= 2;
				DrawDoubler (doubler.value, doubler.owner);
#ifdef DEBUG_REPLAY
				fprintf (stderr,"doubling accepted\n");
#endif
			}
			AppendDialogText (LOWER, yytext);
		}

<REPLAY>"gives up."	{
			AppendDialogText (LOWER, yytext); 
#ifdef DEBUG_REPLAY
			fprintf (stderr,"doubling resign\n");
#endif
			}

<REPLAY>[a-zA-Z0-9]*" moves "	{
			if      (strncmp (player[0], yytext, strlen(player[0]) - 1) == 0) BEGIN GETMOVE;
			else if (strncmp (player[1], yytext, strlen(player[1]) - 1) == 0) BEGIN GETMOVE;

			AppendDialogText (LOWER, yytext);

			count = 0;
#ifdef DEBUG_REPLAY
			fprintf (stderr,"switching to getmove\n");
#endif
		}

<REPLAY>[a-zA-Z0-9]*" can't move."		{
			AppendDialogText (LOWER, yytext);
			if (turn == BLACK) turn = WHITE;
			else turn = BLACK;
		}

<GETMOVE>([1-9]|1[0-9]|2[0-4])"-"([1-9]|1[0-9]|2[0-4]) {
			char *to = yytext;
			int f, t;
			AppendDialogText (LOWER, yytext);
			f = atoi (yytext);
			turn = Pin[f].color;
			while (*to != '-') to++; to++;
			t = atoi (to);
#ifdef DEBUG_REPLAY
			fprintf (stderr,"from %d to %d\n", f, t);
#endif
			RemoveStone  (f);
			if (Pin[t].count == 1 && Pin[t].color != turn) {
				PutStone (Pin[t].color, (turn == BLACK) ? WHITE_BAR : BLACK_BAR);
				RemoveStone  (t);
			}
			PutStone (turn, t);
			XSync    (Player[0].X11Set.dpy, 0);
			usleep   (delaytime);
		}
<GETMOVE>"bar-"([1-9]|1[0-9]|2[0-4]) {
			int f, t, f_color;
			AppendDialogText (LOWER, yytext);
			t = atoi ((yytext+4));
			if (t < 7) {
				f_color = BLACK;
				f       = BLACK_BAR;
				turn    = BLACK; /* for RemoveStone () */
			}
			else {
				f_color = WHITE;
				f       = WHITE_BAR;
				turn    = WHITE;
			}
#ifdef DEBUG_REPLAY
			fprintf (stderr,"from (bar) %d to %d\n", f, t);
#endif
			RemoveStone  (f);
			if (Pin[t].count == 1 && Pin[t].color != f_color) {
				PutStone (Pin[t].color, (f_color == BLACK) ? WHITE_BAR : BLACK_BAR);
				RemoveStone  (t);
			}
			PutStone (f_color, t);
			XSync    (Player[0].X11Set.dpy, 0);
			usleep    (delaytime);
		}

<GETMOVE>([1-9]|1[0-9]|2[0-4])"-off" {
			int f, t;
			AppendDialogText (LOWER, yytext);
			f = atoi (yytext);
			if (Pin[f].color == BLACK) {
				t = 25+BLACK;
				turn = BLACK;
			}
			else {
				t = 25+WHITE;
				turn = WHITE;
			}
#ifdef DEBUG_REPLAY
			fprintf (stderr, "from %d to %d (off)\n", f, t);
#endif
			RemoveStone  (f);
			PutStone    (turn, t);
			XSync        (Player[0].X11Set.dpy, 0);
			usleep       (delaytime);
		}

<REPLAY>[a-zA-Z0-9]*	{ AppendDialogText (LOWER, yytext); }
<GETMOVE>[a-zA-Z0-9]*	{ AppendDialogText (LOWER, yytext); }
<GETMOVE>.		{ AppendDialogText (LOWER, yytext); }
<REPLAY>.		{ AppendDialogText (LOWER, yytext); }

<REPLAY>\n		{ AppendDialogText (LOWER, "\n"); }
<GETMOVE>\n	{
			AppendDialogText (LOWER, "\n"); 
			BEGIN REPLAY; 
		}

<LOAD>"turn: "(black|white) {
		if (strncmp( yytext+6, "black", 5) == 0) {
			turn  = BLACK;
			other = WHITE;
			direction = 1;
			start_pin = 0;
			end_pin = 25;
			Player[0].beginner_of_game = 1;
			Player[1].beginner_of_game = 0;
		}
		if (strncmp( yytext+6, "white", 5) == 0) {
			turn = WHITE; 
		        other = BLACK;
		        direction = -1;
		        start_pin = 25;
		        end_pin = 0;
			Player[1].beginner_of_game = 1;
			Player[0].beginner_of_game = 0;
		}
	}

<LOAD>"dice values: "[1-6]" "[1-6] {
		roll[0] = *(yytext+13) - '0';
		roll[1] = *(yytext+15) - '0';

		roll[0] *= direction;
		roll[1] *= direction;

		if (roll[0] == roll[1]) { 
		        roll[3] = roll[0]; 
		        roll[2] = roll[1]; 
		        to_move = 4;
		        pash = 1;
	        }
		else {
		        roll[2] = roll[3] = 0;
		        pash = 0;
		        to_move = 2;
	        }
	}

<LOAD>"doubler value: "(1|2|4|8|16|32|64)	{
				doubler.value = atoi((yytext+15));
				}
<LOAD>"last doubler: "(none|black|white)	{ 
				if      (*(yytext+14) == 'b') doubler.owner = BLACK;
				else if (*(yytext+14) == 'w') doubler.owner = WHITE;
				else doubler.owner = 0;
			}

<LOAD>"on bar: "(black|white)": "[0-9]+", "(black|white)": "[0-9]+\n {
		char *r = yytext+8;

		r = strstr (yytext, "black: ") + strlen ("black: ");
		if ((Pin[0].count = atoi(r))) Pin[0].color = BLACK;

		r = strstr (yytext, "white: ") + strlen ("white: ");
		if ((Pin[25].count = atoi(r))) Pin[25].color = WHITE;

		found_black += Pin[0].count;
		found_white += Pin[25].count;
	}

<LOAD>"pin "[0-9]+": "[0-9]+" "(black|white)	{
		int  p, m;
		char *r = yytext+4;

		p = atoi(r);

		while (*r != ' ') r++; r++;

		m = atoi (r);

		while (*r != ' ') r++; r++;

		if      (strncmp(r, "black", 5) == 0) {
			Pin[p].color = BLACK;
			found_black += m;
		}
		else if (strncmp(r, "white", 5) == 0) {
			Pin[p].color = WHITE;
			found_white += m;
		}

		Pin[p].count = m;
	}

<LOAD>("money-game"|"best of "[0-9]+|[0-9]+" points")" match between "[a-zA-Z0-9]*" and "[a-zA-Z0-9]*":"\n {
		int i = 1;
		char *r = strstr(yytext, "between") + 8;

		if (kind == 'g') {
			while (*(r+i) != ' ') i++;
			strncpy (Player[0].name, r, i-1);
			*(Player[0].name+i) = '\0';
			r = r+i+5;
			i=1; 
			while (*(r+i) != ':') i++;
			strncpy (Player[1].name, r, i);
			*(Player[0].name+i) = '\0';

			have_tournament = 1;

			if (strncmp (yytext, "money-game", 10) == 0) {
				sprintf (add_text, "%s and %s play a money-game match", Player[0].name, Player[1].name);
				tournament.winning_point = 0; 
				gammon_resource.moneygame = 1;
			} else {
				sprintf (add_text, "%s and %s play a %d points match", Player[0].name, Player[1].name, tournament.winning_point);
				gammon_resource.moneygame = 0;
				gammon_resource.winat = tournament.winning_point = atoi(yytext); 
			}
			AppendDialogText (UPPER, add_text);
		}
	}

<LOAD>[a-zA-Z0-9]*" has "[0-9]+"points, "[a-zA-Z0-9]*" has "[0-9]+"points."\n {
		char *r = strstr (yytext, "has") + 4, *p;
		if (strncmp (yytext, Player[0].name, strlen(Player[0].name)) == 0)
			Player[0].points = atoi(yytext);
		else if (strncmp (yytext, Player[1].name, strlen(Player[1].name)) == 0)
			Player[1].points = atoi(yytext);

		while (*r != ',') r++; r+=2;
		if (strncmp (r, Player[0].name, strlen(Player[0].name)) == 0) {
			p = strstr(r, "has") + 4;
			Player[0].points = atoi(p);
		}
		else if (strncmp (r, Player[1].name, strlen(Player[1].name)) == 0) {
			p = strstr(r, "has") + 4;
			Player[1].points = atoi(p);
		}
		sprintf (add_text, "%s points: %d, %s points: %d", Player[1].name, Player[1].points, Player[0].name, Player[0].points);
		AppendDialogText (UPPER, add_text);
	}

<LOAD_CONFIG>"point values:" {
		count = 0;
		endarray = 24;
		inarray = (point_values+1);
	}

<LOAD_CONFIG>"prime length factors:" {
		if (count < 24) {
			fprintf (stderr, "incomplete array: point_values\n");
		}
		count = 0;
		endarray = 8;
		inarray = prime_length_factor;
	}

<LOAD_CONFIG>[0-9]*"."[0-9]* {
		fval = atof (yytext);
		if ((count ++) >= endarray) {
			fprintf (stderr, "too many float values for array %s\n", (endarray == 24) ? "point_values" : "prine_length_factor");
		}
		else {
			*(inarray++) = fval;
		}
	}

.       ;
\n      ;
%%

void load (Widget w, XEvent *e, String *vector, Cardinal *count)
{
	FILE *f;
	char * filename = "xgammon.save";
	int i;

	if      (*vector[0] == 'p') kind = 'p';		/* position */
	else if (*vector[0] == 'g') kind = 'g';		/* game */
	else if (*vector[0] == 'r') kind = 'r';		/* replay */
	else if (*vector[0] == 'm') {			/* menu */
		if (replaying)	kind = 'r';
		else		kind = 'g';
		filename = vector[1];
	}

	f = fopen (filename,"r");

	if (!f) {
        	AppendDialogText (LOWER, "Couldn't open save file for reading, sorry!\n");
        	return;
        }

	for (i=0; i<29; i++) { Pin[i].color = 0; Pin[i].count = 0; }
	found_black = found_white = 0;

	if (!wraped) { yyin = f; wraped = 1; }
	else	     { yyin = f; YY_NEW_FILE; }

	count = 0;
	have_tournament = 0;

	if (kind != 'r') BEGIN LOAD;
	else {
		BEGIN REPLAY;
		games_replayed = 0;
	}

	Player[0].points = Player[1].points = 0;

	if (!gammon_resource.rollout) {
		AppendDialogText (LOWER, "\ngame aborted\n");
	}
	if (kind != 'r') 
		AppendDialogText (LOWER, "\ntournament restart\nloading position\n\n");

	yylex();

	fclose (f);

	if (!replaying) {
		if (found_white<15) Pin[25+WHITE].count = 15 - found_white;
		if (found_black<15) Pin[25+BLACK].count = 15 - found_black;

		if (turn == BLACK) {
			Player[0].beginner_of_game = 1;
			Player[1].beginner_of_game = 0;
		} else {
			Player[0].beginner_of_game = 0;
			Player[1].beginner_of_game = 1;
		}
	} else {
		end_of_game = 1;
		end_of_tournament = 1;
		break_loop = REPLAY_GAME;
		initialize = REPLAY_GAME;
		replaying = 0;
		return;
	}

	if (!gammon_resource.rollout) {
		DrawEmptyBoard  ();
		DrawBoard       ();
		RedrawAllStones ();
		DrawDice        (turn);
		DrawDoubler     (doubler.value, doubler.owner);

		sprintf (add_text, "%s rolls %d and %d.\n", Player[turn-1].name, roll[0], roll[1]);

		AppendDialogText (LOWER, add_text);

		break_loop = initialize = LOADED_POSITION;
		end_of_game = 1;
	}
}

void print_move (MOVE *m)
{
	int i;

	for (i=0; i<4; i++) fprintf (stderr,"%d %d\t", (m+i)->from, (m+i)->to);

	fprintf (stderr,"\n");
}

void replay_init_game (void)
{
	int i;

	DrawEmptyBoard ();
	DrawBoard      ();
	for (i=0; i<29; i++) { Pin[i].count=0; Pin[i].color=0; }

	Pin[ 1].color = BLACK; Pin[ 1].count = 2;
	Pin[12].color = BLACK; Pin[12].count = 5;
	Pin[17].color = BLACK; Pin[17].count = 3;
	Pin[19].color = BLACK; Pin[19].count = 5;
		
	Pin[ 6].color = WHITE; Pin[ 6].count = 5;
	Pin[ 8].color = WHITE; Pin[ 8].count = 3;
	Pin[13].color = WHITE; Pin[13].count = 5;
	Pin[24].color = WHITE; Pin[24].count = 2;

	RedrawAllStones   ();

	Pin[(25+BLACK)].color = BLACK;
	Pin[(25+WHITE)].color = WHITE;

	doubler.value = 1;
	doubler.owner  = 0;
	DrawDoubler (doubler.value, doubler.owner);
}

void load_config (void)
{
	FILE *f;

	if (!(f = fopen ("xgammon.config", "r"))) {
        	fprintf (stderr, "Couldn't open config file for reading, sorry!\n");
        	return;
        }

	if (!wraped) { yyin = f; wraped = 1; }
	else	     { yyin = f; YY_NEW_FILE; }

	BEGIN LOAD_CONFIG;

	yylex();

	if (count < 8) {
		fprintf (stderr, "incomplete array: prime_length_factors\n");
	}

	count = 0;

	fclose (f);
}
