/***** All content © 2010 DigiPen (USA) Corporation, all rights reserved. ****/
/*! \file    TicTacToe.c
**  \author  Nathan Williams
**  \par     email: nwilliam\@digipen.edu
**  \date    04/10/2010
**  \brief   Implementation of Tic-Tac-Toe.
*
*            Game Rules: Standard gameplay, 3x3 board with Xs and Os.
*
*            Board:   0 | 1 | 2
*                   -------------
*                     3 | 4 | 5
*                   -------------
*                     6 | 7 | 8
*
*            Move String: [int]
*                         Represents board position being played.
*******************************************************************************/

#include <string.h> /* strlen */
#include <stdlib.h> /* calloc, free */

#include "PluginCommon.h"
#include "PluginInterface.h"

#include "TicTacToe.h"

int Init(void)
{
  /* Nothing to do */
  return 0;
}

void Shutdown(void)
{
}

const char* Name(void)
{
  return "Tic-Tac-Toe";
}

const char* Author(void)
{
  return "nlw";
}

const char* Type(void)
{
  return "TicTacToe";
}

const char* Version(void)
{
  return "0.1";
}

const char* APIVersion(void)
{
  return "0.1";
}

int NumberOfPlayers(void)
{
  return 2;
}

void* CreateGame(void)
{
  struct Game* newGame = (struct Game *)calloc(1, sizeof(struct Game));
  if(newGame)
    newGame->status = PLUGIN_GAME_STATUS_CREATED;
  return newGame;
}

int SetGameOption(void* igame, const char* option)
{
  /* No options for this game */
  (void)igame;
  (void)option;

  return 1;
}

int AddPlayer(void* igame, void* player)
{
  struct Game* game = (struct Game *)igame;

  if(game->players[0] == NULL)
    game->players[0] = player;
  else if(game->players[1] == NULL)
    game->players[1] = player;
  else
    return 1;

  return 0;
}

int RemovePlayer(void* igame, void* player)
{
  struct Game* game = (struct Game *)igame;

  if(game->players[0] == player)
    game->players[0] = NULL;
  else if(game->players[1] == player)
    game->players[1] = NULL;
  else
    return 1;

  if(game->status == PLUGIN_GAME_STATUS_PLAYING)
    game->status = PLUGIN_GAME_STATUS_PAUSED;

  return 0;
}

int PlayerCount(void* igame)
{
  struct Game* game = (struct Game *)igame;
  return (game->players[0] != 0) + (game->players[1] != 0);
}

void* GetPlayer(void* igame, int playerNumber)
{
  struct Game* game = (struct Game *)igame;

  if(playerNumber == 1 || playerNumber == 2)
    return game->players[playerNumber-1];

  return NULL;
}

int GetPlayerNumber(void* igame, void* player)
{
  struct Game* game = (struct Game *)igame;

  if(game->players[0] == player)
    return 1;

  if(game->players[1] == player)
    return 2;

  return 0;
}

int StartGame(void* igame)
{
  struct Game* game = (struct Game *)igame;

  if(PlayerCount(game) != 2)
    return 1;

  game->nextPlayer = 1;
  game->status = PLUGIN_GAME_STATUS_PLAYING;

  return 0;
}

void* GetNextPlayer(void* igame)
{
  struct Game* game = (struct Game *)igame;

  if(game->nextPlayer > 0)
    return game->players[game->nextPlayer-1];

  return NULL;
}

int ValidateMove(void* igame, void* player, const char* move)
{
  struct Game* game = (struct Game *)igame;
  char* board = game->board;
  int i, movePos;

  int wins[8][3] = { {0,1,2},  {3,4,5},  {6,7,8},     /* Horizontal */
                     {0,3,6},  {1,4,7},  {2,5,8},     /* Vertical */
                     {0,4,8},  {2,4,6}            };  /* Diagonal */

  /* Sanity check */
  if(move == NULL || strlen(move) != 1 || game->status != PLUGIN_GAME_STATUS_PLAYING)
    return -1;

  movePos = move[0] - '0';

  /* Check out of range or already played */
  if(movePos < 0 || movePos > 8 || board[movePos] != 0)
    return -1;

  if(game->players[0] == player)
  {
    board[movePos] = 'X';
    game->nextPlayer = 2;
  }
  else
  {
    board[movePos] = 'O';
    game->nextPlayer = 1;
  }

  /* Check for winner or draw */
  for(i = 0; i < 8; ++i)
  {
    if(board[wins[i][0]] == board[wins[i][1]] &&
       board[wins[i][0]] == board[wins[i][2]] &&
       board[wins[i][0]] != 0)
    {
      game->nextPlayer = GetPlayerNumber(igame, player);
      game->status = PLUGIN_GAME_STATUS_OVER_WINNER;
      return 0;
    }
  }

  /* Check for draw */
  if(board[0] && board[1] && board[2] && board[3] && board[4] &&
     board[5] && board[6] && board[7] && board[8])
  {
    game->nextPlayer = 0;
    game->status = PLUGIN_GAME_STATUS_OVER_DRAW;
  }

  return 0;
}

int GetGameStatus(void* igame)
{
  struct Game* game = (struct Game *)igame;
  return game->status;
}

void DestroyGame(void* igame)
{
  free(igame);
}