/*
 * src/wio.c, for Pente
 * w/ by Eero Tamminen in Jan 1996.
 * See "configure.h" for copyright information.
 */

/* W1R2 interface for Pente */

#include <configure.h>

#if  W_DISP

#include <Wlib.h>
#include "pente.h"

#define WIN_PROPERTIES	(W_MOVE | W_TITLE | EV_MOUSE | EV_KEYS)
#define WIN_NAME	" PENTE v" VERSION " "

#define SIZE		14	/* block size (even) */
#define TAB_SIZE	5	/* offset from block edge */
#define MOUSE		1
#define LEVELS_MAX	5	/* last possible level + 1 */
#define EMPTY		2
#define PLAYER_0	0	/* same as from BD_OWNER() */
#define PLAYER_1	1

/* global variables */
static WWIN *Window;
static int levels[2];
static int captures[2];
static int prev_player, prev_x, prev_y, think_x, think_y;
static char prev_grid[19][19];	/* previous board situation */

/* prototypes for local functions */
static int win_open(void);
static void game_init(void);
static short wait_input(void);
static void quit(void);
static void show_0_level(void);
static void show_1_level(void);
static void show_player(void);
static void show_captures(void);


/* initialize graphics and set levels */
bd_loc_t w1_init (int *comp_level, uint winner, pl_t *game)
{
  static bool open_needed = TRUE;
  short x, y;

  /* init gfx */
  if (open_needed)
    {
      pl_t game;

      if(!win_open ())
	return (PE_CANTPLAY);
      open_needed = FALSE;
      pl_init (&game);
    }

  /* show winner if needed */
  if (winner != BD_MAXPLAYERS)
    {
      for(x = 0; x < 4; x++)
      {
	w_beep();
        if (!winner)
          w_box(Window, SIZE - 2, SIZE - 2, SIZE + 5, SIZE*19 + 5);
        else
          w_box(Window, SIZE*23 - 2, SIZE - 2, SIZE + 5, SIZE*19 + 5);
	w_flush();
	sleep(1);
      }
    }

  /* get player levels (0=human) */
  levels[0] = comp_level[0];
  levels[1] = comp_level[1];
  show_0_level();
  show_1_level();
  do
  {
    while(wait_input() != MOUSE);

    w_querymousepos(Window, &x, &y);
    if (x < SIZE * 3)
    {
      levels[0] = (levels[0] + 1) % LEVELS_MAX;
      show_0_level();
    }
    if (x > SIZE * 22)
    {
      levels[1] = (levels[1] + 1) % LEVELS_MAX;
      show_1_level();
    }
  }
  while(x < SIZE * 3 || x > SIZE * 22);
  comp_level[0] = levels[0];
  comp_level[1] = levels[1];
  game_init();

  return (PE_RESTART);
}


/* Initialize W stuff (connect server, open window, set font/title)
 * Return 0 on error.
 */
int win_open(void)
{
  WSERVER *wserver;
  int x, y;

  if(!(wserver = w_init()))
  {
    fprintf(stderr, "%s: can't connect to wserver\n");
    return 0;
  }

  if(!(Window = w_create(SIZE * 25, SIZE * 21, WIN_PROPERTIES)))
  {
    fprintf(stderr, "%s: can't create window\n");
    return 0;
  }
  if(w_open(Window, -1, -1) < 0)
  {
    fprintf(stderr, "%s: can't open window\n");
    return 0;
  }
  w_settitle(Window, WIN_NAME);

  /* zero the board */
  for (x = 0; x < 19; x++)
    for (y = 0; y < 19; y++)
      prev_grid[x][y] = EMPTY;

  /* draw the board */
  w_setmode(Window, M_INVERS);
  for (x = 3; x < 20 + 3; x++)
    w_vline(Window, x * SIZE, SIZE, (1+19) * SIZE);
  for (y = 1; y < 20 + 1; y++)
    w_hline(Window, 3 * SIZE, y * SIZE, (3+19) * SIZE);
  w_box(Window, SIZE*3  - 1, SIZE - 1, SIZE*19 + 3, SIZE*19 + 3);

  w_box(Window, SIZE    - 1, SIZE - 1, SIZE + 3, SIZE*19 + 3);
  w_box(Window, SIZE*23 - 1, SIZE - 1, SIZE + 3, SIZE*19 + 3);
  w_box(Window, SIZE    - 2, SIZE - 2, SIZE + 5, SIZE*19 + 5);

  return 1;
}

