/*
 * File: sunview.c
 *
 * This file contains the functions to let the user play GNU Othello 
 * on a SUN workstation using SUNVIEW as user interface.
 */

struct fb_wid_dbl_info {};		/* UGLY!! */
#include <stdio.h>
#include <string.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include <suntool/panel.h>
#if 0
#ifdef __GNUC__
#include "clib.h"
#endif
#endif
#include "textwindow.h"
#include "othello.h"
#include "global.h"
#include "io.h"
#include "version.h"


/* ================================================================ */
/*         Functions that work together with textwindow.[ch]        */


typedef struct {
    Canvas     canvas;
    Pixfont  * font;
    int        fontwidth;
    int        fontheight;
} Subwindow;


extern pw_char();
extern pw_text();

void
window_write_char(win, row, col, ch)
Subwindow  * win;
int          row;
int          col;
int          ch;
{
    pw_char(canvas_pixwin(win->canvas),
	    col * win->fontwidth, -1 + (row + 1) * win->fontheight,
	    PIX_SRC, win->font, ch);
}


void
window_write_text(win, row, col, str)
Subwindow  * win;
int          row;
int          col;
char       * str;
{
    pw_text(canvas_pixwin(win->canvas), 
	    col * win->fontwidth, -1 + (row + 1) * win->fontheight,
	    PIX_SRC, win->font, str);
}


void
window_flush()
{
}


/* ================================================================ */


/* The elements of the user interface: Windows, buttons, and so on.*/

static Frame     frame;
static Canvas    board_canvas;

static Panel        panel;
static Panel_item   pass_button;
static Panel_item   undo_button;
static Panel_item   newgame_button;
static Panel_item   quit_button;
static Panel_item   resign_button;
static Panel_item   color_choice;
static Panel_item   level_choice;

static Canvas     message_canvas;
static Canvas     moves_canvas;
static Canvas     status_canvas;
static Pixfont  * smallfont;
static Pixfont  * bigfont;
static Pixfont  * bigboldfont;

/* Some definitions to use in the text windows. */
#define FONTHEIGHT 15
#define FONTWIDTH 7

#define MESSAGE_WIDTH   40
#define MESSAGE_HEIGHT  11
#define MOVES_WIDTH     15
#define MOVES_HEIGHT    26

static Subwindow   message_window;
static Subwindow   moves_window;
static Subwindow   status_window;

static Textwindow  * message_tw;
static Textwindow  * moves_tw;
static Textwindow  * status_tw;


/* Forward declarations of the callback procedures. */

static void   board_event_handler();

static void   pass_proc();
static void   undo_proc();
static void   newgame_proc();
static void   quit_proc();
static void   resign_proc();

static void   level_proc();
static void   color_proc();
static void   make_move();


/* ================================================================ */
/*      Functions and declarations for dealing with bitmaps.        */


#define Bitmap Pixrect

/*
 * Make a bitmap from an array of bytes in memory.
 */

#define make_bitmap(width, height, array) \
    mem_point(width, height, 1, array)



/*
 * Draw the upper left (WIDTH, HEIGHT) part of a bitmap into
 * the image of the board.
 */

static void
window_put_bitmap(bitmap, x, y, width, height)
struct pixrect *bitmap;
int            x, y;
int            width, height;
{
    pw_write(canvas_pixwin(board_canvas), x, y, width, height,
	     PIX_SRC, bitmap, 0, 0);
}


/* ================================================================ */
/*                  Local variables in sunview.c                    */


#define BM_WIDTH      64
#define SQ_WIDTH      60
#define BORDERWIDTH   16


/* Bitmaps for the three kinds of squares. */
Bitmap  * nopiece_bm;
Bitmap  * blackpiece_bm;
Bitmap  * whitepiece_bm;


unsigned short nopiece_arr[] = {
#   include "nopiece.icon"
};

unsigned short blackpiece_arr[] = {
#   include "blackpiece.icon"
};

