/// This file has been generated, if you wish to
/// modify it in a permanent way, please refer
/// to the script file : gen/generator_caml.rb

extern "C" {
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/memory.h>
}
#include "interface.hh"

template <typename Lang, typename Cxx>
Lang cxx2lang(Cxx in)
{
  return in.__if_that_triggers_an_error_there_is_a_problem;
}

template <>
value cxx2lang<value, int>(int in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
value cxx2lang<value, double>(double in)
{
  CAMLparam0();
  CAMLreturn(caml_copy_double(in));
}

template<>
value cxx2lang<value, std::string>(std::string in)
{
  CAMLparam0();
  size_t l = in.length();
  char * out = (char *) malloc(l + 1);
  for (int i = 0; i < l; i++) out[i] = in[i];
  out[l] = 0;
  CAMLreturn(caml_copy_string(out));
}

template <>
value cxx2lang<value, bool>(bool in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <typename Cxx>
value cxx2lang_array(const std::vector<Cxx>& in)
{
  CAMLparam0();
  CAMLlocal1(v);

  size_t size = in.size();
  if (size == 0)
    CAMLreturn(Atom(0));

  v = caml_alloc(size, 0);
  for (int i = 0; i < size; ++i)
    caml_initialize(&Field(v, i), cxx2lang<value, Cxx>(in[i]));

  CAMLreturn(v);
}

template <typename Lang, typename Cxx>
Cxx lang2cxx(Lang in)
{
  return in.__if_that_triggers_an_error_there_is_a_problem;
}

template<>
std::string lang2cxx<value, std::string>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(std::string, String_val(in));
}

template <>
int lang2cxx<value, int>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(int, Int_val(in));
}

template <>
double lang2cxx<value, double>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(double, Double_val(in));
}

template <>
bool lang2cxx<value, bool>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(bool, Int_val(in));
}

template <typename Cxx>
std::vector<Cxx> lang2cxx_array(value in)
{
  CAMLparam1(in);
  std::vector<Cxx> out;
  mlsize_t size = Wosize_val(in);

  for (int i = 0; i < size; ++i)
    out.push_back(lang2cxx<value, Cxx>(Field(in, i)));

  CAMLreturnT(std::vector<Cxx>, out);
}
/// Types de cases
template <>
value cxx2lang<value, case_type>(case_type in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
case_type lang2cxx<value, case_type>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(case_type, (case_type)Int_val(in));
}

/// Direction
template <>
value cxx2lang<value, direction>(direction in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
direction lang2cxx<value, direction>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(direction, (direction)Int_val(in));
}

/// Erreurs possibles
template <>
value cxx2lang<value, erreur>(erreur in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
erreur lang2cxx<value, erreur>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(erreur, (erreur)Int_val(in));
}

/// Types d'actions
template <>
value cxx2lang<value, action_type>(action_type in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
action_type lang2cxx<value, action_type>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(action_type, (action_type)Int_val(in));
}

/// Types de drapeaux de débug
template <>
value cxx2lang<value, debug_drapeau>(debug_drapeau in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
debug_drapeau lang2cxx<value, debug_drapeau>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(debug_drapeau, (debug_drapeau)Int_val(in));
}

/// Position dans la mine, donnée par deux coordonnées.
template <>
value cxx2lang<value, position>(position in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(2, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, int>(in.ligne));
  caml_initialize(&Field(out, 1), cxx2lang<value, int>(in.colonne));
  CAMLreturn(out);
}

template <>
position lang2cxx<value, position>(value in)
{
  CAMLparam1(in);
  position out;
  out.ligne = lang2cxx<value, int>(Field(in, 0));
  out.colonne = lang2cxx<value, int>(Field(in, 1));
  CAMLreturnT(position, out);
}

/// Minerai à récolter
template <>
value cxx2lang<value, minerai>(minerai in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(2, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, int>(in.resistance));
  caml_initialize(&Field(out, 1), cxx2lang<value, int>(in.rendement));
  CAMLreturn(out);
}

