/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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 the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include <pspctrl.h>
#include <psptypes.h>
#include <png.h>

#include "psp_sdl.h"
#include "psp_global.h"
#include "psp_kbd.h"
#include "psp_go.h"
#include "gnugo.h"
#include "psp_menu.h"
#include "psp_play.h"

  static int psp_go_board_dirty   = 1;

static void
psp_go_get_pix_xy(int x, int y, int *px_pix, int *py_pix)
{
  int square_width_pix = 272 / (GGO.board_width + 1);
  int board_width_pix  = square_width_pix * (GGO.board_width - 1);
  int x_orig = (480 - board_width_pix) / 2;
  int y_orig = (272 - board_width_pix) / 2;
  
  *px_pix = x_orig + (x * square_width_pix);
  *py_pix = y_orig + ((GGO.board_width - 1 - y) * square_width_pix);
}

static void
psp_go_display_handicap_xy(int x, int y)
{
  int x_pix = 0;
  int y_pix = 0;

  psp_go_get_pix_xy(x, y, &x_pix, &y_pix);

  psp_sdl_put_pixel(x_pix - 1, y_pix - 1, GGO.board_color);
  psp_sdl_put_pixel(x_pix + 1, y_pix - 1, GGO.board_color);
  psp_sdl_put_pixel(x_pix + 1, y_pix + 1, GGO.board_color);
  psp_sdl_put_pixel(x_pix - 1, y_pix + 1, GGO.board_color);
}

static void
psp_go_display_handicap()
{
  int boardsize = GGO.board_width;

  /* Display handicap */
  if (boardsize == 5) {

    psp_go_display_handicap_xy(1, 1);
    psp_go_display_handicap_xy(3, 1);
    psp_go_display_handicap_xy(1, 3);
    psp_go_display_handicap_xy(3, 3);
    psp_go_display_handicap_xy(2, 2);
    
    return;
  }

  if (!(boardsize%2)) {
    /* If the board size is even, no center handicap spots. */
    if (boardsize > 2 && boardsize < 12) {
      /* Place the outer 4 only. */
      psp_go_display_handicap_xy(2,2);
      psp_go_display_handicap_xy(boardsize - 3,2);
      psp_go_display_handicap_xy(2,boardsize - 3);
      psp_go_display_handicap_xy(boardsize-3,boardsize - 3);
    }
    else {
      /* Place the outer 4 only. */
      psp_go_display_handicap_xy(3,3);
      psp_go_display_handicap_xy(boardsize - 4,3);
      psp_go_display_handicap_xy(3, boardsize - 4);
      psp_go_display_handicap_xy(boardsize - 4, boardsize - 4);
    }
  }
  else {
    /* Uneven board size */
    if (boardsize > 2 && boardsize < 12) {
      /* Place the outer 4... */
      psp_go_display_handicap_xy(2,2);
      psp_go_display_handicap_xy(boardsize-3,2);
      psp_go_display_handicap_xy(2, boardsize-3);
      psp_go_display_handicap_xy(boardsize-3, boardsize-3);

      /* ...and the middle one. */
      psp_go_display_handicap_xy(boardsize/2, boardsize/2);
    }
    else {
      /* Place the outer 4... */
      psp_go_display_handicap_xy(3,3);
      psp_go_display_handicap_xy(boardsize - 4,3);
      psp_go_display_handicap_xy(3, boardsize - 4);
      psp_go_display_handicap_xy(boardsize - 4, boardsize - 4);

      /* ...and the inner 4... */
      psp_go_display_handicap_xy(3, boardsize/2);
      psp_go_display_handicap_xy(boardsize/2, 3);
      psp_go_display_handicap_xy(boardsize/2, boardsize-4);
      psp_go_display_handicap_xy(boardsize-4, boardsize/2);

      /* ...and the middle one. */
      psp_go_display_handicap_xy(boardsize/2, boardsize/2);
    }
  }
}

int
psp_go_is_computer_move()
{
  return (GGO.gameinfo.computer_player == GGO.gameinfo.to_move);
}

