#include "Game.hpp"

Game::Game() : current(NULL), moves(NULL), result("*") {
  tags["White"] = "";
  tags["Black"] = "";
  initial_fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
  board = "rnbqkbnrpppppppp                                PPPPPPPPRNBQKBNR";
}

Game::Game(std::string fen) : current(NULL), moves(NULL), result("*") {
  tags["White"] = "";
  tags["Black"] = "";
  tags["FEN"] = fen;
  initial_fen = fen;
  board = chessarbiter::FENParser::Parse(fen).board;
}

Game::Game(HalfMove *m, std::string initial_fen) : result("*") {
  moves = m;
  current = m;
  this->initial_fen = initial_fen;
  board = chessarbiter::FENParser::Parse(initial_fen).board;
}

Game::~Game() {
  if (moves != NULL) {
    delete moves;
  }
}

std::string Game::GetBoard() { return (board); }

std::string Game::GetTag(std::string tagname) { return (tags[tagname]); }

void Game::SetTag(std::string tagname, std::string value) {
  tags[tagname] = value;
}

bool Game::IsBlackToPlay() {
  if (current == NULL) {
    return (false);
  }
  return (!current->IsBlack);
}

void Game::DeleteTag(std::string tagname) { tags.erase(tagname); }

void Game::DeleteMove(HalfMove *m) {
  if (moves == m) {
    current = NULL;
    moves = NULL;
    delete m;
  } else {
    if (m != NULL) {
      current = m->GetParent();
      if (current != NULL) {
        current->RemoveChild(m);
      }
      delete m;
    }
  }
}

HalfMove *Game::GetCurrentMove() { return (current); }

HalfMove *Game::GetMoves() { return (moves); }

void Game::PromoteMove(HalfMove *m) {
  if (m != NULL) {
    current = m;
    m->Promote();
  }
}

void Game::SetMoveAsMainline(HalfMove *m) {
  if (m != NULL) {
    current = m;
    m->SetAsMainline();
  }
}

bool Game::Play(std::string move) {
  wxLogDebug("Playing move %s", move);
  std::string fen = GetFen();
  arbiter.Setup(fen);
  if (arbiter.Play(move)) {
    HalfMove *m = new HalfMove(move, arbiter.GetSAN(), arbiter.GetFEN());
    char capture = arbiter.GetCapture();
    if (capture != ' ') {
      wxLogDebug("%c", capture);
      m->SetCapture(capture);
    }
    if (current != NULL) {
      current->AddMove(m);
    } else if (moves != NULL) {
      moves->AddVariation(m);
    }
    current = m;
    if (moves == NULL) {
      moves = m;
    }
    return (true);
  }
  return (false);
}

void Game::Previous() {
  if (current != NULL) {
    current = current->GetParent();
  }
}

std::vector<std::string> Game::ListTags() {
  std::vector<std::string> keys;
  for (auto const &element : tags) {
    keys.push_back(element.first);
  }
  return (keys);
}

void Game::Next() {
  if (current != NULL) {
    HalfMove *m = current->GetMainline();
    if (m != NULL) {
      current = m;
    }
  } else {
    current = moves;
  }
}

void Game::SetCurrent(HalfMove *m) { current = m; }

std::string Game::GetFen() {
  if (current == NULL) {
    return (initial_fen);
  }
  return (current->GetFen());
}

std::string Game::GetResult() { return (result); }

void Game::SetResult(std::string result) { this->result = result; }

void Game::BuildAndVerify() {
  if (moves != NULL) {
    moves->BuildAndVerify(GetFen());
  }
}