template <>
minerai lang2cxx<value, minerai>(value in)
{
  CAMLparam1(in);
  minerai out;
  out.resistance = lang2cxx<value, int>(Field(in, 0));
  out.rendement = lang2cxx<value, int>(Field(in, 1));
  CAMLreturnT(minerai, out);
}

/// Nain (standard)
template <>
value cxx2lang<value, nain>(nain in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(6, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, position>(in.pos));
  caml_initialize(&Field(out, 1), cxx2lang<value, int>(in.vie));
  caml_initialize(&Field(out, 2), cxx2lang<value, int>(in.pa));
  caml_initialize(&Field(out, 3), cxx2lang<value, int>(in.pm));
  caml_initialize(&Field(out, 4), cxx2lang<value, bool>(in.accroche));
  caml_initialize(&Field(out, 5), cxx2lang<value, int>(in.butin));
  CAMLreturn(out);
}

template <>
nain lang2cxx<value, nain>(value in)
{
  CAMLparam1(in);
  nain out;
  out.pos = lang2cxx<value, position>(Field(in, 0));
  out.vie = lang2cxx<value, int>(Field(in, 1));
  out.pa = lang2cxx<value, int>(Field(in, 2));
  out.pm = lang2cxx<value, int>(Field(in, 3));
  out.accroche = lang2cxx<value, bool>(Field(in, 4));
  out.butin = lang2cxx<value, int>(Field(in, 5));
  CAMLreturnT(nain, out);
}

/// Action de déplacement représentée dans l'historique.
template <>
value cxx2lang<value, action_hist>(action_hist in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(4, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, action_type>(in.atype));
  caml_initialize(&Field(out, 1), cxx2lang<value, int>(in.id_nain));
  caml_initialize(&Field(out, 2), cxx2lang<value, direction>(in.dir));
  caml_initialize(&Field(out, 3), cxx2lang<value, direction>(in.sens));
  CAMLreturn(out);
}

template <>
action_hist lang2cxx<value, action_hist>(value in)
{
  CAMLparam1(in);
  action_hist out;
  out.atype = lang2cxx<value, action_type>(Field(in, 0));
  out.id_nain = lang2cxx<value, int>(Field(in, 1));
  out.dir = lang2cxx<value, direction>(Field(in, 2));
  out.sens = lang2cxx<value, direction>(Field(in, 3));
  CAMLreturnT(action_hist, out);
}

/*
** Inititialize caml
*/
static inline void _init_caml()
{
    static bool is_initialized = false;

    if (!is_initialized)
    {
        is_initialized = true;

        const char* argv[2] = {"./caml", NULL};
        caml_startup(const_cast<char**>(argv));
    }
}

/// Renvoie un chemin entre deux positions de la mine sous la forme d'une suite de directions à emprunter. Ce chemin minimise le nombre de blocs de granite nécessaire à casser. Si la position est invalide ou qu'il n'existe pas de tel chemin, le chemin renvoyé est vide.
extern "C" value ml_chemin(value pos1, value pos2)
{
  CAMLparam0();
  CAMLxparam2(pos1, pos2);
  CAMLreturn((cxx2lang_array<direction>(api_chemin(lang2cxx<value, position>(pos1), lang2cxx<value, position>(pos2)))));
}

/// Déplace le nain (standard) ``id_nain`` d'une case dans la direction choisie.
extern "C" value ml_deplacer(value id_nain, value dir)
{
  CAMLparam0();
  CAMLxparam2(id_nain, dir);
  CAMLreturn((cxx2lang<value, erreur>(api_deplacer(lang2cxx<value, int>(id_nain), lang2cxx<value, direction>(dir)))));
}

/// Le nain (standard) ``id_nain`` lâche la paroi.
extern "C" value ml_lacher(value id_nain)
{
  CAMLparam0();
  CAMLxparam1(id_nain);
  CAMLreturn((cxx2lang<value, erreur>(api_lacher(lang2cxx<value, int>(id_nain)))));
}