unsigned short whitepiece_arr[] = {
#   include "whitepiece.icon"
};


/* ================================================================ */
/*                        Internal functions                        */


/* The icon of the main window. */
static short icon_image[] = {
#include "othellotool.icon"
};
/* DEFINE_ICON_FROM_IMAGE(the_icon, icon_image);*/


/*
 * Create all the windows that are part of the sunview interface to 
 * GNU Othello.  This includes the panel with all its panel items.
 */

static void
init_windows(argc, argv)
int    *argc;
char   *argv[];
{
    /* Open the fonts we need and quit if we can't find them. */
    smallfont = pf_open("/usr/lib/fonts/fixedwidthfonts/screen.r.12");
    bigfont = pf_open("/usr/lib/fonts/fixedwidthfonts/screen.r.14");
    bigboldfont = pf_open("/usr/lib/fonts/fixedwidthfonts/screen.b.14");

    if (smallfont == NULL) {
	fprintf(stderr, "smallfont was not found\n");
	exit(1);
    }
    if (bigfont == NULL) {
	fprintf(stderr, "bigfont was not found\n");
	exit(1);
    }
    if (bigboldfont == NULL) {
	fprintf(stderr, "bigboldfont was not found\n");
	exit(1);
    }

    /* Create bitmaps with the three kinds of squares. */
    nopiece_bm = make_bitmap(BM_WIDTH, BM_WIDTH, nopiece_arr);
    blackpiece_bm = make_bitmap(BM_WIDTH, BM_WIDTH, blackpiece_arr);
    whitepiece_bm = make_bitmap(BM_WIDTH, BM_WIDTH, whitepiece_arr);

    /* Main window */
    frame = window_create(NULL, FRAME,
			  FRAME_LABEL,        VERSIONSTRING,
/*			  FRAME_ICON,         &the_icon,*/
			  FRAME_ARGS,         *argc, argv,
			  FRAME_SUBWINDOWS_ADJUSTABLE, FALSE,
			  0);

    board_canvas = window_create(frame, CANVAS,
                  /* set default size */
		  WIN_WIDTH,                8 * SQ_WIDTH + 2 * BORDERWIDTH,
		  WIN_HEIGHT,               8 * SQ_WIDTH + 2 * BORDERWIDTH,

                  /* default, but do it anyway for clarity */	
		  WIN_CONSUME_PICK_EVENT,   MS_LEFT,
		  WIN_CONSUME_PICK_EVENT,   MS_MIDDLE,
		  WIN_CONSUME_PICK_EVENT,   MS_RIGHT,
		  WIN_CONSUME_KBD_EVENT,    WIN_ASCII_EVENTS,

                  /* ... and don't let the drawing area shrink below it */
		  CANVAS_AUTO_SHRINK,       FALSE,
				 
		  WIN_EVENT_PROC,           board_event_handler,
		  0);

    moves_canvas = window_create(frame, CANVAS,
				 WIN_WIDTH,           MOVES_WIDTH * FONTWIDTH,
				 WIN_HEIGHT,          MOVES_HEIGHT * FONTHEIGHT
                                                      + 5,
				 WIN_RIGHT_OF,        board_canvas,
				 WIN_Y,               0,
				 0);
    
    status_canvas = window_create(frame, CANVAS,
				  WIN_WIDTH,     MOVES_WIDTH * FONTWIDTH,
				  WIN_HEIGHT,    8 * SQ_WIDTH + 2 * BORDERWIDTH
                                                 - MOVES_HEIGHT * FONTHEIGHT
                                                 - 10,
				  WIN_RIGHT_OF,  board_canvas,
				  WIN_BELOW,     moves_canvas,
				  0);
	
    message_canvas = window_create(frame, CANVAS,
				   WIN_WIDTH,      MESSAGE_WIDTH * FONTWIDTH,
				   WIN_HEIGHT,     MESSAGE_HEIGHT * FONTHEIGHT,
				   WIN_X,          0,
				   WIN_BELOW,      board_canvas,
				   0);

    panel = window_create(frame, PANEL,
			  WIN_BELOW,            board_canvas,
			  WIN_RIGHT_OF,         message_canvas,
			  PANEL_LABEL_FONT,     bigboldfont,
			  PANEL_LABEL_BOLD,     TRUE,
			  0);

    pass_button = panel_create_item(panel, PANEL_BUTTON,
				    PANEL_LABEL_IMAGE,
				    panel_button_image(panel, "Pass",
						       8, bigboldfont),
				    PANEL_NOTIFY_PROC,    pass_proc,
				    PANEL_ITEM_X,         ATTR_COL(1),
				    PANEL_ITEM_Y,         ATTR_ROW(0),
				    0);

    undo_button = panel_create_item(panel, PANEL_BUTTON,
				    PANEL_LABEL_IMAGE,
				    panel_button_image(panel, "Undo",
						       8, bigboldfont),
				    PANEL_NOTIFY_PROC,    undo_proc,
				    PANEL_ITEM_X,         ATTR_COL(1),
				    PANEL_ITEM_Y,         ATTR_ROW(2),
				    0);

    newgame_button = panel_create_item(panel, PANEL_BUTTON,
				       PANEL_LABEL_IMAGE,
				       panel_button_image(panel, "New Game",
							  8, bigboldfont),
				       PANEL_NOTIFY_PROC,    newgame_proc,
				       PANEL_ITEM_X,         ATTR_COL(15),
				       PANEL_ITEM_Y,         ATTR_ROW(0),
				       0);

    quit_button = panel_create_item(panel, PANEL_BUTTON,
				    PANEL_LABEL_IMAGE,
				    panel_button_image(panel, "Quit",
						       8, bigboldfont),
				    PANEL_NOTIFY_PROC,    quit_proc,
				    PANEL_ITEM_X,         ATTR_COL(15),
				    PANEL_ITEM_Y,         ATTR_ROW(2),
				    0);

    resign_button = panel_create_item(panel, PANEL_BUTTON,
				      PANEL_LABEL_IMAGE,
				      panel_button_image(panel, "Resign",
							 8, bigboldfont),
				      PANEL_NOTIFY_PROC,    resign_proc,
				      PANEL_ITEM_X,         ATTR_COL(29),
				      PANEL_ITEM_Y,         ATTR_ROW(0),
				      0);

    color_choice = panel_create_item(panel, PANEL_CHOICE,
				     PANEL_LABEL_STRING,     "Computer Plays:",
				     PANEL_CHOICE_STRINGS,   "White",
				                             "Black",
				                             0,
				     PANEL_CHOICE_XS, ATTR_COL(1),
				                      ATTR_COL(10),
				                      0,
				     PANEL_CHOICE_YS, ATTR_ROW(5),
						      ATTR_ROW(5),
				                      0,
				     PANEL_DISPLAY_LEVEL,    PANEL_ALL,
				     PANEL_FEEDBACK,         PANEL_INVERTED,
				     PANEL_LAYOUT,           PANEL_HORIZONTAL,
				     PANEL_NOTIFY_PROC,      color_proc,
				     PANEL_ITEM_X,           ATTR_COL(1),
				     PANEL_ITEM_Y,           ATTR_ROW(4),
				     0);

    level_choice = panel_create_item(panel, PANEL_CHOICE,
				     PANEL_LABEL_STRING,     "Level:",
				     PANEL_CHOICE_STRINGS,
				       " 1 ", " 2 ", " 3 ",
				       " 4 ", " 5 ", " 6 ",
				       " 7 ", " 8 ", " 9 ",
				       0,
				     PANEL_CHOICE_XS,        
				      ATTR_COL(27), ATTR_COL(32), ATTR_COL(37),
				      ATTR_COL(27), ATTR_COL(32), ATTR_COL(37),
				      ATTR_COL(27), ATTR_COL(32), ATTR_COL(37),
				      0,
				     PANEL_CHOICE_YS,
				       ATTR_ROW(4), ATTR_ROW(4), ATTR_ROW(4),
				       ATTR_ROW(5), ATTR_ROW(5), ATTR_ROW(5),
				       ATTR_ROW(6), ATTR_ROW(6), ATTR_ROW(6),
				       0,
				     PANEL_DISPLAY_LEVEL,    PANEL_ALL,
				     PANEL_FEEDBACK,         PANEL_INVERTED,
				     PANEL_LAYOUT,           PANEL_HORIZONTAL,
				     PANEL_NOTIFY_PROC,      level_proc,
				     PANEL_ITEM_X,           ATTR_COL(20),
				     PANEL_ITEM_Y,           ATTR_ROW(4),
				     0);

    window_fit(frame);
}



