/*LINTLIBRARY*/

/*  @(#)events.c 1.5 90/04/09
 *
 *  Procedures for handling various events in the Othello game.
 *
 *  Original SunView version by Ed Falk - Sun Microsystems Inc.
 *
 *  Rewritten for independent use by
 *          Rich Burridge, Sun Microsystems, Australia
 *
 *  Copyright (c) Ed Falk & Rich Burridge - Sun Microsystems.
 *                                          All rights reserved.
 *
 *  Permission is given to distribute these sources, as long as the
 *  introductory messages are not removed, and no monies are exchanged.
 *
 *  No responsibility is taken for any errors on inaccuracies inherent
 *  either to the comments or the code of this program, but if reported
 *  to me, then an attempt will be made to fix them.
 */

#include "othello.h"
#include "color.h"
#include "extern.h"


check_button_down(item)
enum panel_type item ;
{
  int n ;

  n = (int) item ;
  if ((curx >  items[n].x) && (curx < (items[n].x + items[n].width)) &&
      (cury >  items[n].y) && (cury < (items[n].y + items[n].height)))
    {
      down = nextc ;
      itemno = n ;
      but_inverted = itemno ;
      draw_button((enum panel_type) itemno, C_LGREY, BUT_INVERT) ;
    }
}


check_cycle_down(item)
enum panel_type item ;
{
  int ix, n, reply ;

  n = (int) item ;
  ix = items[n].x + (3 * BWIDTH) + (2 * BGAP) - CWIDTH ;
       if ((curx > ix) && (curx < (ix + (items[n].width / 2))) &&
           (cury > items[n].y) && (cury < (items[n].y + items[n].height)) &&
            nextc != RIGHT_DOWN)
    {
      direction = INCREMENT ;
      down = nextc ;
      itemno = n ;
      draw_cycle((enum panel_type) n, C_LGREY, CY_LINVERT) ;
    }
  else if ((curx > ix) && (curx < (ix + items[n].width)) &&
           (cury > items[n].y) && (cury < (items[n].y + items[n].height)) &&
            nextc != RIGHT_DOWN)
    {
      direction = DECREMENT ;
      down = nextc ;
      itemno = n ;
      draw_cycle((enum panel_type) n, C_LGREY, CY_RINVERT) ;
    }
  else if ((curx > ix) && (curx < (ix + items[n].width)) &&
           (cury > items[n].y) && (cury < (items[n].y + items[n].height)))
    {
      direction = NONE ;
      down = RIGHT_DOWN ;
      itemno = n ;
      if ((reply = do_menu((enum panel_type) itemno)))
        {                                                   
          nextc = RIGHT_UP ;                                
          handle_item(reply - 1) ;
          draw_cycle((enum panel_type) itemno, C_LGREY, CY_NORMAL) ;
        }
    }
}


check_item_down()
{
  int n ;

  for (n = 0; n < MAXITEMS; n++)
    switch (items[n].type)
      {
        case P_BUTTON  : check_button_down((enum panel_type) n) ;
                         break ;
        case P_CYCLE   : check_cycle_down((enum panel_type) n) ;
                         break ;
        case P_MESSAGE : /* do nothing. */ ;
      }
}


check_item_up()
{
  if ((nextc == LEFT_UP   && down == LEFT_DOWN)   ||
      (nextc == MIDDLE_UP && down == MIDDLE_DOWN) ||
      (nextc == RIGHT_UP  && down == RIGHT_DOWN))
    {
      if (items[itemno].type == P_BUTTON && but_inverted == -1) return ;
      handle_item(items[itemno].value) ;
      if (items[itemno].type == P_BUTTON)
        draw_button((enum panel_type) itemno, C_LGREY, BUT_NORMAL) ;
      else if (items[itemno].type == P_CYCLE)
        draw_cycle((enum panel_type) itemno, C_LGREY, CY_NORMAL) ;
    } 
}


do_action()
{
  switch (nextc)
    {
      case MOUSE_MOVING : draw_piece(next_player, piece_x, piece_y, RINV) ;
                          piece_x = curx - PIECE_RAD ;
                          piece_y = cury - PIECE_RAD ;
                          draw_piece(next_player, piece_x, piece_y, RINV) ;
                          break ;
                          
      case ENTER_WINDOW : 
      case EXIT_WINDOW  : set_cursor(CANVASCUR) ;
                          draw_piece(next_player, piece_x, piece_y, RINV) ;
                          cmode = (enum cantype) ((int) cmode - 1) ;
                          break ;
                          
      case LEFT_DOWN    : 
      case LEFT_UP      :
      case MIDDLE_DOWN  :
      case MIDDLE_UP    :
      case RIGHT_DOWN   :
      case RIGHT_UP     : set_cursor(CANVASCUR) ;
                          do_selection(nextc) ;
    }                 
}


