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

#include "interface.hh"

#include <iostream>
#include <assert.h>
#include <cstdlib>
#include <cstring>

CSharpInterface gl_csharp;

template < class Out, class Cxx >
Out cxx2lang(Cxx in)
{
  return (Out)in;
}

template <>
MonoString* cxx2lang<MonoString*, std::string>(std::string in)
{
  return mono_string_new (gl_csharp.getDomain(), in.c_str());
}

template <>
gint32 cxx2lang< gint32, int >(int in)
{
  return (gint32)in;
}

template <>
gint32 cxx2lang< gint32, bool >(bool in)
{
  return (gint32)in;
}

template < class Out, class Cxx >
Cxx lang2cxx(Out in)
{
  return (Cxx)in;
}

template <>
std::string lang2cxx< MonoString*, std::string >(MonoString* in)
{
  std::string s_out;
  MonoError error;
  char *c_out;

  if (!in)
    return std::string("(null)");
  c_out = mono_string_to_utf8_checked(in, &error);
  if (!mono_error_ok(&error)) {
    s_out = std::string(mono_error_get_message(&error));
    mono_error_cleanup(&error);
    return s_out;
  } else {
    s_out = std::string(c_out);
    mono_free(c_out);
    return s_out;
  }
}

template <>
int lang2cxx< gint32, int >(gint32 in)
{
  return (int)in;
}

template <>
bool lang2cxx< gint32, bool >(gint32 in)
{
  return (bool)in;
}

template <>
MonoArray* cxx2lang< MonoArray*, std::vector<int> >(std::vector<int> in)
{
  gint32 size = in.size();
  MonoClass* mcKlass = mono_get_int32_class();
  MonoArray * maArray = mono_array_new(gl_csharp.getDomain(), mcKlass, size);

  for (int i = 0; i < size; ++i)
    mono_array_set(maArray, gint32, i, (cxx2lang< gint32, int >(in[i])));

  return maArray;
}

template <>
std::vector<int> lang2cxx< MonoArray*, std::vector<int> >(MonoArray* in)
{
  std::vector< int > out;
  gint32 size = mono_array_length(in);

  for (int i = 0; i < size; ++i)
    out.push_back(lang2cxx< gint32, int >(mono_array_get(in, gint32, i)));

  return out;
}
///
// Erreurs possibles
//
template <>
gint32 cxx2lang< gint32, erreur >(erreur in)
{
  return (gint32)in;
}

template <>
erreur lang2cxx< gint32, erreur >(gint32 in)
{
  return (erreur)in;
}
template <>
MonoArray* cxx2lang< MonoArray*, std::vector<erreur> >(std::vector<erreur> in)
{
  gint32 size = in.size();
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Erreur");
  MonoArray * maArray = mono_array_new(gl_csharp.getDomain(), mcKlass, size);
  for (int i = 0; i < size; ++i)
    mono_array_set(maArray, gint32, i, (cxx2lang< gint32, erreur >(in[i])));
  return maArray;
}

template <>
std::vector<erreur> lang2cxx< MonoArray*, std::vector<erreur> >(MonoArray* in)
{
  std::vector< erreur > out;
  gint32 size = mono_array_length(in);

  for (int i = 0; i < size; ++i)
    out.push_back(lang2cxx< gint32, erreur >(mono_array_get(in , gint32, i)));
  return out;
}

///
// Position sur la carte, donnée par deux coordonnées.
//
template <>
MonoObject* cxx2lang< MonoObject*, position >(position in)
{
  void* arg;
  MonoClass*  mcKlass  = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Position");
  MonoObject* moObj    = mono_object_new(gl_csharp.getDomain(), mcKlass);
mono_runtime_object_init(moObj);
  arg = reinterpret_cast< void* >(cxx2lang< gint32, int >(in.x));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "X"), &arg);
  arg = reinterpret_cast< void* >(cxx2lang< gint32, int >(in.y));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "Y"), &arg);
  return moObj;
}