/*
 * Event handler for the board window.  This routine is called when
 * we click the mouse in the board.
 */

/*ARGSUSED*/
static void
board_event_handler(canvas, event, arg)
Canvas    canvas;
Event   * event;
caddr_t   arg;
{
    int   col;
    int   row;
    int   evid;

    evid = event_id(event);
    col = 1 + (event_x(event) - BORDERWIDTH) / SQ_WIDTH;
    row = 1 + (event_y(event) - BORDERWIDTH) / SQ_WIDTH;

    if (evid < 128) {

	/* Keyboard event */
	if (evid == 'p')
	    make_move(PASS);
    } else {

	/* Return if we clicked inside the border. */
	if (row < 1 || row > 8 || col < 1 || col > 8)
	    return;

	switch (evid) {
	  case MS_LEFT:
	    if (event_is_down(event)) {
		/* NOTHING */;
	    } else if (event_is_up(event))
		make_move(SQ(col, row));
	    break;

	  default:
	    break;
	}
    }
}



/* 
 * This function is called from the UNDO button.
 */

static void
undo_proc()
{
    make_move(UNDO);
}


/* 
 * This function is called from the PASS button.
 */

static void
pass_proc()
{
    make_move(PASS);
}


/* 
 * This function is called from the QUIT button.
 */