/// Le nain (standard) ``id_nain`` s'agrippe à la paroi.
extern "C" value ml_agripper(value id_nain)
{
  CAMLparam0();
  CAMLxparam1(id_nain);
  CAMLreturn((cxx2lang<value, erreur>(api_agripper(lang2cxx<value, int>(id_nain)))));
}

/// Le nain (standard) ``id_nain`` mine le bloc ou le nain (standard) dans la direction indiquée.
extern "C" value ml_miner(value id_nain, value dir)
{
  CAMLparam0();
  CAMLxparam2(id_nain, dir);
  CAMLreturn((cxx2lang<value, erreur>(api_miner(lang2cxx<value, int>(id_nain), lang2cxx<value, direction>(dir)))));
}

/// Le nain (standard) ``id_nain`` tire la corde dans le sens donné (HAUT ou BAS).
extern "C" value ml_tirer(value id_nain, value dir_corde, value sens)
{
  CAMLparam0();
  CAMLxparam3(id_nain, dir_corde, sens);
  CAMLreturn((cxx2lang<value, erreur>(api_tirer(lang2cxx<value, int>(id_nain), lang2cxx<value, direction>(dir_corde), lang2cxx<value, direction>(sens)))));
}

/// Le nain (standard) ``id_nain`` pose une corde dans la direction indiquée.
extern "C" value ml_poser_corde(value id_nain, value dir)
{
  CAMLparam0();
  CAMLxparam2(id_nain, dir);
  CAMLreturn((cxx2lang<value, erreur>(api_poser_corde(lang2cxx<value, int>(id_nain), lang2cxx<value, direction>(dir)))));
}

/// Affiche le drapeau spécifié sur la case indiquée.
extern "C" value ml_debug_afficher_drapeau(value pos, value drapeau)
{
  CAMLparam0();
  CAMLxparam2(pos, drapeau);
  CAMLreturn((cxx2lang<value, erreur>(api_debug_afficher_drapeau(lang2cxx<value, position>(pos), lang2cxx<value, debug_drapeau>(drapeau)))));
}

/// Renvoie le type d'une case donnée.
extern "C" value ml_type_case(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, case_type>(api_type_case(lang2cxx<value, position>(pos)))));
}

/// Renvoie la liste de toutes les positions occupées par une corde dans la mine.
extern "C" value ml_liste_cordes(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang_array<position>(api_liste_cordes())));
}

/// Indique si une corde se trouve sur une case donnée.
extern "C" value ml_corde_sur_case(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, bool>(api_corde_sur_case(lang2cxx<value, position>(pos)))));
}

/// Renvoie le numéro du joueur à qui appartienent les nains (standard) sur la case indiquée. Renvoie -1 s'il n'y a pas de nain (standard) ou si la position est invalide.
extern "C" value ml_nain_sur_case(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, int>(api_nain_sur_case(lang2cxx<value, position>(pos)))));
}

/// Renvoie la description du nain (standard) désigné par le numéro ``id_nain`` appartenant au joueur ``id_joueur``. Si le nain (standard)  n'est pas présent sur la carte, tous les membres de la structure ``nain`` renvoyée sont initialisés à -1 (et le champ ``accroche`` à `false`).
extern "C" value ml_info_nain(value id_joueur, value id_nain)
{
  CAMLparam0();
  CAMLxparam2(id_joueur, id_nain);
  CAMLreturn((cxx2lang<value, nain>(api_info_nain(lang2cxx<value, int>(id_joueur), lang2cxx<value, int>(id_nain)))));
}

/// Renvoie la liste de tous les minerais dans la mine.
extern "C" value ml_liste_minerais(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang_array<position>(api_liste_minerais())));
}

