#ifndef INCLUDE_GUARD_RCHESS_TYPES
#define INCLUDE_GUARD_RCHESS_TYPES

#include <RcppCommon.h>

#include "SchachHoernchen/Move.h"
#include "SchachHoernchen/Board.h"
#include "SchachHoernchen/uci.h"

namespace Rcpp {
    template <> Move as(SEXP);
    template <> SEXP wrap(const Move&);

    template <> Board as(SEXP);
    template <> SEXP wrap(const Board&);
} /* namespace Rcpp */

#include <Rcpp.h>

namespace Rcpp {
    // Convert a coordinate encoded move string into a Move
    template <>
    Move as(SEXP obj) {
        // parse (and validate) the move
        bool parseError = false;
        Move move = UCI::parseMove(Rcpp::as<std::string>(obj), parseError);
        if (parseError) {
            Rcpp::stop("Error parsing move");
        }
        return move;
    }

    // Convert a Move into an `R` character
    template <>
    SEXP wrap(const Move& move) {
        return Rcpp::CharacterVector::create(UCI::formatMove(move));
    }

    // Convert a FEN string to a board
    template <>
    Board as(SEXP obj) {
        bool parseError = false;
        Board board;
        std::string fen = Rcpp::as<std::string>(obj);
        if (fen != "startpos") {
            board.init(fen, parseError);
        }
        if (parseError) {
            Rcpp::stop("Parsing FEN failed");
        }
        return board;
    }

    // Convert board to `R` board class (as character FEN string)
    template <>
    SEXP wrap(const Board& board) {
        auto obj = Rcpp::CharacterVector::create(board.fen());
        obj.attr("class") = "board";
        return obj;
    }

    // Convert a character vector or list to a vector of Boards
    template <>
    std::vector<Board> as(SEXP obj) {
        // Convert SEXP to be a vector of string
        auto fens = Rcpp::as<std::vector<std::string>>(obj);
        // Try to parse every string as a Board from a FEN
        std::vector<Board> boards(fens.size());
        for (int i = 0; i < fens.size(); ++i) {
            bool parseError = false;
            if (fens[i] != "startpos") {
                boards[i].init(fens[i], parseError);
            }
            if (parseError) {
                Rcpp::stop("Parsing FEN nr. %d failed", i + 1);
            }
        }
        return boards;
    }
} /* namespace Rcpp */

#endif /* INCLUDE_GUARD_RCHESS_TYPES */