static void
quit_proc()
{
    exit(0);
}


/* 
 * This function is called from the RESIGN button.
 */

static void
resign_proc()
{
    if (game_in_progress) {
	print_message("Giving up, eh?\n");
	make_move(RESIGN);
    } else {
	print_message("There is no game to resign.\n");
    }

}



/* 
 * This function is called when a new level is chosen.
 */

static void
level_proc(item, value, event)
Panel_item   item;
int          value;
Event        *event;
{
    char   buff[100];

    level = value + 1;
    sprintf(buff, "Playing level reset to %d.\n", level);
    print_message(buff);
}



/* 
 * This function is called when a new color is chosen.
 */

static void
color_proc(item, value, event)
Panel_item   item;
int          value;
Event        *event;
{
    /* If the user tried to change color during a game, refuse */
    /* and reset the color to the previous value. */
    if (game_in_progress && value == (mycolor == WHITE)) {
	print_message("You can't change color during a game!\n");
	panel_set(color_choice, PANEL_VALUE, 1 - value, 0);

    } else {
	if (value == 0) {
	    mycolor = WHITE;
	    yourcolor = BLACK;
	} else {
	    mycolor = BLACK;
	    yourcolor = WHITE;
	}
    }
}



/* ================================================================ */
/*                     Initialization functions                     */


/*
 * The following functions are the ones that are called from the
 * Othello program.  The ones above are all local to sunview.c
 */


/*
 * Init the sunview interface. This includes creating all the 
 * subwindows, initializing the headlines in the text windows,
 * drawing the starting position of the board and drawing
 * the border and legend around the board.
 *
 * A few default values are also displayed in the choises in
 * the panel.
 */

