#ifndef _MFG_AI_INTERFACE_
#define _MFG_AI_INTERFACE_

#include <windows.h>

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the AI_INTERFACE_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// AI_INTERFACE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.

#ifdef AI_INTERFACE_EXPORTS
#define AI_INTERFACE_API __declspec(dllexport)
#else
#define AI_INTERFACE_API __declspec(dllimport)
#endif

/* piece colors */
  /** Plays on top setup zone (0,0) -> (9, 3) & goes first. */
  #define COLOR_RED 0;

  /** Plays on bottom setup zone (0,6) -> (9, 9) & goes second. */
  #define COLOR_BLUE 1;

  /* player turn result */
  /** Player forfeits. */
  #define TURN_RESULT_PLAYER_FORFEITS -3;

  /** Player loses turn. */
  #define TURN_RESULT_PLAYER_LOST_TURN -2;

  /** Player requests draw. */
  #define TURN_RESULT_PLAYER_REQUESTS_DRAW -1;
  
  /** No battle result from move. */
  #define MOVE_RESULT_NONE 0;

  /** Piece that did not move (defender) is killed. */
  #define MOVE_RESULT_KILL 1;

  /** Piece that moved (attacker) is killed. */
  #define MOVE_RESULT_KILLED 2;

  /** Both attacker and defender are killed. */
  #define MOVE_RESULT_BOTH_KILLED 3;

  #define GAME_RESULT_LOSS 0;
  
  #define GAME_RESULT_WIN 1;
  
  #define GAME_RESULT_DRAW 2;
  
  /** Game is forced to end, perhaps by admin or system error. */
  #define GAME_RESULT_FORCED_END 3;
  
  /** End for unknown reason. */
  #define GAME_REASON_UNKNOWN  -1;
  
  /** End by a capturing flag. */
  #define GAME_REASON_FLAG_CAPTURED 0;

  /** End by player forfeiting. */
  #define GAME_REASON_FORFEIT = 1;

  /** End by opponent disconnecting. */
  #define GAME_REASON_DISCONNECT = 2;

  /** End by unable to move. */
  #define GAME_REASON_UNABLE_TO_MOVE = 3;

  /** End by timing out. */
  #define GAME_REASON_TIMED_OUT = 4;
  
  /** Rank for Marshal */
  #define RANK_MARSHAL 0;

  /** Rank for General */
  #define RANK_GENERAL 1;

  /** Rank for Colonel */
  #define RANK_COLONEL 2;

  /** Rank for Major */
  #define RANK_MAJOR 3;

  /** Rank for Captain */
  #define RANK_CAPTAIN 4;

  /** Rank for Lieutenant */
  #define RANK_LIEUTENANT 5;

  /** Rank for Sergeant */
  #define RANK_SERGEANT 6;

  /** Rank for Miner */
  #define RANK_MINER  7;

  /** Rank for Scout */
  #define RANK_SCOUT  8;

  /** Rank for Spy */
  #define RANK_SPY  9;

  /** Rank for Bomb */
  #define RANK_BOMB  10;

  /** Rank for Flag */
  #define RANK_FLAG  11;

  /** Rank is unknown. */
  #define RANK_UNKNOWN  12;

  /** There is no piece at (x,y). */
  #define RANK_EMPTY  13;

  /** The square at (x,y) is impassible, such as a lake. */
  #define RANK_IMPASSIBLE  14;

  // game options

  /** One-time bombs bitflag. */
  #define GAMEOPT_ONE_TIME_BOMBS  0x01;

  /** Radius bombs bitflag. */
  #define GAMEOPT_RADIUS_BOMBS  0x02;

  /** Secrecy bitflag. */
  #define GAMEOPT_SECRECY  0x04;

  /** Complete visibility bitflag. */
  #define GAMEOPT_COMPLETE_VISIBILITY  0x08;

  /** Range attack bitflag. */
  #define GAMEOPT_RANGE_ATTACK  0x10;

  /** Economy bitflag. */
  #define GAMEOPT_ECONOMY  0x20;

  /** Movable flag bitflag. */
  #define GAMEOPT_MOVABLE_FLAG  0x40;

  /** Aggression bitflag. */
  #define GAMEOPT_AGGRESSION  0x80;

  /** Super-spy bitflag. */
  #define GAMEOPT_SUPER_SPY  0x100;

  /** Mobility bitflag. */
  #define GAMEOPT_MOBILITY  0x200;

  /** Blitzkrieg bitflag. */
  #define GAMEOPT_BLITZKRIEG  0x400;

  /** Visible flag bitflag. */
  #define GAMEOPT_VISIBLE_FLAG  0x800;

  /** Remain visible bitflag. */
  #define GAMEOPT_REMAIN_VISIBLE  0x1000;

  /** Rescue bitflag. */
  #define GAMEOPT_RESCUE  0x2000;

  /** Probability kill bitflag. */
  #define GAMEOPT_PROBABILITY_KILL  0x4000;

  // set game modes

  /** Classic Stratego, played with 40 pieces and standard rules. */
  #define GAMEMODE_CLASSIC 0;

  /** Barrage Stratego, played with 8 pieces and standard rules. */
  #define GAMEMODE_BARRAGE 1;

  /** Ultimate Lightning, played with 20 pieces and modified rules. */
  #define GAMEMODE_ULTIMATE_LIGHTNING 2;

  /** Peloton (Duell) Stratego, played with 10 pieces and standard rules. */
  #define GAMEMODE_PELOTON  3;

  /** RPS Stratego, played with 7s, 8s, and bombs where bombs can move. */
  #define GAMEMODE_ROCK_PAPER_SCISSORS  4;

  /** Custom mode (not yet supported). */
  #define GAMEMODE_CUSTOM  5;

  // special field values for last entry of AI move

  /** No special component to the AI move. */
  #define AI_SPECIAL_MOVE_NOTHING  0;

  /** AI requests draw. */
  #define AI_SPECIAL_MOVE_REQUEST_DRAW  1;

  /** AI accepts draw request if one has been offered. */
  #define AI_SPECIAL_MOVE_ACCEPT_DRAW  2;

  /** AI resigns. */
  #define AI_SPECIAL_MOVE_RESIGN  3;

  /** AI accepts draw request if one has been offered. */
  #define AI_SPECIAL_MOVE_REJECT_DRAW 4;
  
  /** AI passes.  This is legal only if the preceding opponent move was a turn timeout. */
  #define AI_SPECIAL_MOVE_PASS_TURN = 5;

  // skill level

  /** Beginner level. */
  #define LEVEL_BEGINNER  0;

  /** Intermediate level. */
  #define LEVEL_INTERMEDIATE  1;

  /** Expert level. */
  #define LEVEL_EXPERT  2;

  /** Tournament (highest) level. */
  #define LEVEL_TOURNAMENT  3;

  /** Constant to denote that an option is off. */
  #define OPTION_OFF  0;

  /** Constant to denote that an option is on. */
  #define OPTION_ON  1;