static void game_init(void)
{
  if(captures[0] || captures[1])
  {
    captures[0] = captures[1] = 0;
    show_captures();
  }
  if(prev_player)
  {
    show_player();
    prev_player = 0;
  }
  think_x = -1;
}

/* draw the game board */
void w1_draw (pl_t * game, bool forced)
{
  bd_t *board = pl_board (game);
  int x, y, mode, over = FALSE;
  bd_loc_t loc;

  if(think_x >= 0 && think_y >= 0)
  {
    w_pbox(Window, (3+think_x) * SIZE + 3, (1+think_y) * SIZE + 3,
      SIZE - 5, SIZE - 5);
    think_x = -1;
  }

  if (pl_nmoves (game) > 1)
    w_pbox(Window, (3+prev_x) * SIZE + TAB_SIZE, (1+prev_y) * SIZE + TAB_SIZE,
      SIZE - TAB_SIZE*2+1, SIZE - TAB_SIZE*2+1);

  if(captures[0] != board->captures[0] || captures[1] != board->captures[1])
  {
    captures[1] = board->captures[1];
    captures[0] = board->captures[0];
    show_captures();
  }

  w_setmode(Window, M_CLEAR);
  mode = M_CLEAR;

  /* output only changed squares */
  for (x = 0; x < 19; x++)
  {
    for (y = 0; y < 19; y++)
    {
      loc = bd_xy_loc (x, y);
      if (BD_EMPTYP (board->grid[loc]))
      {
	if(prev_grid[x][y] != EMPTY)
	{
	  prev_grid[x][y] = EMPTY;
	  if(mode != M_CLEAR)
	  {
	    mode = M_CLEAR;
	    w_setmode(Window, M_CLEAR);
	  }
	  w_pbox(Window,
	    (3+x) * SIZE + 1, (1+y) * SIZE + 1,
	    SIZE - 1, SIZE - 1);
	}
      }
      else
      {
	if(BD_OWNER(board->grid[loc]) != prev_grid[x][y])
	{
	  if(mode != M_INVERS)
	  {
	    mode = M_INVERS;
	    w_setmode(Window, M_INVERS);
	  }
	  if(BD_OWNER(board->grid[loc]))
	  {
	    prev_grid[x][y] = 1;
	    w_circle(Window, (3+x) * SIZE + SIZE / 2,
	      (1+y) * SIZE + SIZE / 2, SIZE/2-1);
	  }
	  else
	  {
	    prev_grid[x][y] = 0;
	    w_pcircle(Window, (3+x) * SIZE + SIZE / 2,
	      (1+y) * SIZE + SIZE / 2, SIZE/2-1);
	  }
	}
	if (BD_WINNERP (board->grid[loc]))
	{
	  over = TRUE;
	  if(mode != M_INVERS)
	  {
	    mode = M_INVERS;
	    w_setmode(Window, M_INVERS);
	  }
	  w_pbox(Window,
	    (3+x) * SIZE + TAB_SIZE, (1+y) * SIZE + TAB_SIZE,
	    SIZE - TAB_SIZE*2+1, SIZE - TAB_SIZE*2+1);
	}
      }
    }
  }

  w_setmode(Window, M_INVERS);
  if(!over)
  {
    loc = pl_getmove (game, pl_nmoves (game) - 1);
    prev_x = bd_loc_x(loc);
    prev_y = bd_loc_y(loc);
    w_pbox(Window, (3+prev_x) * SIZE + TAB_SIZE, (1+prev_y) * SIZE + TAB_SIZE,
      SIZE - TAB_SIZE*2+1, SIZE - TAB_SIZE*2+1);
  }
  w_flush();
}

/* get a move */
bd_loc_t w1_selectmove (pl_t * game, int compfd)
{
  uint player = pl_player (game), turn_num = pl_turn (game);
  short x, y, input;
  bd_loc_t loc;

  if (player != prev_player)
  {
    /* show which player only if eiterh player is human */
    if(levels[0] == 0 || levels[1] == 0)
      show_player();
    prev_player = pl_player(game);
  }

  if (levels[player] > 0)
  {
    w_flush();
    return (PE_COMP);
  }
  if ((turn_num == 0) && (player == 0))
    return (bd_xy_loc (9, 9));

  for (;;)
    {
      if((input = wait_input()) == MOUSE)
        {
	  w_querymousepos(Window, &x, &y);
	  x = x / SIZE - 3;
	  y = y / SIZE - 1;
	  /* make a move */
	  if (pl_movep (game, bd_xy_loc (x, y)))
	      return (bd_xy_loc (x, y));
	  else
	    {
	      w_beep();
	      continue;
	    }
	}
      switch (input)
	{
	case 'u':
	case 'U':
	  if (turn_num > 1)
	    return (PE_UNDO);
	  else
	    w_beep();
	  break;

	case 'r':
	case 'R':
	  return (PE_RESTART);
	  break;

	default:
	  w_beep();
	  break;
	}
    }
}