do_cycle_key(item, ch)
enum panel_type item ;
int ch ;
{
  int val ;

  if (!validkey)
    {
      validkey = cur_ch ;
      message(PANEL_MES, items[(int) item].text) ;
    }
  else
    {
      val = -1 ;
      switch (item)
        {
          case ASPIRATION     : if (ch >= '1' && ch <= '6') val = ch - '1' ;
                                break ;
          case COMPUTER_PLAYS : switch (ch)
                                  {
                                    case 'b' :
                                    case 'B' : val = 0 ;
                                               break ;
                                    case 'w' :
                                    case 'W' : val = 1 ;
                                               break ;
                                    default  : return ;
                                  }
                                break ;
          case DIFFICULTY     : if (ch >= '1' && ch <= '4') val = ch - '1' ;
                                break ;
          case REMARK         : switch (ch)
                                  {
                                    case 'n' :
                                    case 'N' : val = 0 ;
                                               break ;
                                    case 'y' :
                                    case 'Y' : val = 1 ;
                                               break ;
                                    default  : return ;
                                  }
        }
      if (val != -1)
        {
          validkey = 0 ;
          message(PANEL_MES, "") ;
          if (item == COMPUTER_PLAYS && val == items[(int) item].value)
            return ;
          items[(int) item].value = item_value = val ;
          direction = NONE ;
          (*items[(int) item].func)() ;
        }
    }
}


do_key_move(n1, n2)
int n1, n2 ;
{
  move = (n2 - '1') * BOARD_SIZE + (n1 - 'a') ;
  next_player = (int) cmode - 1 ;
  cmode = (enum cantype) ((int) cmode + 1) ;
  make_move() ;
  validkey = 0 ;
}


get_xy(n, x, y)      /* Return piece coordinates given board index. */
int n, *x,*y ;
{
  *x = (n & 7) * CELL_SIZE + BBORDER + PIECE_MARGIN ;
  *y = (n >> 3) * CELL_SIZE + BBORDER + PIECE_MARGIN ;
}


handle_board_event()
{
  switch (cmode)
    {
      case WHITE_START  :
      case BLACK_START  : next_player = (int) cmode - 1 ;
                          if (nextc == LEFT_DOWN || nextc == MIDDLE_DOWN ||
                              nextc == RIGHT_DOWN)
                            {
                              set_cursor(NOCURSOR) ;
                              piece_x = curx - BBORDER - (PIECE_RAD) ;
                              piece_y = cury - BBORDER - (PIECE_RAD) ;
                              draw_piece(next_player, piece_x, piece_y, RINV) ;
                              cmode = (enum cantype) ((int) cmode + 1) ;
                            }
                          break ;
      case WHITE_MOVING :
      case BLACK_MOVING : do_action() ;
    }
}


handle_event()
{
  process_event() ;

       if (nextc == FRAME_REPAINT) init_canvas() ;
  else if (nextc == KEYBOARD)      handle_key() ;
  else if (nextc == EXIT_WINDOW && but_inverted != -1)
    {
      draw_button((enum panel_type) but_inverted, C_LGREY, BUT_NORMAL) ;
      but_inverted = -1 ;
      down = 0 ;
    }
  else if (cury > (CY + BBORDER)) handle_board_event() ;
  else if (nextc == LEFT_UP || nextc == MIDDLE_UP || nextc == RIGHT_UP)
    check_item_up() ;
  else if (nextc == LEFT_DOWN || nextc == MIDDLE_DOWN || nextc == RIGHT_DOWN)
    check_item_down() ;
}


handle_item(val)
int val ;
{
  items[itemno].value = item_value = val ;
  (*items[itemno].func)() ;
  but_inverted = -1 ;
  down = 0 ;
}


handle_key()     /* Process the latest key that the user has pressed. */
{
  char str[9] ;  /* To display half move position. */
  int nextc ;

  if (cur_ch == ESCAPE) validkey = 0 ;
  if (validkey)
    {
      nextc = cur_ch ;
      cur_ch = validkey ;
    }
  switch (cur_ch)
    {
      case 'A' : do_cycle_key(ASPIRATION, nextc) ;
                 break ;
      case 'C' : do_cycle_key(COMPUTER_PLAYS, nextc) ;
                 break ;
      case 'D' : do_cycle_key(DIFFICULTY, nextc) ;
                 break ;
      case 'r' :
      case 'R' : do_cycle_key(REMARK, nextc) ;
                 break ;
      case 'l' :
      case 'L' : last() ;
                 break ;
      case 'n' :
      case 'N' : new_game() ;
                 break ;
      case 'q' :
      case 'Q' : quit() ;
      case 's' :
      case 'S' : suggest() ;
                 break ;
      case 'u' :
      case 'U' : undo() ;
                 break ;
      case '1' :
      case '2' :
      case '3' :
      case '4' :
      case '5' :
      case '6' :
      case '7' :
      case '8' : if (!validkey)
                   {
                     validkey = cur_ch ;
                     SPRINTF(str, "Move: %c", cur_ch) ;
                     message(PANEL_MES, str) ;
                   }
                 else if (nextc >= 'a' && nextc <= 'h')
                   {
                     SPRINTF(str, "Move: %c%c", cur_ch, nextc) ;
                     message(PANEL_MES, str) ;
                     do_key_move(nextc, cur_ch) ;
                   }
                 else validkey = 0 ;
                 break ;
      case 'a' :
      case 'b' :
      case 'c' :
      case 'd' :
      case 'e' :
      case 'f' :
      case 'g' :
      case 'h' : if (!validkey)
                   {
                     validkey = cur_ch ;
                     SPRINTF(str, "Move: %c", cur_ch) ;
                     message(PANEL_MES, str) ;
                   }
                 else if (nextc >= '1' && nextc <= '8')
                   {
                     SPRINTF(str, "Move: %c%c", cur_ch, nextc) ;
                     message(PANEL_MES, str) ;
                     do_key_move(cur_ch, nextc) ;
                   }
                 else validkey = 0 ;
                 break ;
      default  : message(PANEL_MES, "") ;
                 validkey = 0 ;
    }
}