void
init_io(argc, argv)
int   * argc;
char  * argv[];
{
    init_windows(argc, argv);

    message_window.canvas = message_canvas;
    message_window.font = smallfont;
    message_window.fontwidth = FONTWIDTH;
    message_window.fontheight = FONTHEIGHT;
    message_tw = textwindow_create( (void *) &message_window,
				    MESSAGE_WIDTH, MESSAGE_HEIGHT);
    textwindow_set_scrollregion(message_tw, 1, MESSAGE_HEIGHT - 1);

    moves_window.canvas = moves_canvas;
    moves_window.font = smallfont;
    moves_window.fontwidth = FONTWIDTH;
    moves_window.fontheight = FONTHEIGHT;
    moves_tw = textwindow_create( (void *) &moves_window,
				  MOVES_WIDTH, MOVES_HEIGHT);
    textwindow_set_scrollregion(moves_tw, 2, MOVES_HEIGHT - 1);

    status_window.canvas = status_canvas;
    status_window.font = smallfont;
    status_window.fontwidth = FONTWIDTH;
    status_window.fontheight = FONTHEIGHT;
    status_tw = textwindow_create( (void *) &status_window, MOVES_WIDTH, 6);

    panel_set(level_choice, PANEL_VALUE, level - 1, 0);
    panel_set(color_choice, PANEL_VALUE, mycolor, 0);

    /* Draw the initial board position on the board canvas and */
    /* write the legend around it. */
    {
	State   state;
	int     i;

	resetstate(&state);
	print_state(&state);
	for (i = 0; i < 8; ++i) {
	    pw_char(canvas_pixwin(board_canvas), 
		    BORDERWIDTH + SQ_WIDTH / 2 - 4 + i * SQ_WIDTH, 12,
		    PIX_SRC | PIX_DST, bigboldfont, "ABCDEFGH"[i]);
	    pw_char(canvas_pixwin(board_canvas), 
		    BORDERWIDTH + SQ_WIDTH / 2 - 4 + i * SQ_WIDTH, 
		    BORDERWIDTH + 8 * SQ_WIDTH + 12,
		    PIX_SRC | PIX_DST, bigboldfont, "ABCDEFGH"[i]);
	    pw_char(canvas_pixwin(board_canvas), 
		    4, BORDERWIDTH + i * SQ_WIDTH + SQ_WIDTH / 2 + 4,
		    PIX_SRC | PIX_DST, bigboldfont, "12345678"[i]);
	    pw_char(canvas_pixwin(board_canvas), 
		    BORDERWIDTH + 8 * SQ_WIDTH + 4,
		    BORDERWIDTH + i * SQ_WIDTH + SQ_WIDTH / 2 + 4,
		    PIX_SRC | PIX_DST, bigboldfont, "12345678"[i]);
	}
	init_io_for_one_game();
    }

    window_set(frame, WIN_SHOW, TRUE, 0);
    notify_dispatch();
}



/*
 * This functions is called once before each game starts. It empties
 * the text subwindows and writes the headlines in them.
 */

void
init_io_for_one_game()
{
    int   i;

    textwindow_putcur(message_tw, 0, 0);
    textwindow_print(message_tw, "       M E S S A G E   A R E A\n");
    for (i = 0; i < MESSAGE_HEIGHT - 1; ++i)
	textwindow_print(message_tw, "                                      \n");
    textwindow_putcur(message_tw, 1, 0);

    textwindow_putcur(moves_tw, 0, 0);
    textwindow_print(moves_tw,"    M O V E S\n");
    if (mycolor == BLACK)
	textwindow_print(moves_tw, "     Me  You\n");
    else
	textwindow_print(moves_tw, "    You   Me\n");

    textwindow_putcur(moves_tw, 2, 0);
    for (i = 0; i < MOVES_HEIGHT - 2; ++i)
	textwindow_print(moves_tw, "            \n");

    textwindow_putcur(status_tw, 0, 0);
    textwindow_print(status_tw, "  S T A T U S");
}


/* ================================================================ */
/*                          Output functions                        */


/*
 * Draw a piece with the color COLOR at the position (ROW, COL) 
 * on the screen.
 */