/// Renvoie la description d'un minerai en fonction d'une position donnée. Si le minerai n'est pas présent sur la carte, ou si la position est invalide, tous les membres de la structure ``minerai`` renvoyée sont initialisés à -1.
extern "C" value ml_info_minerai(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, minerai>(api_info_minerai(lang2cxx<value, position>(pos)))));
}

/// Renvoie le nombre de points de déplacement que coûterai le déplacement d'un nain (standard) dans une direction donnée. Renvoie -1 si le déplacement n'est pas possible.
extern "C" value ml_cout_de_deplacement(value id_nain, value dir)
{
  CAMLparam0();
  CAMLxparam2(id_nain, dir);
  CAMLreturn((cxx2lang<value, int>(api_cout_de_deplacement(lang2cxx<value, int>(id_nain), lang2cxx<value, direction>(dir)))));
}

/// Renvoie la position de la taverne appartenant au joueur ``id_joueur``. Si le joueur n'existe pas, renvoie la position (-1, -1).
extern "C" value ml_position_taverne(value id_joueur)
{
  CAMLparam0();
  CAMLxparam1(id_joueur);
  CAMLreturn((cxx2lang<value, position>(api_position_taverne(lang2cxx<value, int>(id_joueur)))));
}

/// Renvoie la liste des actions effectuées par l’adversaire durant son tour, dans l'ordre chronologique. Les actions de débug n'apparaissent pas dans cette liste.
extern "C" value ml_historique(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang_array<action_hist>(api_historique())));
}

/// Renvoie le score du joueur ``id_joueur``. Renvoie -1 si le joueur est invalide.
extern "C" value ml_score(value id_joueur)
{
  CAMLparam0();
  CAMLxparam1(id_joueur);
  CAMLreturn((cxx2lang<value, int>(api_score(lang2cxx<value, int>(id_joueur)))));
}

/// Renvoie votre numéro de joueur.
extern "C" value ml_moi(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, int>(api_moi())));
}

/// Renvoie le numéro de joueur de votre adversaire.
extern "C" value ml_adversaire(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, int>(api_adversaire())));
}

/// Annule la dernière action. Renvoie faux quand il n'y a pas d'action à annuler ce tour ci.
extern "C" value ml_annuler(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, bool>(api_annuler())));
}

/// Retourne le numéro du tour actuel.
extern "C" value ml_tour_actuel(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, int>(api_tour_actuel())));
}

/// Affiche le contenu d'une valeur de type case_type
extern "C" value ml_afficher_case_type(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_case_type(lang2cxx<value, case_type>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type direction
extern "C" value ml_afficher_direction(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_direction(lang2cxx<value, direction>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type erreur
extern "C" value ml_afficher_erreur(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_erreur(lang2cxx<value, erreur>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type action_type
extern "C" value ml_afficher_action_type(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_action_type(lang2cxx<value, action_type>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type debug_drapeau
extern "C" value ml_afficher_debug_drapeau(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_debug_drapeau(lang2cxx<value, debug_drapeau>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type position
extern "C" value ml_afficher_position(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_position(lang2cxx<value, position>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type minerai
extern "C" value ml_afficher_minerai(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_minerai(lang2cxx<value, minerai>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type nain
extern "C" value ml_afficher_nain(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_nain(lang2cxx<value, nain>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type action_hist
extern "C" value ml_afficher_action_hist(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_action_hist(lang2cxx<value, action_hist>(v));
  CAMLreturn(Val_unit);
}

/// Fonction appelée au début de la partie.
void partie_init()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_partie_init");
  _ret = callback(*closure, Val_unit);
  CAMLreturn0;
}


/// Fonction appelée à chaque tour.
void jouer_tour()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_jouer_tour");
  _ret = callback(*closure, Val_unit);
  CAMLreturn0;
}


/// Fonction appelée à la fin de la partie.
void partie_fin()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_partie_fin");
  _ret = callback(*closure, Val_unit);
  CAMLreturn0;
}


