#ifndef UCI_GUARD_MOVE_H
#define UCI_GUARD_MOVE_H

#include <string>
#include <vector>

#include "types.h"

// Forward declarations
class Board;
class Move;
class MoveList;

namespace std {
    ostream& operator<<(ostream& out, const Move& move);
    ostream& operator<<(ostream& out, const MoveList& moveList);
}

/**
 * UCI ... Universal Chess Interface
 *
 * Implements the UCI interface for interaction between the internal engine
 * and an GUI using the UCI standard.
 */
namespace UCI {

// General UCI protocol configuration
extern bool readSAN; // if moves should be read in SAN
extern bool writeLAN; // moves written in Long Algebraic Notation

/**
 * Parses square in algebraic notation as internal square index.
 *
 * @param str string representation of a square /[a-h][1-8]/.
 * @param parseError output variable set to true if illegal square
 *  representation is encountered (aka. parse error occured).
 *
 * @returns index between 0 and 63 if legal, 64 otherwise.
 */
Index parseSquare(const std::string& str, bool& parseError);

/**
 * Parses a move given in pure coordinate notation
 *
 * @param str string representation of a move in `<from><to>[<promotion>]` format
 * @param parseError output variable set to false if successfully parsed, true
 *  otherwise.
 */
Move parseMove(const std::string& str, bool& parseError);

/**
 * Formats a move in coordinate notation (Unary Function equiv to the pipe
 * operator for Move)
 *
 * @param move move to be formated as a string
 *
 * @return string representation of the move in coordinate notation
 */
const std::string formatMove(const Move move);

/**
 * Parses a move given in standard algebraic notation (SAN)
 *
 * @param str string representation of a move in SAN format
 * @param pos current position, needed for move interpretation
 * @param parseError output variable set to false if successfully parsed, true
 *  otherwise.
 */
Move parseSAN(const std::string& str, const Board& pos, bool& parseError);

/**
 * Parses multiple moves from an input stream into a `MoveList`
 */
void parseMoves(std::istream&, MoveList&, bool&);

char formatPiece(enum piece piece);
void printBoard(const Board&);
void printMoves(const Board&, bool = false);
void printBitBoards(const Board&);

/**
 * Handles `position ...` command by setting given board (including moves).
 *
 * @param board internal board representation to be manipulated.
 * @param cmd argument `...` of the position command. For example; given the
 *  command `position startpos moves e2e4`, str should contain `startpos moves e2e4`.
 * @param parseError output, true if a parse error occured, false otherwise.
 */
void position(std::vector<Board>&, std::istream&, bool&);

/**
 * handles `go ...` commands. Starts searches, performance tests, ...
 */
void go(std::vector<Board>&, std::istream&, bool&);

/**
 * Processes/Parses input from stdin and dispatches appropriate command handler.
 */
void stdin_listen(std::vector<Board>& game);

} /* namespace UCI */

#endif /* UCI_GUARD_MOVE_H */