void
psp_go_display_board()
{
  char buffer[32];
  int  x_orig;
  int  y_orig;
  int  x_dst;
  int  y_dst;
  int  x_pix;
  int  y_pix;
  int  x;
  int  y;
  char letter;

  int square_width_pix = 272 / (GGO.board_width + 1);
  int board_width_pix  = square_width_pix * (GGO.board_width - 1);

  x_orig = (480 - board_width_pix) / 2;
  y_orig = (272 - board_width_pix) / 2;

  psp_sdl_blit_board();

  psp_sdl_draw_rectangle(x_orig, y_orig,
                         board_width_pix, board_width_pix, GGO.board_color, 0);

  for (y = GGO.board_width; y > 0; y--) {
    x_dst = x_orig;
    y_dst = y_orig + ((GGO.board_width - y) * square_width_pix);

    if (y != 0)  {
      psp_sdl_fill_rectangle(x_dst, y_dst, board_width_pix, 0, GGO.board_color, 0);
    }

    sprintf(buffer, "%-2d", y);
    x_dst -= square_width_pix;
    if (GGO.board_width >= 10) x_dst -= square_width_pix;
    psp_sdl_print(x_dst, y_dst - 4, buffer, GGO.board_color);

    sprintf(buffer, "%2d", y);
    x_dst = x_orig + board_width_pix;
    x_dst += square_width_pix;
    psp_sdl_print(x_dst, y_dst - 4, buffer, GGO.board_color);
  }

  for (x = 0; x < GGO.board_width; x++) {
    x_dst = x_orig + (x * square_width_pix);
    y_dst = y_orig;

    letter = 'A' + x;
    if (letter >= 'I') letter++;

    psp_sdl_fill_rectangle(x_dst, y_dst, 0, board_width_pix, GGO.board_color, 0);

    y_dst = y_orig - (square_width_pix / 2) - 8;
    if (y_dst <= 0) y_dst = 1;
    psp_sdl_put_char(x_dst - 3, y_dst, GGO.board_color, 0, letter, 1, 0);

    y_dst = y_orig + board_width_pix;
    psp_sdl_put_char(x_dst - 3, y_dst + (square_width_pix / 2), GGO.board_color, 0, letter, 1, 0);
  }

  psp_go_display_handicap();

  for (y = 0; y < GGO.board_width; y++) {
    for (x = 0; x < GGO.board_width; x++) {

      int index = (y*GGO.board_width) + x;
      if (GGO.board_array[index] == GGO_EMPTY) continue;

      int stone_is_black = (GGO.board_array[index] == GGO_BLACK);
      int last_move = ((GGO.last_move_x == x) && (GGO.last_move_y == y));

      psp_go_get_pix_xy(x, y, &x_pix, &y_pix);
      psp_sdl_blit_node_xy(x_pix, y_pix, stone_is_black, last_move);
    }
  }

  if (psp_go_is_computer_move()) {
    psp_sdl_print(5, 5, "Thinking ...", PSP_MENU_RED_COLOR);
  } else {
    psp_go_get_pix_xy(GGO.current_x, GGO.current_y, &x_pix, &y_pix);
    psp_sdl_blit_ghost_xy(x_pix, y_pix, GGO.go_player_color == GGO_BLACK);
  }
}

void
psp_go_go_down()
{
  GGO.current_y--; 
  if (GGO.current_y < 0) GGO.current_y = GGO.board_width - 1;
  psp_go_board_dirty = 1;
}

void
psp_go_go_up()
{
  GGO.current_y++; 
  if (GGO.current_y >= GGO.board_width) GGO.current_y = 0;
  psp_go_board_dirty = 1;
}

void
psp_go_go_left()
{
  GGO.current_x--; 
  if (GGO.current_x < 0) GGO.current_x = GGO.board_width - 1;
  psp_go_board_dirty = 1;
}

void
psp_go_go_right()
{
  GGO.current_x++; 
  if (GGO.current_x >= GGO.board_width) GGO.current_x = 0;
  psp_go_board_dirty = 1;
}

# define ANALOG_THRESHOLD 30

void 
psp_go_get_analog_direction(int Analog_x, int Analog_y, int *x, int *y)
{
  int DeltaX = 255;
  int DeltaY = 255;
  int DirX   = 0;
  int DirY   = 0;

  *x = 0;
  *y = 0;

  if (Analog_x <=        ANALOG_THRESHOLD)  { DeltaX = Analog_x; DirX = -1; }
  else 
  if (Analog_x >= (255 - ANALOG_THRESHOLD)) { DeltaX = 255 - Analog_x; DirX = 1; }

  if (Analog_y <=        ANALOG_THRESHOLD)  { DeltaY = Analog_y; DirY = -1; }
  else 
  if (Analog_y >= (255 - ANALOG_THRESHOLD)) { DeltaY = 255 - Analog_y; DirY = 1; }

  *x = DirX;
  *y = DirY;
}

void
psp_go_new_game()
{
  psp_global_reset();
  psp_play_reset();
}