template <>
position lang2cxx< MonoObject*, position >(MonoObject* in)
{
    position out;
  void*      field_out;
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Position");
  (void)field_out;
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "X"), &out.x);
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "Y"), &out.y);
  return out;
}

template <>
MonoArray* cxx2lang< MonoArray*, std::vector<position> >(std::vector<position> in)
{
  gint32 size = in.size();
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Position");
  MonoArray * maArray = mono_array_new(gl_csharp.getDomain(), mcKlass, size);
  for (int i = 0; i < size; ++i)
    mono_array_setref(maArray, i, (cxx2lang< MonoObject*, position >(in[i])));
  return maArray;
}

template <>
std::vector<position> lang2cxx< MonoArray*, std::vector<position> >(MonoArray* in)
{
  std::vector< position > out;
  gint32 size = mono_array_length(in);

  for (int i = 0; i < size; ++i)
    out.push_back(lang2cxx< MonoObject*, position >(reinterpret_cast<MonoObject*>(mono_array_get(in, MonoObject*, i))));
  return out;
}

///
// Représente un lien existant.
//
template <>
MonoObject* cxx2lang< MonoObject*, lien >(lien in)
{
  void* arg;
  MonoClass*  mcKlass  = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Lien");
  MonoObject* moObj    = mono_object_new(gl_csharp.getDomain(), mcKlass);
mono_runtime_object_init(moObj);
  arg = reinterpret_cast< void* >(cxx2lang< MonoObject*, position >(in.extr1));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "Extr1"), &arg);
  arg = reinterpret_cast< void* >(cxx2lang< MonoObject*, position >(in.extr2));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "Extr2"), &arg);
  arg = reinterpret_cast< void* >(cxx2lang< gint32, int >(in.joueur_l));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "JoueurL"), &arg);
  return moObj;
}

template <>
lien lang2cxx< MonoObject*, lien >(MonoObject* in)
{
    lien out;
  void*      field_out;
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Lien");
  (void)field_out;
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "Extr1"), &field_out);
  out.extr1 = lang2cxx< MonoObject*, position >(reinterpret_cast< MonoObject* >(field_out));
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "Extr2"), &field_out);
  out.extr2 = lang2cxx< MonoObject*, position >(reinterpret_cast< MonoObject* >(field_out));
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "JoueurL"), &out.joueur_l);
  return out;
}

template <>
MonoArray* cxx2lang< MonoArray*, std::vector<lien> >(std::vector<lien> in)
{
  gint32 size = in.size();
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Lien");
  MonoArray * maArray = mono_array_new(gl_csharp.getDomain(), mcKlass, size);
  for (int i = 0; i < size; ++i)
    mono_array_setref(maArray, i, (cxx2lang< MonoObject*, lien >(in[i])));
  return maArray;
}

template <>
std::vector<lien> lang2cxx< MonoArray*, std::vector<lien> >(MonoArray* in)
{
  std::vector< lien > out;
  gint32 size = mono_array_length(in);

  for (int i = 0; i < size; ++i)
    out.push_back(lang2cxx< MonoObject*, lien >(reinterpret_cast<MonoObject*>(mono_array_get(in, MonoObject*, i))));
  return out;
}

///
// Représente un champ de contrôle existant.
//
template <>
MonoObject* cxx2lang< MonoObject*, champ >(champ in)
{
  void* arg;
  MonoClass*  mcKlass  = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Champ");
  MonoObject* moObj    = mono_object_new(gl_csharp.getDomain(), mcKlass);
mono_runtime_object_init(moObj);
  arg = reinterpret_cast< void* >(cxx2lang< MonoObject*, position >(in.som1));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "Som1"), &arg);
  arg = reinterpret_cast< void* >(cxx2lang< MonoObject*, position >(in.som2));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "Som2"), &arg);
  arg = reinterpret_cast< void* >(cxx2lang< MonoObject*, position >(in.som3));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "Som3"), &arg);
  arg = reinterpret_cast< void* >(cxx2lang< gint32, int >(in.joueur_c));
  mono_field_set_value(moObj, mono_class_get_field_from_name(mcKlass, "JoueurC"), &arg);
  return moObj;
}

