///
// 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, 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 <>
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);
}
///
// Information sur les cases
//
template <>
value cxx2lang<value, case_info>(case_info in)
{
  CAMLparam0();
  CAMLreturn(Val_int(in));
}

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

///
// Représente la position sur la carte
//
template <>
value cxx2lang<value, position>(position in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(2, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, int>(in.x));
  caml_initialize(&Field(out, 1), cxx2lang<value, int>(in.y));
  CAMLreturn(out);
}

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

///
// Représente une tourelle
//
template <>
value cxx2lang<value, tourelle>(tourelle in)
{
  CAMLparam0();
  CAMLlocal1(out);
  out = caml_alloc(5, 0);
  caml_initialize(&Field(out, 0), cxx2lang<value, position>(in.pos));
  caml_initialize(&Field(out, 1), cxx2lang<value, int>(in.portee));
  caml_initialize(&Field(out, 2), cxx2lang<value, int>(in.joueur));
  caml_initialize(&Field(out, 3), cxx2lang<value, int>(in.vie));
  caml_initialize(&Field(out, 4), cxx2lang<value, int>(in.attaque));
  CAMLreturn(out);
}

template <>
tourelle lang2cxx<value, tourelle>(value in)
{
  CAMLparam1(in);
  tourelle out;
  out.pos = lang2cxx<value, position>(Field(in, 0));
  out.portee = lang2cxx<value, int>(Field(in, 1));
  out.joueur = lang2cxx<value, int>(Field(in, 2));
  out.vie = lang2cxx<value, int>(Field(in, 3));
  out.attaque = lang2cxx<value, int>(Field(in, 4));
  CAMLreturnT(tourelle, 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));
    }
}

///
// Retourne le type de la case à l'emplacement `pos`
//
extern "C" value ml_info_case(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, case_info>(api_info_case(lang2cxx<value, position>(pos)))));
}

///
// Retourne la liste des tourelles qui appartiennent au joueur ``joueur``
//
extern "C" value ml_tourelles_joueur(value joueur)
{
  CAMLparam0();
  CAMLxparam1(joueur);
  CAMLreturn((cxx2lang_array<tourelle>(api_tourelles_joueur(lang2cxx<value, int>(joueur)))));
}

///
// Retourne la magie que possède le joueur ``joueur``
//
extern "C" value ml_magie(value joueur)
{
  CAMLparam0();
  CAMLxparam1(joueur);
  CAMLreturn((cxx2lang<value, int>(api_magie(lang2cxx<value, int>(joueur)))));
}

///
// Retourne le nombre de sorciers du joueur ``joueur`` sur la case ``pos``
//
extern "C" value ml_nb_sorciers(value pos, value joueur)
{
  CAMLparam0();
  CAMLxparam2(pos, joueur);
  CAMLreturn((cxx2lang<value, int>(api_nb_sorciers(lang2cxx<value, position>(pos), lang2cxx<value, int>(joueur)))));
}

///
// Retourne le nombre de sorciers du joueur ``joueur`` déplacables sur la case ``pos``
//
extern "C" value ml_nb_sorciers_deplacables(value pos, value joueur)
{
  CAMLparam0();
  CAMLxparam2(pos, joueur);
  CAMLreturn((cxx2lang<value, int>(api_nb_sorciers_deplacables(lang2cxx<value, position>(pos), lang2cxx<value, int>(joueur)))));
}

///
// Retourne le numéro du joueur qui contrôle la case ``pos``
//
extern "C" value ml_joueur_case(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, int>(api_joueur_case(lang2cxx<value, position>(pos)))));
}

///
// Retourne la tourelle située sur la case ``pos``
//
extern "C" value ml_tourelle_case(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, tourelle>(api_tourelle_case(lang2cxx<value, position>(pos)))));
}

///
// Retourne la position de la base du joueur ``joueur``
//
extern "C" value ml_base_joueur(value joueur)
{
  CAMLparam0();
  CAMLxparam1(joueur);
  CAMLreturn((cxx2lang<value, position>(api_base_joueur(lang2cxx<value, int>(joueur)))));
}

///
// Retourne vrai si l'on peut construire sur la case ``pos``
//
extern "C" value ml_constructible(value pos, value joueur)
{
  CAMLparam0();
  CAMLxparam2(pos, joueur);
  CAMLreturn((cxx2lang<value, bool>(api_constructible(lang2cxx<value, position>(pos), lang2cxx<value, int>(joueur)))));
}