static void
draw_piece(col, row, color)
int   col;
int   row;
int   color;
{
    Bitmap  * bm;

    switch (color) {
      case EMPTY:
	bm = nopiece_bm;
	break;
      case MYCOLOR:
	bm = (mycolor == BLACK ? blackpiece_bm : whitepiece_bm);
	break;
      case YOURCOLOR:
	bm = (mycolor == BLACK ? whitepiece_bm : blackpiece_bm);
      default:
	break;
    }

    window_put_bitmap(bm, 
		      BORDERWIDTH + (col - 1) * SQ_WIDTH,
		      BORDERWIDTH + (row - 1) * SQ_WIDTH,
		      SQ_WIDTH, SQ_WIDTH);
}



/*
 * Draw the configuration in BOARD on the screen.
 */

void
print_board(board)
Board   board;
{
    int   col;
    int   row;

    for (col = 1; col < 9; ++col)
	for (row = 1; row < 9; ++row)
	    draw_piece(col, row, board[SQ(col, row)]);
}



/*
 * Print the outcome of the game in the message window.
 */

void
print_statistics(state)
State  * state;
{
    char   buff[100];
    int    mypieces;
    int    yourpieces;

    count_pieces(state, &mypieces, &yourpieces);
    if (mypieces == yourpieces) {
	sprintf(buff, "The game ended %d - %d. A tie.\n",
		mypieces, yourpieces);

    } else {
	sprintf(buff, "%s won with %d - %d\n",
		(mypieces > yourpieces) ? "I" : "You",
		mycolor == BLACK ? mypieces : yourpieces,
		mycolor == BLACK ? yourpieces : mypieces);
    }

    textwindow_print(message_tw, buff);
}



/*
 * Print the move with number MOVENO in the moves window.
 */

static void
print_move(moveno, sq)
int      moveno;
Square   sq;
{
    static char   movestr[3];
    static char   buf[20];
    static int    last_moveno;

    if (moveno == 1) {
	/* Clean the first row in case we just undid a move. */
	textwindow_putcur(moves_tw, 2, 0);
	textwindow_print(moves_tw, "              ");
	last_moveno = 0;

	textwindow_putcur(moves_tw, 2, 0);
    }

    /* If this is the first move after an undo, delete all */
    /* rows that were undone. */
    while (last_moveno != moveno - 1) {
	if (last_moveno & 1)
	    textwindow_print(moves_tw, "\r              \r");
	else
	    textwindow_putcur(moves_tw, 
			      textwindow_get_currow(moves_tw) - 1, 7);
	--last_moveno;
    }

    if (sq == PASS)
	sprintf(movestr, "--");
    else
	sprintf(movestr, "%c%c", COL(sq) + 'a' - 1, ROW(sq) + '0');

    /* If moveno is odd, this is blacks move. */
    if (moveno & 1) {
	sprintf(buf, "%2d.%4s", moveno, movestr);
	textwindow_print(moves_tw, buf);
    } else {
	sprintf(buf,  " - %s\n", movestr);
	textwindow_print(moves_tw, buf);
    }

    last_moveno = moveno;
}



/*
 * Print the computers move.
 */

void
print_my_move(moveno, sq)
int      moveno;
Square   sq;
{
    print_move(moveno, sq);
}



/*
 * Print the humans move.
 */

void
print_your_move(moveno, sq)
int      moveno;
Square   sq;
{
    print_move(moveno, sq);
}



/*
 * Print a message to the user in the message window.
 */

void
print_message(msg)
char  * msg;
{
    textwindow_print(message_tw, msg);
}



/*
 * Print the score in STATE in the status window and update the 
 * image of the board.
 */

void
print_state(state)
State  * state;
{
    static char   buf[100];
    int   my;
    int   yours;
    
    print_board(&(state->board[0]));

    count_pieces(state, &my, &yours);
    sprintf(buf, "You have  %2d  \nI have    %2d  ",
	    yours, my);
    textwindow_putcur(status_tw, 2, 0);
    textwindow_print(status_tw, buf);
}