template <>
champ lang2cxx< MonoObject*, champ >(MonoObject* in)
{
    champ out;
  void*      field_out;
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Champ");
  (void)field_out;
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "Som1"), &field_out);
  out.som1 = lang2cxx< MonoObject*, position >(reinterpret_cast< MonoObject* >(field_out));
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "Som2"), &field_out);
  out.som2 = lang2cxx< MonoObject*, position >(reinterpret_cast< MonoObject* >(field_out));
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "Som3"), &field_out);
  out.som3 = lang2cxx< MonoObject*, position >(reinterpret_cast< MonoObject* >(field_out));
  mono_field_get_value(in, mono_class_get_field_from_name(mcKlass, "JoueurC"), &out.joueur_c);
  return out;
}

template <>
MonoArray* cxx2lang< MonoArray*, std::vector<champ> >(std::vector<champ> in)
{
  gint32 size = in.size();
  MonoClass* mcKlass = mono_class_from_name(gl_csharp.getImage(), "Prologin", "Champ");
  MonoArray * maArray = mono_array_new(gl_csharp.getDomain(), mcKlass, size);
  for (int i = 0; i < size; ++i)
    mono_array_setref(maArray, i, (cxx2lang< MonoObject*, champ >(in[i])));
  return maArray;
}

template <>
std::vector<champ> lang2cxx< MonoArray*, std::vector<champ> >(MonoArray* in)
{
  std::vector< champ > out;
  gint32 size = mono_array_length(in);

  for (int i = 0; i < size; ++i)
    out.push_back(lang2cxx< MonoObject*, champ >(reinterpret_cast<MonoObject*>(mono_array_get(in, MonoObject*, i))));
  return out;
}

gint32 deplacer(MonoObject* dest)
{
	return cxx2lang< gint32, erreur >(api_deplacer(lang2cxx< MonoObject*, position >(dest)))
;
}

gint32 utiliser_turbo()
{
	return cxx2lang< gint32, erreur >(api_utiliser_turbo())
;
}

gint32 capturer()
{
	return cxx2lang< gint32, erreur >(api_capturer())
;
}

gint32 lier(MonoObject* portail)
{
	return cxx2lang< gint32, erreur >(api_lier(lang2cxx< MonoObject*, position >(portail)))
;
}

gint32 neutraliser()
{
	return cxx2lang< gint32, erreur >(api_neutraliser())
;
}

gint32 ajouter_bouclier()
{
	return cxx2lang< gint32, erreur >(api_ajouter_bouclier())
;
}

MonoArray* liste_liens()
{
	return cxx2lang< MonoArray*, std::vector<lien> >(api_liste_liens())
;
}

MonoArray* liste_champs()
{
	return cxx2lang< MonoArray*, std::vector<champ> >(api_liste_champs())
;
}

MonoArray* liste_portails()
{
	return cxx2lang< MonoArray*, std::vector<position> >(api_liste_portails())
;
}

MonoArray* liens_bloquants(MonoObject* ext1, MonoObject* ext2)
{
	return cxx2lang< MonoArray*, std::vector<lien> >(api_liens_bloquants(lang2cxx< MonoObject*, position >(ext1), lang2cxx< MonoObject*, position >(ext2)))
;
}

gint32 lien_existe(MonoObject* ext1, MonoObject* ext2)
{
	return cxx2lang< gint32, bool >(api_lien_existe(lang2cxx< MonoObject*, position >(ext1), lang2cxx< MonoObject*, position >(ext2)))
;
}