///
// Retourne la liste des positions constituant le plus court chemin allant de la case ``pos1`` à la case ``pos2``. Attention : Cette fonction est lente.
//
extern "C" value ml_chemin(value pos1, value pos2)
{
  CAMLparam0();
  CAMLxparam2(pos1, pos2);
  CAMLreturn((cxx2lang_array<position>(api_chemin(lang2cxx<value, position>(pos1), lang2cxx<value, position>(pos2)))));
}

///
// Construire une tourelle à la position ``pos``
//
extern "C" value ml_construire(value pos, value portee)
{
  CAMLparam0();
  CAMLxparam2(pos, portee);
  CAMLreturn((cxx2lang<value, erreur>(api_construire(lang2cxx<value, position>(pos), lang2cxx<value, int>(portee)))));
}

///
// Supprimer une tourelle à la position ``pos``
//
extern "C" value ml_supprimer(value pos)
{
  CAMLparam0();
  CAMLxparam1(pos);
  CAMLreturn((cxx2lang<value, erreur>(api_supprimer(lang2cxx<value, position>(pos)))));
}

///
// Tirer avec ``pts`` points de dégats depuis la tourelles ``tourelle`` sur la position ``cible``
//
extern "C" value ml_tirer(value pts, value tourelle, value cible)
{
  CAMLparam0();
  CAMLxparam3(pts, tourelle, cible);
  CAMLreturn((cxx2lang<value, erreur>(api_tirer(lang2cxx<value, int>(pts), lang2cxx<value, position>(tourelle), lang2cxx<value, position>(cible)))));
}

///
// Créer ``nb`` sorciers dans la base
//
extern "C" value ml_creer(value nb)
{
  CAMLparam0();
  CAMLxparam1(nb);
  CAMLreturn((cxx2lang<value, erreur>(api_creer(lang2cxx<value, int>(nb)))));
}

///
// Déplace ``nb`` sorciers de la position ``depart`` jusqu'à la position ``arrivee``.
//
extern "C" value ml_deplacer(value depart, value arrivee, value nb)
{
  CAMLparam0();
  CAMLxparam3(depart, arrivee, nb);
  CAMLreturn((cxx2lang<value, erreur>(api_deplacer(lang2cxx<value, position>(depart), lang2cxx<value, position>(arrivee), lang2cxx<value, int>(nb)))));
}

///
// Attaquer la tourelle à la position ``cible`` depuis la position ``pos``
//
extern "C" value ml_assieger(value pos, value cible, value nb_sorciers)
{
  CAMLparam0();
  CAMLxparam3(pos, cible, nb_sorciers);
  CAMLreturn((cxx2lang<value, erreur>(api_assieger(lang2cxx<value, position>(pos), lang2cxx<value, position>(cible), lang2cxx<value, int>(nb_sorciers)))));
}

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

///
// Retourne la liste des numéros de vos adversaires
//
extern "C" value ml_adversaires(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang_array<int>(api_adversaires())));
}

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

///
// Retourne la distance entre deux positions
//
extern "C" value ml_distance(value depart, value arrivee)
{
  CAMLparam0();
  CAMLxparam2(depart, arrivee);
  CAMLreturn((cxx2lang<value, int>(api_distance(lang2cxx<value, position>(depart), lang2cxx<value, position>(arrivee)))));
}

///
// Annule la dernière action
//
extern "C" value ml_annuler(value unit)
{
  CAMLparam0();
  CAMLxparam1(unit);
  CAMLreturn((cxx2lang<value, erreur>(api_annuler())));
}

///
// Affiche le contenu d'une valeur de type case_info
//
extern "C" value ml_afficher_case_info(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_case_info(lang2cxx<value, case_info>(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 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 tourelle
//
extern "C" value ml_afficher_tourelle(value v)
{
  CAMLparam0();
  CAMLxparam1(v);
  api_afficher_tourelle(lang2cxx<value, tourelle>(v));
  CAMLreturn(Val_unit);
}

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


///
// Fonction appelée pendant la phase de construction
//
void phase_construction()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_phase_construction");
  _ret = callback(*closure, Val_unit);
  CAMLreturn0;
}


///
// Fonction appelée pendant la phase de déplacement
//
void phase_deplacement()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_phase_deplacement");
  _ret = callback(*closure, Val_unit);
  CAMLreturn0;
}


///
// Fonction appelée pendant la phase de tirs des tourelles
//
void phase_tirs()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_phase_tirs");
  _ret = callback(*closure, Val_unit);
  CAMLreturn0;
}


///
// Fonction appelée pendant la phase de siège des tourelles
//
void phase_siege()
{
  _init_caml();
  CAMLparam0();
  CAMLlocal1(_ret);
  static value *closure = NULL;
  if (closure == NULL)
    closure = caml_named_value("ml_phase_siege");
  _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;
}


