/*
 * File: dumbterm.c
 *
 * This file implements the interface between GNU Othello and the user
 * on a dumb terminal which just scrolls.
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef __GNUC__
/*#include "clib.h"*/
#endif
#include "othello.h"
#include "io.h"
#include "global.h"
#include "version.h"


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


/*
 * Initialize the io package. We need do nothing special.
 */

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



void
init_io_for_one_game()
{
}



/*
 * Print a move in text format.
 */

static void
print_move(sq)
Square   sq;
{
    if (sq == PASS)
	puts("pass");
    else
	printf("%c%c\n", COL(sq) + 'a' - 1, ROW(sq) + '0');
    fflush(stdout);
}



/*
 * Print the computers move on the screen.
 */

void
print_my_move(moveno, sq)
int      moveno;
Square   sq;
{
    printf("My move: ");
    print_move(sq);
}


/*
 * Print the opponents move on the screen.
 */

void
print_your_move(moveno, sq)
int      moveno;
Square   sq;
{
    printf("Your move: ");
    print_move(sq);
}



/*
 * Print a board with some extra info.
 */

void
print_board(board)
Board   board;
{
    int   row;
    int   col;
    
    puts("   A B C D E F G H");
    for (row = 1; row <= 8; ++row) {
	putchar(' ');
	putchar(row + '0');
	putchar(' ');
	for (col = 1; col < 9; ++col) {
	    switch (board[SQ(col, row)]) {

	      case EMPTY:
		putchar('.');
		break;

	      case MYCOLOR:
		putchar(mycolor == WHITE ? 'O' : 'X');
		break;

	      case YOURCOLOR:
		putchar(yourcolor == WHITE ? 'O' : 'X');
		break;
	    }
	    putchar(' ');
	}
	putchar(row + '0');
	putchar('\n');
    }
    puts("   A B C D E F G H");
    fflush(stdout);
}



/*
 * Print a much simplified and somewhat formatted summary of the
 * position in 'state'.
 */

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

    count_pieces(state, &my, &yours);
    printf("I have   %2d. \nYou have %2d.\n\n", my, yours);
    fflush(stdout);
}



/*
 * Print a message for the user on the screen.
 */

void
print_message(msg)
char  * msg;
{
    printf("%s", msg);
    fflush(stdout);
}



/*
 * Print some statistics about the state PLAYSTATE.
 */

void
print_statistics(state)
State   *state;
{
    int   mypieces;
    int   yourpieces;
    
    count_pieces(state, &mypieces, &yourpieces);
    printf("me:\t%d\n", mypieces);
    printf("you:\t%d\n", yourpieces);
    fflush(stdout);
}



/*
 * Show the user the status of the game (thinking, waiting for users
 * move, etc). Since the state is obvious from other output we
 * don't have to do anything here. This function is primarily used
 * in user interfaces featuring some kind of windows where the state
 * might not be clear from the look of the screen.
 */

void
show_status(status)
int   status;
{
}



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



/*
 * Print help about commands to the user.
 */

static void
printhelp()
{
    puts("[a-h][1-8]\tput a piece on the location.");
    puts("l[1-9]\t\tset the playing level to the number. 1 is easiest.");
    puts("p\t\tpass - don't move (illegal if you can move)");
    puts("s\t\tshow the board");
    puts("u\t\tundo your last move");
    puts("v\t\tprint version of the program.");
    puts("?\t\tprint this help.");
    fflush(stdout);
}



/*
 * Receive input from the user on stdin and check it. Don't return
 * until something legal was entered. Blanks are deleted and all input
 * is made lower case prior to returning. 
 *
 * If EOF was entered, the program stops short.
 */

static void
get_input(buffer)
char   buffer[];
{
    char   linebuf[100];
    bool   ok;
    int    in;
    int    out;

    ok = FALSE;
    do {
	/* Prompt the user so that he knows the program is alive. */
	putchar('>');
	fflush(stdout);

	/* Get input from the user and quit if we got EOF. */
	(void) fgets(linebuf, 100, stdin);
	if (feof(stdin)) {
	    print_message("Giving up, eh?\n");
	    exit(0);
	}

	/* Delete all blanks in the input. */
	in = 0;
	out = 0;
	while (linebuf[in] != '\000') {
	    if (linebuf[in] != ' ')
		linebuf[out++] = linebuf[in];
	    ++in;
	}
	linebuf[out] = '\000';

	/* Check if the input is correct. If it is, set the variable ok */
	/* so that the loop ends. */
	if (strlen(linebuf) <= 3) {

	    /* Make all input lower case. */
	    if (isupper(linebuf[0]))
		linebuf[0] = tolower(linebuf[0]);

	    buffer[0] = linebuf[0];
	    buffer[1] = linebuf[1];
	    switch(buffer[0]) {
	      case 'a':    case 'b':    case 'c':    case 'd':
	      case 'e':    case 'f':    case 'g':    case 'h':
		if ('1' <= buffer[1] && buffer[1] <= '8')
		    ok = TRUE;
		break;

	      case 'p':
	      case 's':
	      case 'u':
	      case 'v':
	      case '?':
		if (buffer[1] = '\n')
		    ok = TRUE;
		break;

	      case 'l':
		if ('1' <= buffer[1] && buffer[1] <= '9')
		    ok = TRUE;
		break;

	      default:
		break;
	    }
	}

	/* Give an error message if we couldn't understand the input. */
	if (!ok)
	    print_message("eh?\n");

    } while (!ok);
}



/*
 * Get the users move, and return it. For getting the users input,
 * the function get_input() is called. Also take care of other
 * user requests such as print the board, get help etc.
 */

Square
get_users_move(state)
State   *state;
{
    char       buffer[2];
    Square     sq;
    bool       ok;

    ok = FALSE;
    do {
	get_input(buffer);
	switch (buffer[0]) {
	  case 'a':    case 'b':    case 'c':    case 'd':
	  case 'e':    case 'f':    case 'g':    case 'h':
	    sq = SQ(buffer[0] - 'a' + 1, buffer[1] - '0');
	    ok = can_move(state, sq, YOURCOLOR);

	    if (!ok) {
		printf("Illegal move!\n");
		fflush(stdout);
	    }
	    break;

	  case 'l':
	    level = buffer[1] - '0';
	    break;

	  case 'p':
	    if (num_legal_moves(state, YOURCOLOR) == 0) {
		ok = TRUE;
		sq = PASS;
	    } else {
		printf("You cannot pass. There is at least one legal move!\n");
		fflush(stdout);
	    }
	    break;

	  case 's':
	    print_state(state);
	    break;

	  case 'u':
	    ok = TRUE;
	    sq = UNDO;
	    break;

	  case 'v':
	    printf("\nThis is %s\n\n", VERSIONSTRING);
	    break;

	  case '?':
	    printhelp();
	    break;

	  default:
	    break;
	}
    } while (!ok);

    return sq;
}



/*
 * This function waits for the user to start a new game. It is only
 * used in windowing environments where the board is seen all the time.
 */

void
start_game()
{
}



/*
 * Prompt the user whether he/she wants another game.  Return 
 * TRUE if he does.
 */

bool
another_game()
{
    char   answer;

    printf("another game (y/n)?");
    do {
	answer = getchar();
    } while (answer != 'y' && answer != 'n');

    return answer == 'y';
}