#ifdef __cplusplus
extern "C" {
#endif

  /**
   * Called by the bot to tell the AI that it is aborting the game prior to start.
   * 
   * @param reason
   *          the reason for aborting the game.
   */
  AI_INTERFACE_API void __stdcall abortGame(int reason);

  /**
   * Called to initialize the setup process RED sets his pieces on rows 0-3 and BLUE sets his pieces
   * on rows 6-9 RED starts the game.
   * 
   * @param color
   *          the color RED or BLUE which the AI will play as.
   */
  AI_INTERFACE_API void __stdcall createAISetup(int color);

  /**
   * Asks the AI whether it would like to create a game. If so, the AI is then asked for the mode &
   * options of the game.
   * 
   * @return <em>true</em> if AI would like to create a game, <em>false</em> if not.
   */
  AI_INTERFACE_API int __stdcall createGame(void);

  /**
   * Tells the AI that the game it wanted to create has been created.
   */
  AI_INTERFACE_API void __stdcall gameCreated(void);

  /**
   * Tells the AI that the game it wanted to join has been joined.
   */
  AI_INTERFACE_API void __stdcall gameJoined(void);

  /**
   * Called for each field of the setup and should return the rank of the piece on field (x,y) in
   * the AI's setup, or EMPTY if no piece.
   * 
   * @param x
   *          x coordinate on board.
   * @param y
   *          y coordinate on board.
   * @return rank of piece located at (x,y) or EMPTY if none.
   */
  AI_INTERFACE_API int __stdcall getAISetupPiece(int x, int y);

  /**
   * Ask the AI what mode game it would like to create.
   * 
   * @return a valid game mode for the game to create.
   * @see #createGame
   * @see #getCreateGameOption
   */
  AI_INTERFACE_API int __stdcall getCreateGameMode(void);

  /**
   * Ask the AI for the value of the specified option. If the option is one the AI does not
   * recognize, it should return {@link #OPTION_OFF}.
   * 
   * @param option
   *          the option whose value we would like to know.
   * @return AI's desired value for the game option in question.
   * @see #createGame
   * @see #getCreateGameMode
   */
  AI_INTERFACE_API int __stdcall getCreateGameOption(int option);

  /**
   * Asks the AI if it wants to send an in game chat message once the game has entered setup mode.
   * 
   * @return a string to send via game chat, or null if none.
   */
  AI_INTERFACE_API const char * __stdcall getPreGameChat(void);

  /**
   * Asks the AI if it wants to send a chat message after the game has ended.
   * 
   * @return a string to send via chat, or null if none.
   */
  AI_INTERFACE_API const char * __stdcall getPostGameChat(void);

  /**
   * Returns the name by which the AI wishes to be known.
   * 
   * @return the name by which the AI wishes to be known.
   */
  AI_INTERFACE_API const char * __stdcall getPublicName(void);

  /**
   * Tells the AI that the game is over.
   * 
   * @param result
   *          result of the game (WIN, LOSS, DRAW)
   * @param reason
   *          reason for game ending (enumerations to follow... capture flag, resign, can't move,
   *          etc)
   */
  AI_INTERFACE_API void __stdcall endGame(int result, int reason);

  /**
   * Requests the next AI Move. The result is an array with 4 numbers:
   * <ul>
   * <li>result[0] => x coordinate from field</li>
   * <li>result[1] => y coordinate from field</li>
   * <li>result[2] => x coordinate to field</li>
   * <li>result[3] => y coordinate to field</li>
   * <li>result[4] => special (for draw requests or resignations)</li>
   * </ul>
   * 
   * @param move
   *          array passed in by bot which AI populates with its move as specified above.
   */
  AI_INTERFACE_API void __stdcall getAIMove(BYTE *move);

  /**
   * Tells AI that the last move submitted was illegal.
   * 
   * @param move
   *          the move array last returned by the AI.
   */
  AI_INTERFACE_API BYTE __stdcall illegalMove(BYTE *move);

  /**
   * Tells AI that the last setup (x,y,rank) returned was illegal. After calling this method, the
   * bot will exit the game.
   * 
   * @param x
   *          x coordinate of last setup piece returned by AI.
   * @param y
   *          y coordinate of last setup piece returned by AI.
   * @param rank
   *          rank of piece from last setup piece returned by AI.
   */
  AI_INTERFACE_API void __stdcall illegalSetup(int x, int y, int rank);

  /**
   * Notifies the AI that it has been constructed and should do any initialization that is required.
   * If the return value is <em>false</em>, the bot will call terminate, logoff of the server,
   * and shutdown the application.
   * 
   * @return <em>true</em> on success, <em>false</em> on failure.
   * @see #terminate
   */
  AI_INTERFACE_API int __stdcall initialize(const char *password);

  /**
   * Tells the AI that options are all set and the AI will then be asked for its setup.
   */
  AI_INTERFACE_API void __stdcall initializeGame(void);

  /**
   * Asks the AI whether it wants to join the most recently described game. This will occur after
   * notification of the game and its options. Note that an AI is expected to not join a game that
   * it is incapable of playing!
   * 
   * @return <em>true</em> if AI wants to join, <em>false</em> if not.
   * @see #newGameCreated
   * @see #newGameOption
   */
  AI_INTERFACE_API int __stdcall joinGame(void);

  /**
   * Tells the AI that a new game has been created. This will be followed by calls to newGameOption
   * and joinGame. AI should return <em>false</em> if it is not interested in joining this game,
   * or <em>true</em> if it wants more information before deciding.
   * 
   * @param owner
   *          owner of the new game.
   * @param mode
   *          mode of the new game.
   * @return <em>false</em> if the AI is not interested in joining, <em>true</em> if the AI
   *         wants more information about the game before deciding.
   * @see #newGameOption
   * @see #joinGame
   */
  AI_INTERFACE_API int __stdcall newGameCreated(const char *owner, int mode);

  /**
   * Tells the AI about the options for the most recently created game. Multiple calls of this
   * method will be made after newGameCreated and before joinGame.
   * 
   * @param option
   *          the option.
   * @param value
   *          its value.
   * @return <em>false</em> if the AI is not interested in joining, <em>true</em> if the AI
   *         wants more information about the game before deciding.
   * @see #newGameCreated
   * @see #joinGame
   */
  AI_INTERFACE_API int __stdcall newGameOption(int option, int value);

  AI_INTERFACE_API void __stdcall postGameLogStart(void);
  AI_INTERFACE_API void __stdcall postGameLogClose(void);
  AI_INTERFACE_API void __stdcall postGameLogOriginalOpponentSetup(int x, int y, int rank);

  /**
   * Sets the username which the bot interacting with the AI instance has logged in as.
   * 
   * @param aiUsername
   *          the username which the bot interacting with the AI instance has logged in as.
   */
  AI_INTERFACE_API void __stdcall setAIUsername(const char *aiUsername);

  /**
   * Tells the AI the username of its opponent, so that if part of the AI's strategy is to keep
   * knowledge of the player in a database, this can be used.
   * 
   * @param opponentName
   *          username of the opponent.
   */
  AI_INTERFACE_API void __stdcall setOpponentUsername(const char *opponentName);

  /**
   * Turns the game aids option on or off. This may be useful to an AI to tell it whether it can
   * model forgetting which pieces have been moved and/or seen to support a lesser mode of play, and
   * also to let it know if the opponent is going to have the use of game aids.
   */
  AI_INTERFACE_API void __stdcall setGameAids(int value);

  /**
   * Sets the value of a game option. This will be called for all options, typically with value of
   * OPTION_OFF indicating option is off, OPTION_ON indicating option is on. Although there is
   * nothing that restricts the theoretical value to these two values. Thus options can be supported
   * which have any integral value.
   * <p>
   * If an AI receives an option it does not recognize, it should return <em>false</em> unless the
   * value is zero. In that case, it should return <em>true</em>.
   * <p>
   * Returning <em>false</em> will cause the game to terminate prior to start, or to not be joined
   * if not already joined.
   * 
   * @param option
   *          option being set.
   * @param value
   *          value of the option.
   * @return whether the option,value pair is accepted.
   */
  AI_INTERFACE_API int __stdcall setGameOption(int option, int value);

  /**
   * Sets the skill level of the AI.
   * 
   * @param level
   *          from BEGINNER to TOURNAMENT.
   */
  AI_INTERFACE_API int __stdcall setSkillLevel(int level);

  /**
   * Sets thet turn time limit in seconds.
   * 
   * @param turnTimeLimitSecs
   *          the number of seconds the AI will have to return a move once it is asked for its move.
   * @return <em>true</em> if the turn time limit is acceptable, <em>false</em> if not.
   */
  AI_INTERFACE_API int __stdcall setMoveTimeLimit(int turnTimeLimitSecs);

  /**
   * Sets the number of pieces for each rank. This is needed only for custom mode games, not for the
   * standard five modes.
   * 
   * @return <em>true</em> if piece count is supported, <em>false</em> if not.
   */
  AI_INTERFACE_API int __stdcall setCustomPieceCount(int marshals, int generals, int colonels, int majors,
      int captains, int lieutenants, int sergeants, int miners, int scouts, int spies, int bombs,
      int flags);

  /**
   * Sets the game mode. Returns false if this mode is not accepted.
   * 
   * @param mode
   *          the mode of the game.
   */
  AI_INTERFACE_API int __stdcall setGameMode(int mode);

  //
  // Setup methods: startSetup(c) FOR EACH SETUP FIELD getSetupPiece(x,y) END
  // FOR EACH FOR EACH OPPONENT FIELD setSetupPiece(x,y) END FOR EACH
  //

  /**
   * Called for each field containing an opponent piece this is necessary for game modes with less
   * than 40 pieces or custom setup areas.
   * 
   * @param x
   *          x coordinate on board.
   * @param y
   *          y coordinate on board.
   */
  AI_INTERFACE_API void __stdcall setOpponentSetupPiece(int x, int y);

  /**
   * Informs the AI that both setups have been received, are valid, and the game has now begun.
   */
  AI_INTERFACE_API void __stdcall startGame(void);

  //
  // Moving methods: LOOP submitOpponentMove(x,y,r) getAIMove()
  // submitAIMoveResult(r) END LOOP
  //

  /**
   * Submits the move of the opponent and if the move is an attack, also the rank of the attacking
   * piece. If the move is not attacking, then rank is UNKNOWN. Also includes the result of any
   * attack.
   * 
   * @param xo
   *          starting x coordinate of opponent piece.
   * @param yo
   *          starting y coordinate of opponent piece.
   * @param xf
   *          const x coordinate of opponent piece.
   * @param yf
   *          const y coordinate of opponent piece.
   * @param rank
   *          rank of opponent piece, if revealed by move, or UNKNOWN.
   * @param result
   *          the result of the move for the opponent (KILL, KILLED, BOTH_KILLED, NONE)
   */
  AI_INTERFACE_API BYTE __stdcall submitOpponentMove(int xo, int yo, int xf, int yf, int rank, int result);

  /**
   * Submits the result of an AI move back to the AI. This validates that the move was accepted as
   * legal. If the move was an attack, the parameters will describe the result of the attack. If
   * not, the parameters will be set to empty/default values such as RANK_UNKNOWN and
   * MOVE_RESULT_NONE.
   * 
   * @param rank
   *          rank of the defending piece if AI move is an attack.
   * @param result
   *          result of the move if AI move is an attack.
   */
  AI_INTERFACE_API BYTE __stdcall submitAIMoveResult(int rank, int result);

  /**
   * Tells the AI that it should shutdown permanently. This allows a const chance to release any
   * resources the AI may still hold.
   */
  AI_INTERFACE_API void __stdcall terminate(void);

#ifdef __cplusplus
}
#endif
#endif