/*
 * Show the user whose turn it is in the status window.
 */

void
show_status(status)
int   status;
{
    textwindow_putcur(status_tw, 6, 0);
    switch (status) {
      case MYMOVE:
	textwindow_print(status_tw, "Thinking...");
	break;

      case YOURMOVE:
	textwindow_print(status_tw, "Your move  ");
	break;

      case NOGAME:
	textwindow_print(status_tw, "           ");
	break;

      default:
	fprintf(stderr, "BUG: show_status() got funny status: %d\n",
		status);
    }
}


/* ================================================================ */
/*                         Input functions                          */


/*
 * The way we get a move from the user is somewhat complicated.
 * We cannot just wait for the user to give us the move since
 * there are other things he might want to do besides making a 
 * move. He might for instance want to close the window and make
 * a small pause or perhaps move the window or bring it to the
 * front or back.
 *
 * Since the main loop is in the function play() we cannot just
 * call window_main_loop() and be done but we have to decide 
 * ourselves when to receive events and when not to. 
 *
 * What we do is to have a local variable telling us if a move
 * is available (movesquarevalid) and then let the event handler
 * for the board canvas set this variable and the variable 
 * holding the square itself (movesquare). This is done through
 * the function make_move().
 *
 * Get_users_move() makes a round over all events that have 
 * accumulated so far and process them (in the call to 
 * notify_dispatch()). If there is no move to return yet, we wait 
 * 0.1 seconds and try again. This is done until a move has been
 * stored in movesquare and then we return to the caller.
 */

static Square   movesquare;
static bool     movesquarevalid = FALSE;


/*
 * Store a move in the variable `movesquare' and tell get_users_move()
 * that there is one by setting `movesquarevalid' to TRUE. This
 * function is called from the board event handler and from a 
 * number of buttons.
 */

static void
make_move(sq)
Square   sq;
{
    movesquare = sq;
    movesquarevalid = TRUE;
}



/*
 * Wait for the user to make a move and return it if it was legal.
 * If not, say so in the message window and wait for another one.
 */

Square
get_users_move(state)
State   *state;
{
    Sqlist   legal_moves;
    int      num_moves;

    get_legal_moves(state, YOURCOLOR, &legal_moves, &num_moves);
    while (TRUE) {

	/* Process accumulated events. */
	notify_dispatch();

	if (movesquarevalid) {
	    movesquarevalid = FALSE;
	    if (movesquare == UNDO || movesquare == RESIGN)
		return movesquare;

	    if (movesquare == PASS && num_moves == 0) {
		return PASS;

	    } else if (can_move(state, movesquare, YOURCOLOR)) {
		return movesquare;

	    } else {
		print_message("Illegal move\n");
	    }
	} 
	usleep(100000);
    }
}


/* ================================================================ */


/*
 * When a new game is to start, we wait for the user to press the
 * `New Game' button. When he does this, the function newgame_proc()
 * is called and the flag `start_game_flag' is set to TRUE.
 *
 * The function start_game() is called from main() and its purpose
 * is to wait until the game is ready to start. This function
 * only processec events and waits for `start_game_flag' to become
 * TRUE.
 */


bool  start_game_flag = FALSE;


/*
 * This is the callback function for the `New Game' button. See further
 * above.
 */

static void
newgame_proc()
{
    if (game_in_progress) {
	print_message("You can't start a new game while\n");
	print_message("another one is in progress.\n");
    } else
	start_game_flag = TRUE;
}


/*
 * Wait for the user to press the `New Game' button.
 */

void
start_game()
{
    while (!start_game_flag) {
	notify_dispatch();
	usleep(100000);
    }
}



/*
 * Return TRUE since don't want to stop the program any other way than
 * the user pressing the `Quit' Button.
 */

bool
another_game()
{
    start_game_flag = FALSE;
    print_message("Want another game?\nPress the \"New Game\" button\n");

    return TRUE;
}