void
psp_go_game_over()
{
  psp_go_display_board();

  float score = gnugo_estimate_score(NULL, NULL);
  char  buffer[128];
  int   you_win = 0;

  if (score == 0.0) {
    sprintf(buffer, "No winner, Jigo");
  } else {

    if (score > 0.0) { /* White wins */

      if (GGO.go_player_color == GGO_WHITE) you_win = 1;
      else                                  you_win = 0;

    } else { /* Black wins */

      if (GGO.go_player_color == GGO_WHITE) you_win = 0;
      else                                  you_win = 1;
      score = - score;
    }

    if (you_win) {
      sprintf(buffer, "You win with %d", (int)score);
    } else {
      sprintf(buffer, "AI GNU-Go wins with %d", (int)score);
    }
  }
  psp_sdl_back3_rectangle(100, 110, 280, 45);
  psp_sdl_draw_rectangle(100, 110, 280, 45, 0, 0);
  psp_sdl_print(135,  125, buffer, PSP_MENU_RED_COLOR);
  psp_sdl_print(135,  135, "Game over, press start ...", PSP_MENU_RED_COLOR);
  psp_sdl_flip();

  psp_kbd_wait_start();
  psp_go_board_dirty = 1;

  psp_go_new_game();
}


void
psp_go_main_loop()
{
  SceCtrlData c;
  long        new_pad;
  long        old_pad;
  int         last_time;

  int new_Lx;
  int new_Ly;

  old_pad   = 0;
  last_time = 0;

  psp_main_menu();

  while (1) {

    do {

      if (GGO.psp_screenshot_mode) {
        GGO.psp_screenshot_mode = 0;
        psp_go_display_board();
        psp_sdl_flip();
        psp_go_display_board();
        psp_sdl_flip();
        psp_sdl_save_screenshot();
      }

      if (psp_go_board_dirty) {
        psp_go_board_dirty = 0;
        psp_go_display_board();
        psp_sdl_flip();
      }

      if (psp_go_is_computer_move()) {

        if (! psp_play_computer_move()) {
          /* Game OVER ! */
          GGO.passes = 2;
        } else {
          psp_go_display_board();
          psp_sdl_flip();
        }
      }

      if (GGO.passes >= 2) {
        /* Game OVER ! */
        psp_go_game_over();
      }

    } while (psp_go_board_dirty);

    while (1)
    {
      sceCtrlReadBufferPositive(&c, 1);

      /* Check Analog Device */
      psp_go_get_analog_direction( c.Lx, c.Ly, &new_Lx, &new_Ly);
      if (new_Lx || new_Ly || c.Buttons)  break;
    }

    new_pad = c.Buttons;

    if (new_pad) {
      if ((old_pad != new_pad) || ((c.TimeStamp - last_time) > PSP_GO_MIN_TIME)) {
        last_time = c.TimeStamp;
        old_pad = new_pad;
      } else continue;

    } else {
      if ((c.TimeStamp - last_time) > PSP_GO_MIN_ANALOG_TIME) {
        last_time = c.TimeStamp;
      } else continue;
    }

    if ((c.Buttons & (PSP_CTRL_LTRIGGER|PSP_CTRL_RTRIGGER|PSP_CTRL_START)) ==
        (PSP_CTRL_LTRIGGER|PSP_CTRL_RTRIGGER|PSP_CTRL_START)) {
      /* Exit ! */
      psp_sdl_exit(0);
    } else
    if((new_pad & PSP_CTRL_SELECT) == PSP_CTRL_SELECT) {
      psp_main_menu();
      psp_go_board_dirty = 1;
    } else {

      if (new_pad & PSP_CTRL_CROSS) {

        if (psp_play_player_move()) {
          psp_go_board_dirty = 1;
        }

      }
      if (new_pad & PSP_CTRL_CIRCLE) {

        if (psp_play_player_pass(0)) {
          psp_go_board_dirty = 1;
        }
      }
      if (new_pad & PSP_CTRL_TRIANGLE) {
        /* TO_BE_DONE ! */
      }
      if(new_pad & PSP_CTRL_SQUARE) {
        /* TO_BE_DONE ! */
      }
      if ((new_pad & PSP_CTRL_UP) || (new_Ly < 0)) {
        psp_go_go_up();
      }
      if ((new_pad & PSP_CTRL_DOWN) || (new_Ly > 0)) {
        psp_go_go_down();
      }
      if ((new_pad & PSP_CTRL_LEFT) || (new_Lx < 0)) {
        psp_go_go_left();
      }
      if ((new_pad & PSP_CTRL_RIGHT) || (new_Lx > 0)) {
        psp_go_go_right();
      }
    }
# if 0
    sceKernelDelayThread(1000); 
    GGO.board_width--;
    if (GGO.board_width < GGO.board_min_width) GGO.board_width = GGO.board_max_width;
# endif
  }
}

int 
SDL_main(int argc,char *argv[])
{
  psp_sdl_init();
  psp_global_init();
  psp_play_init();

  psp_go_main_loop();

  psp_sdl_exit(0);

  return 0;
}