gint32 champ_existe(MonoObject* som1, MonoObject* som2, MonoObject* som3)
{
	return cxx2lang< gint32, bool >(api_champ_existe(lang2cxx< MonoObject*, position >(som1), lang2cxx< MonoObject*, position >(som2), lang2cxx< MonoObject*, position >(som3)))
;
}

gint32 case_dans_champ(MonoObject* pos)
{
	return cxx2lang< gint32, bool >(api_case_dans_champ(lang2cxx< MonoObject*, position >(pos)))
;
}

MonoArray* case_champs(MonoObject* pos)
{
	return cxx2lang< MonoArray*, std::vector<champ> >(api_case_champs(lang2cxx< MonoObject*, position >(pos)))
;
}

gint32 portail_joueur(MonoObject* portail)
{
	return cxx2lang< gint32, int >(api_portail_joueur(lang2cxx< MonoObject*, position >(portail)))
;
}

gint32 portail_boucliers(MonoObject* portail)
{
	return cxx2lang< gint32, int >(api_portail_boucliers(lang2cxx< MonoObject*, position >(portail)))
;
}

MonoArray* liens_incidents_portail(MonoObject* portail)
{
	return cxx2lang< MonoArray*, std::vector<lien> >(api_liens_incidents_portail(lang2cxx< MonoObject*, position >(portail)))
;
}

MonoArray* champs_incidents_portail(MonoObject* portail)
{
	return cxx2lang< MonoArray*, std::vector<champ> >(api_champs_incidents_portail(lang2cxx< MonoObject*, position >(portail)))
;
}

MonoArray* champs_incidents_segment(MonoObject* ext1, MonoObject* ext2)
{
	return cxx2lang< MonoArray*, std::vector<champ> >(api_champs_incidents_segment(lang2cxx< MonoObject*, position >(ext1), lang2cxx< MonoObject*, position >(ext2)))
;
}

MonoArray* hist_portails_captures()
{
	return cxx2lang< MonoArray*, std::vector<position> >(api_hist_portails_captures())
;
}

MonoArray* hist_portails_neutralises()
{
	return cxx2lang< MonoArray*, std::vector<position> >(api_hist_portails_neutralises())
;
}

MonoArray* hist_liens_crees()
{
	return cxx2lang< MonoArray*, std::vector<lien> >(api_hist_liens_crees())
;
}

MonoArray* hist_champs_crees()
{
	return cxx2lang< MonoArray*, std::vector<champ> >(api_hist_champs_crees())
;
}

MonoArray* hist_boucliers_ajoutes()
{
	return cxx2lang< MonoArray*, std::vector<position> >(api_hist_boucliers_ajoutes())
;
}

gint32 distance(MonoObject* pos1, MonoObject* pos2)
{
	return cxx2lang< gint32, int >(api_distance(lang2cxx< MonoObject*, position >(pos1), lang2cxx< MonoObject*, position >(pos2)))
;
}

gint32 score_triangle(MonoObject* som1, MonoObject* som2, MonoObject* som3)
{
	return cxx2lang< gint32, int >(api_score_triangle(lang2cxx< MonoObject*, position >(som1), lang2cxx< MonoObject*, position >(som2), lang2cxx< MonoObject*, position >(som3)))
;
}

gint32 intersection_segments(MonoObject* a1, MonoObject* a2, MonoObject* b1, MonoObject* b2)
{
	return cxx2lang< gint32, bool >(api_intersection_segments(lang2cxx< MonoObject*, position >(a1), lang2cxx< MonoObject*, position >(a2), lang2cxx< MonoObject*, position >(b1), lang2cxx< MonoObject*, position >(b2)))
;
}

gint32 point_dans_triangle(MonoObject* p, MonoObject* som1, MonoObject* som2, MonoObject* som3)
{
	return cxx2lang< gint32, bool >(api_point_dans_triangle(lang2cxx< MonoObject*, position >(p), lang2cxx< MonoObject*, position >(som1), lang2cxx< MonoObject*, position >(som2), lang2cxx< MonoObject*, position >(som3)))
;
}

