/// 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));
}

/// Types de propriétés des éléments
template <>
value cxx2lang<value, element_propriete>(element_propriete in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

template <>
element_propriete lang2cxx<value, element_propriete>(value in)
{
  CAMLparam1(in);
  CAMLreturnT(element_propriete, (element_propriete)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));
}

/// Position sur la carte, 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);
}

/// Échantillon, défini par deux types d’éléments
template <>
value cxx2lang<value, echantillon>(echantillon in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(2, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, case_type>(in.element1));
  caml_initialize(&Field(out, 1), cxx2lang<value, case_type>(in.element2));
  CAMLreturn(out);
}

template <>
echantillon lang2cxx<value, echantillon>(value in)
{
  CAMLparam1(in);
  echantillon out;
  out.element1 = lang2cxx<value, case_type>(Field(in, 0));
  out.element2 = lang2cxx<value, case_type>(Field(in, 1));
  CAMLreturnT(echantillon, out);
}

/// Position d’un échantillon, donnée par deux positions adjacentes
template <>
value cxx2lang<value, position_echantillon>(position_echantillon in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(2, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, position>(in.pos1));
  caml_initialize(&Field(out, 1), cxx2lang<value, position>(in.pos2));
  CAMLreturn(out);
}

template <>
position_echantillon lang2cxx<value, position_echantillon>(value in)
{
  CAMLparam1(in);
  position_echantillon out;
  out.pos1 = lang2cxx<value, position>(Field(in, 0));
  out.pos2 = lang2cxx<value, position>(Field(in, 1));
  CAMLreturnT(position_echantillon, out);
}

/// Action représentée dans l’historique. L’action ``placer_echantillon`` utilise ``pos1`` et ``pos2``. L’action ``transmuter`` utilise ``pos1``. L’action ``catalyser`` utilise ``pos1``, ``id_apprenti`` et ``nouvelle_case``. L’action ``donner_echantillon`` n’est pas représentée dans l’historique, car ``echantillon_tour`` donne l’information.
template <>
value cxx2lang<value, action_hist>(action_hist in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(5, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, action_type>(in.atype));
  caml_initialize(&Field(out, 1), cxx2lang<value, position>(in.pos1));
  caml_initialize(&Field(out, 2), cxx2lang<value, position>(in.pos2));
  caml_initialize(&Field(out, 3), cxx2lang<value, int>(in.id_apprenti));
  caml_initialize(&Field(out, 4), cxx2lang<value, case_type>(in.nouvelle_case));
  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.pos1 = lang2cxx<value, position>(Field(in, 1));
  out.pos2 = lang2cxx<value, position>(Field(in, 2));
  out.id_apprenti = lang2cxx<value, int>(Field(in, 3));
  out.nouvelle_case = lang2cxx<value, case_type>(Field(in, 4));
  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));
    }
}

/// Place l’échantillon du tour sur l’établi, avec les coordonnées de deux cases adjacentes.
extern "C" value ml_placer_echantillon(value pos1, value pos2)
{
  CAMLparam0();
  CAMLxparam2(pos1, pos2);
  CAMLreturn((cxx2lang<value, erreur>(api_placer_echantillon(lang2cxx<value, position>(pos1), lang2cxx<value, position>(pos2)))));
}

/// Provoque la transformation chimique de l’élément à la case ciblée, ainsi que tous les éléments adjacents du même type, ceux du même type adjacents à ces derniers, etc. Ils disparaissent alors tous dans leur transmutation en or ou en catalyseur.
extern "C" value ml_transmuter(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, erreur>(api_transmuter(lang2cxx<value, position>(pos)))));
}

/// Utilise un catalyseur sur la case ciblée de l'apprenti indiqué. Transforme l’ancien élément en l’élément indiqué.
extern "C" value ml_catalyser(value pos, value id_apprenti, value terrain)
{
  CAMLparam0();
  CAMLxparam3(pos, id_apprenti, terrain);
  CAMLreturn((cxx2lang<value, erreur>(api_catalyser(lang2cxx<value, position>(pos), lang2cxx<value, int>(id_apprenti), lang2cxx<value, case_type>(terrain)))));
}

/// Définit l’échantillon que l’adversaire recevra à son prochain tour.
extern "C" value ml_donner_echantillon(value echantillon_donne)
{
  CAMLparam0();
  CAMLxparam1(echantillon_donne);
  CAMLreturn((cxx2lang<value, erreur>(api_donner_echantillon(lang2cxx<value, echantillon>(echantillon_donne)))));
}

/// Renvoie le type d’une case donnée, ou 0 si la case est invaide.
extern "C" value ml_type_case(value pos, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam2(pos, id_apprenti);
  CAMLreturn((cxx2lang<value, case_type>(api_type_case(lang2cxx<value, position>(pos), lang2cxx<value, int>(id_apprenti)))));
}

/// Indique si une case donnée est vide ou contient un élément. Renvoie faux en cas d'erreur.
extern "C" value ml_est_vide(value pos, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam2(pos, id_apprenti);
  CAMLreturn((cxx2lang<value, bool>(api_est_vide(lang2cxx<value, position>(pos), lang2cxx<value, int>(id_apprenti)))));
}

/// Renvoie la propriété de l’élément sur une case donnée. Un élément invalide n'a pas de propriété.
extern "C" value ml_propriete_case(value pos, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam2(pos, id_apprenti);
  CAMLreturn((cxx2lang<value, element_propriete>(api_propriete_case(lang2cxx<value, position>(pos), lang2cxx<value, int>(id_apprenti)))));
}