static short wait_input(void)
{
  WEVENT *ev;

  /* until mouse button pressed or a key */
  while(ev = w_queryevent(NULL, NULL, NULL, -1))
  {
    if((ev->type == EVENT_GADGET && ev->key == GADGET_EXIT))
      quit();
    if(ev->type == EVENT_MPRESS)
      return MOUSE;
    if(ev->type == EVENT_KEY)
      if(ev->key == '\33')
        quit();
      else
        return ev->key & 0xff;
  }
}

/* quit Pente */
static void quit (void)
{
  if(Window)
  {
    w_close(Window);
    w_delete(Window);
  }
  pe_output_vars ();
  exit (0);
}

/* -------------- */
/* show position candinate */
void w1_think (bd_loc_t pos, uint player)
{
  if(think_x >= 0 && think_y >= 0)
  {
    w_pbox(Window, (3+think_x) * SIZE + 3, (1+think_y) * SIZE + 3,
      SIZE - 5, SIZE - 5);
  }
  think_x = bd_loc_x(pos);
  think_y = bd_loc_y(pos);
  w_pbox(Window, (3+think_x) * SIZE + 3, (1+think_y) * SIZE + 3,
    SIZE - 5, SIZE - 5);
  w_flush();
}

static void show_0_level(void)
{
  int i;
  w_setmode(Window, M_CLEAR);
  w_pbox(Window, SIZE, SIZE, SIZE, SIZE*LEVELS_MAX);
  w_setmode(Window, M_INVERS);
  if(!levels[0])
    w_pcircle(Window, SIZE + SIZE/2, SIZE + SIZE/2, SIZE/2-1);
  else
    for(i = 0; i < levels[0]; i++)
      w_pbox(Window, SIZE+3, SIZE*(i+1)+3, SIZE - 5, SIZE - 5);
}

static void show_1_level(void)
{
  int i;
  w_setmode(Window, M_CLEAR);
  w_pbox(Window, SIZE*23, SIZE, SIZE, SIZE*LEVELS_MAX);
  w_setmode(Window, M_INVERS);
  if(!levels[1])
    w_circle(Window, SIZE*23 + SIZE/2, SIZE + SIZE/2, SIZE/2-1);
  else
    for(i = 0; i < levels[1]; i++)
      w_pbox(Window, SIZE*23+3, SIZE*(i+1)+3, SIZE - 5, SIZE - 5);
}

static void show_player(void)
{
  /* expects mode to be inverse */
  w_box(Window, SIZE    - 2, SIZE - 2, SIZE + 5, SIZE*19 + 5);
  w_box(Window, SIZE*23 - 2, SIZE - 2, SIZE + 5, SIZE*19 + 5);
}

static void show_captures(void)
{
  int i;

  w_setmode(Window, M_CLEAR);
  w_pbox(Window, SIZE, SIZE*(20-5), SIZE, SIZE*5);
  w_pbox(Window, SIZE*23, SIZE*(20-5), SIZE, SIZE*5);

  w_setmode(Window, M_INVERS);
  for(i = 0; i < captures[0]; i++)
  {
    w_circle(Window, SIZE + SIZE/2, (19-i) * SIZE + SIZE/2, SIZE/2-1);
    /* a winning capture? */
    if(captures[0] >= 5)
      w_pbox(Window, SIZE + TAB_SIZE, (19-i) * SIZE + TAB_SIZE,
        SIZE - TAB_SIZE*2+1, SIZE - TAB_SIZE*2+1);
  }
  for(i = 0; i < captures[1]; i++)
  {
    w_pcircle(Window, SIZE*23 + SIZE/2, (19-i) * SIZE + SIZE/2, SIZE/2-1);
    if(captures[1] >= 5)
      w_pbox(Window, SIZE*23 + TAB_SIZE, (19-i) * SIZE + TAB_SIZE,
        SIZE - TAB_SIZE*2+1, SIZE - TAB_SIZE*2+1);
  }
}

#endif