gint32 moi()
{
	return cxx2lang< gint32, int >(api_moi())
;
}

gint32 adversaire()
{
	return cxx2lang< gint32, int >(api_adversaire())
;
}

MonoObject* position_agent(gint32 id_joueur)
{
	return cxx2lang< MonoObject*, position >(api_position_agent(lang2cxx< gint32, int >(id_joueur)))
;
}

gint32 points_action()
{
	return cxx2lang< gint32, int >(api_points_action())
;
}

gint32 points_deplacement()
{
	return cxx2lang< gint32, int >(api_points_deplacement())
;
}

gint32 score(gint32 id_joueur)
{
	return cxx2lang< gint32, int >(api_score(lang2cxx< gint32, int >(id_joueur)))
;
}

gint32 tour_actuel()
{
	return cxx2lang< gint32, int >(api_tour_actuel())
;
}

gint32 annuler()
{
	return cxx2lang< gint32, bool >(api_annuler())
;
}

void afficher_erreur(gint32 v)
{
	api_afficher_erreur(lang2cxx< gint32, erreur >(v))
;
}

void afficher_position(MonoObject* v)
{
	api_afficher_position(lang2cxx< MonoObject*, position >(v))
;
}

void afficher_lien(MonoObject* v)
{
	api_afficher_lien(lang2cxx< MonoObject*, lien >(v))
;
}

void afficher_champ(MonoObject* v)
{
	api_afficher_champ(lang2cxx< MonoObject*, champ >(v))
;
}