/// Renvoie la propriété d’un type de case donné.
extern "C" value ml_propriete_case_type(value ctype)
{
  CAMLparam0();
  CAMLxparam1(ctype);
  CAMLreturn((cxx2lang<value, element_propriete>(api_propriete_case_type(lang2cxx<value, case_type>(ctype)))));
}

/// Renvoie la taille de la région à laquelle appartient un élément. Renvoie -1 si la position est invalide.
extern "C" value ml_taille_region(value pos, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam2(pos, id_apprenti);
  CAMLreturn((cxx2lang<value, int>(api_taille_region(lang2cxx<value, position>(pos), lang2cxx<value, int>(id_apprenti)))));
}

/// Renvoie la liste des positions des cases composant la région à laquelle appartient un élément donné. Renvoie une liste vide en cas d'erreur.
extern "C" value ml_positions_region(value pos, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam2(pos, id_apprenti);
  CAMLreturn((cxx2lang_array<position>(api_positions_region(lang2cxx<value, position>(pos), lang2cxx<value, int>(id_apprenti)))));
}

/// Détermine si le placement d’un échantillon est valide.
extern "C" value ml_placement_possible_echantillon(value echantillon_a_placer, value pos1, value pos2, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam4(echantillon_a_placer, pos1, pos2, id_apprenti);
  CAMLreturn((cxx2lang<value, bool>(api_placement_possible_echantillon(lang2cxx<value, echantillon>(echantillon_a_placer), lang2cxx<value, position>(pos1), lang2cxx<value, position>(pos2), lang2cxx<value, int>(id_apprenti)))));
}

/// Renvoie la liste des placements possibles pour un échantillon donné sur l’établi d’un apprenti donné. Renvoie une liste vide en cas d'erreur.
extern "C" value ml_placements_possible_echantillon(value echantillon_a_placer, value id_apprenti)
{
  CAMLparam0();
  CAMLxparam2(echantillon_a_placer, id_apprenti);
  CAMLreturn((cxx2lang_array<position_echantillon>(api_placements_possible_echantillon(lang2cxx<value, echantillon>(echantillon_a_placer), lang2cxx<value, int>(id_apprenti)))));
}

/// Renvoie la liste des actions jouées par l’adversaire pendant son tour, dans l’ordre chronologique.
extern "C" value ml_historique(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang_array<action_hist>(api_historique())));
}

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

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

/// Renvoie la quantité d’or amassée par l’apprenti désigné par le numéro ``id_apprenti``. Renvoie 0 si ``id_apprenti`` est invalide (attention, le score d’un apprenti valide peut aussi être 0).
extern "C" value ml_score(value id_apprenti)
{
  CAMLparam0();
  CAMLxparam1(id_apprenti);
  CAMLreturn((cxx2lang<value, int>(api_score(lang2cxx<value, int>(id_apprenti)))));
}

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

/// Annule la dernière action. Renvoie ``false`` 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())));
}

/// Indique le nombre de catalyseurs en votre possession.
extern "C" value ml_nombre_catalyseurs(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, int>(api_nombre_catalyseurs())));
}

/// Indique l’échantillon reçu pour ce tour.
extern "C" value ml_echantillon_tour(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, echantillon>(api_echantillon_tour())));
}

/// Indique si l’échantillon reçu pour ce tour a déjà été posé.
extern "C" value ml_a_pose_echantillon(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, bool>(api_a_pose_echantillon())));
}

/// Indique si un échantillon a déjà été donné ce tour.
extern "C" value ml_a_donne_echantillon(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, bool>(api_a_donne_echantillon())));
}

/// Renvoie la quantité d’or (et donc le score) obtenue par la transmutation de ``taille_region`` éléments transmutables en or.
extern "C" value ml_quantite_transmutation_or(value taille_region)
{
  CAMLparam0();
  CAMLxparam1(taille_region);
  CAMLreturn((cxx2lang<value, int>(api_quantite_transmutation_or(lang2cxx<value, int>(taille_region)))));
}

/// Renvoie la quantité de catalyseurs obtenue par la transmutation de ``taille_region`` éléments transmutables en catalyseur.
extern "C" value ml_quantite_transmutation_catalyseur(value taille_region)
{
  CAMLparam0();
  CAMLxparam1(taille_region);
  CAMLreturn((cxx2lang<value, int>(api_quantite_transmutation_catalyseur(lang2cxx<value, int>(taille_region)))));
}

/// Renvoie la quantité d’or obtenue par la transmutation de ``taille_region`` éléments transmutables en catalyseur.
extern "C" value ml_quantite_transmutation_catalyseur_or(value taille_region)
{
  CAMLparam0();
  CAMLxparam1(taille_region);
  CAMLreturn((cxx2lang<value, int>(api_quantite_transmutation_catalyseur_or(lang2cxx<value, int>(taille_region)))));
}

/// Indique l’échantillon par défaut lors du premier tour
extern "C" value ml_echantillon_defaut_premier_tour(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, echantillon>(api_echantillon_defaut_premier_tour())));
}

/// Affiche l'état actuel des deux établis dans la console.
extern "C" value ml_afficher_etablis(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  api_afficher_etablis();
  CAMLreturn(Val_unit);
}

/// 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 element_propriete
extern "C" value ml_afficher_element_propriete(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_element_propriete(lang2cxx<value, element_propriete>(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 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 echantillon
extern "C" value ml_afficher_echantillon(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_echantillon(lang2cxx<value, echantillon>(v));
  CAMLreturn(Val_unit);
}

/// Affiche le contenu d'une valeur de type position_echantillon
extern "C" value ml_afficher_position_echantillon(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_position_echantillon(lang2cxx<value, position_echantillon>(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;
}