/*
** Inititialize Mono and load the DLL file.
*/
CSharpInterface::CSharpInterface()
{
  const char*		champion_path = getenv("CHAMPION_PATH");
  std::string		champion;

  if (!champion_path)
    champion = "./champion-prologin.dll";
  else
  {
    champion = champion_path;
    champion += "/champion-prologin.dll";
  }

  _domain = mono_jit_init(champion.c_str());
  assert(_domain != NULL);

  _assembly = mono_domain_assembly_open(_domain, champion.c_str());
  assert(_assembly != NULL);

  _image = mono_assembly_get_image(_assembly);
  assert(_image != NULL);

  _class = mono_class_from_name(_image, "Prologin", "Prologin");
  assert(_class != NULL);

  _object = mono_object_new(_domain, _class);
  assert(_object);

  mono_runtime_object_init(_object);

  // Register API functions as internal Mono functions
  mono_add_internal_call("Prologin.Api::Deplacer", (const void*)deplacer);
  mono_add_internal_call("Prologin.Api::UtiliserTurbo", (const void*)utiliser_turbo);
  mono_add_internal_call("Prologin.Api::Capturer", (const void*)capturer);
  mono_add_internal_call("Prologin.Api::Lier", (const void*)lier);
  mono_add_internal_call("Prologin.Api::Neutraliser", (const void*)neutraliser);
  mono_add_internal_call("Prologin.Api::AjouterBouclier", (const void*)ajouter_bouclier);
  mono_add_internal_call("Prologin.Api::ListeLiens", (const void*)liste_liens);
  mono_add_internal_call("Prologin.Api::ListeChamps", (const void*)liste_champs);
  mono_add_internal_call("Prologin.Api::ListePortails", (const void*)liste_portails);
  mono_add_internal_call("Prologin.Api::LiensBloquants", (const void*)liens_bloquants);
  mono_add_internal_call("Prologin.Api::LienExiste", (const void*)lien_existe);
  mono_add_internal_call("Prologin.Api::ChampExiste", (const void*)champ_existe);
  mono_add_internal_call("Prologin.Api::CaseDansChamp", (const void*)case_dans_champ);
  mono_add_internal_call("Prologin.Api::CaseChamps", (const void*)case_champs);
  mono_add_internal_call("Prologin.Api::PortailJoueur", (const void*)portail_joueur);
  mono_add_internal_call("Prologin.Api::PortailBoucliers", (const void*)portail_boucliers);
  mono_add_internal_call("Prologin.Api::LiensIncidentsPortail", (const void*)liens_incidents_portail);
  mono_add_internal_call("Prologin.Api::ChampsIncidentsPortail", (const void*)champs_incidents_portail);
  mono_add_internal_call("Prologin.Api::ChampsIncidentsSegment", (const void*)champs_incidents_segment);
  mono_add_internal_call("Prologin.Api::HistPortailsCaptures", (const void*)hist_portails_captures);
  mono_add_internal_call("Prologin.Api::HistPortailsNeutralises", (const void*)hist_portails_neutralises);
  mono_add_internal_call("Prologin.Api::HistLiensCrees", (const void*)hist_liens_crees);
  mono_add_internal_call("Prologin.Api::HistChampsCrees", (const void*)hist_champs_crees);
  mono_add_internal_call("Prologin.Api::HistBoucliersAjoutes", (const void*)hist_boucliers_ajoutes);
  mono_add_internal_call("Prologin.Api::Distance", (const void*)distance);
  mono_add_internal_call("Prologin.Api::ScoreTriangle", (const void*)score_triangle);
  mono_add_internal_call("Prologin.Api::IntersectionSegments", (const void*)intersection_segments);
  mono_add_internal_call("Prologin.Api::PointDansTriangle", (const void*)point_dans_triangle);
  mono_add_internal_call("Prologin.Api::Moi", (const void*)moi);
  mono_add_internal_call("Prologin.Api::Adversaire", (const void*)adversaire);
  mono_add_internal_call("Prologin.Api::PositionAgent", (const void*)position_agent);
  mono_add_internal_call("Prologin.Api::PointsAction", (const void*)points_action);
  mono_add_internal_call("Prologin.Api::PointsDeplacement", (const void*)points_deplacement);
  mono_add_internal_call("Prologin.Api::Score", (const void*)score);
  mono_add_internal_call("Prologin.Api::TourActuel", (const void*)tour_actuel);
  mono_add_internal_call("Prologin.Api::Annuler", (const void*)annuler);
  mono_add_internal_call("Prologin.Api::AfficherErreur", (const void*)afficher_erreur);
  mono_add_internal_call("Prologin.Api::AfficherPosition", (const void*)afficher_position);
  mono_add_internal_call("Prologin.Api::AfficherLien", (const void*)afficher_lien);
  mono_add_internal_call("Prologin.Api::AfficherChamp", (const void*)afficher_champ);
}

MonoImage* CSharpInterface::getImage()
{
    return _image;
}

MonoDomain* CSharpInterface::getDomain()
{
    return _domain;
}

CSharpInterface::~CSharpInterface()
{
  mono_image_close(_image);
  mono_assembly_close(_assembly);
  // XXX -- mono segfaults when calling this. Seems to be a known bug
  //        appearing when mono_jit_clean() is called from a dtor. ???
  //mono_jit_cleanup(_domain);
}

/*
** Calls C# functions from C++
*/
MonoObject* CSharpInterface::callCSharpMethod(const char* name)
{
  MonoThread*   thread = mono_thread_attach(_domain);
  MonoMethod*   method = mono_class_get_method_from_name(_class, name, 0);
  MonoObject*   object = mono_runtime_invoke(method, _object, NULL, NULL);

  mono_thread_detach(thread);

  return object;
}

/*
** Functions called from stechec to C.
*/
void partie_init()
{
  gl_csharp.callCSharpMethod("PartieInit");
}
void jouer_tour()
{
  gl_csharp.callCSharpMethod("JouerTour");
}
void partie_fin()
{
  gl_csharp.callCSharpMethod("PartieFin");
}
