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

#include "interface.hh"

// In case of errors...
template<typename Lang, typename Cxx>
Cxx lang2cxx(Lang in)
{
  return in.error_should_not_happens;
}

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

template<typename Lang, typename Cxx>
std::vector<Cxx> lang2cxx_array(jobject in);

template<typename Cxx, typename Lang>
jarray cxx2lang_array(std::vector<Cxx> in);

// Basic type wrappers
template <>
jboolean cxx2lang<boolean, jboolean>(boolean in)
{
  return (jboolean)in;
}

template <>
boolean lang2cxx<jboolean, boolean>(jboolean in)
{
  return (boolean)in;
}

template <>
jarray cxx2lang_array<boolean, jboolean>(std::vector<boolean> in)
{
  jbooleanArray out = jrt.env->NewBooleanArray((jsize)in.size());
  jrt.env->SetBooleanArrayRegion(out, (jsize)0, (jsize)in.size(), (const jboolean*)in.data());
  return (jarray)out;
}

template <>
std::vector<boolean> lang2cxx_array<jboolean, boolean>(jobject in)
{
  jbooleanArray array = (jbooleanArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jboolean* datas = jrt.env->GetBooleanArrayElements(array, NULL);
  std::vector<boolean> out(datas, datas + size);
  jrt.env->ReleaseBooleanArrayElements(array, datas, JNI_ABORT);
  return out;
}

template <>
jbyte cxx2lang<byte, jbyte>(byte in)
{
  return (jbyte)in;
}

template <>
byte lang2cxx<jbyte, byte>(jbyte in)
{
  return (byte)in;
}

template <>
jarray cxx2lang_array<byte, jbyte>(std::vector<byte> in)
{
  jbyteArray out = jrt.env->NewByteArray((jsize)in.size());
  jrt.env->SetByteArrayRegion(out, (jsize)0, (jsize)in.size(), (const jbyte*)in.data());
  return (jarray)out;
}

template <>
std::vector<byte> lang2cxx_array<jbyte, byte>(jobject in)
{
  jbyteArray array = (jbyteArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jbyte* datas = jrt.env->GetByteArrayElements(array, NULL);
  std::vector<byte> out(datas, datas + size);
  jrt.env->ReleaseByteArrayElements(array, datas, JNI_ABORT);
  return out;
}

template <>
jchar cxx2lang<char, jchar>(char in)
{
  return (jchar)in;
}

template <>
char lang2cxx<jchar, char>(jchar in)
{
  return (char)in;
}

template <>
jarray cxx2lang_array<char, jchar>(std::vector<char> in)
{
  jcharArray out = jrt.env->NewCharArray((jsize)in.size());
  jrt.env->SetCharArrayRegion(out, (jsize)0, (jsize)in.size(), (const jchar*)in.data());
  return (jarray)out;
}

template <>
std::vector<char> lang2cxx_array<jchar, char>(jobject in)
{
  jcharArray array = (jcharArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jchar* datas = jrt.env->GetCharArrayElements(array, NULL);
  std::vector<char> out(datas, datas + size);
  jrt.env->ReleaseCharArrayElements(array, datas, JNI_ABORT);
  return out;
}

template <>
jshort cxx2lang<short, jshort>(short in)
{
  return (jshort)in;
}

template <>
short lang2cxx<jshort, short>(jshort in)
{
  return (short)in;
}

template <>
jarray cxx2lang_array<short, jshort>(std::vector<short> in)
{
  jshortArray out = jrt.env->NewShortArray((jsize)in.size());
  jrt.env->SetShortArrayRegion(out, (jsize)0, (jsize)in.size(), (const jshort*)in.data());
  return (jarray)out;
}

template <>
std::vector<short> lang2cxx_array<jshort, short>(jobject in)
{
  jshortArray array = (jshortArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jshort* datas = jrt.env->GetShortArrayElements(array, NULL);
  std::vector<short> out(datas, datas + size);
  jrt.env->ReleaseShortArrayElements(array, datas, JNI_ABORT);
  return out;
}

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

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

template <>
jarray cxx2lang_array<int, jint>(std::vector<int> in)
{
  jintArray out = jrt.env->NewIntArray((jsize)in.size());
  jrt.env->SetIntArrayRegion(out, (jsize)0, (jsize)in.size(), (const jint*)in.data());
  return (jarray)out;
}

template <>
std::vector<int> lang2cxx_array<jint, int>(jobject in)
{
  jintArray array = (jintArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jint* datas = jrt.env->GetIntArrayElements(array, NULL);
  std::vector<int> out(datas, datas + size);
  jrt.env->ReleaseIntArrayElements(array, datas, JNI_ABORT);
  return out;
}

template <>
jlong cxx2lang<long, jlong>(long in)
{
  return (jlong)in;
}

template <>
long lang2cxx<jlong, long>(jlong in)
{
  return (long)in;
}

template <>
jarray cxx2lang_array<long, jlong>(std::vector<long> in)
{
  jlongArray out = jrt.env->NewLongArray((jsize)in.size());
  jrt.env->SetLongArrayRegion(out, (jsize)0, (jsize)in.size(), (const jlong*)in.data());
  return (jarray)out;
}

template <>
std::vector<long> lang2cxx_array<jlong, long>(jobject in)
{
  jlongArray array = (jlongArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jlong* datas = jrt.env->GetLongArrayElements(array, NULL);
  std::vector<long> out(datas, datas + size);
  jrt.env->ReleaseLongArrayElements(array, datas, JNI_ABORT);
  return out;
}

template <>
jfloat cxx2lang<float, jfloat>(float in)
{
  return (jfloat)in;
}

template <>
float lang2cxx<jfloat, float>(jfloat in)
{
  return (float)in;
}

template <>
jarray cxx2lang_array<float, jfloat>(std::vector<float> in)
{
  jfloatArray out = jrt.env->NewFloatArray((jsize)in.size());
  jrt.env->SetFloatArrayRegion(out, (jsize)0, (jsize)in.size(), (const jfloat*)in.data());
  return (jarray)out;
}

template <>
std::vector<float> lang2cxx_array<jfloat, float>(jobject in)
{
  jfloatArray array = (jfloatArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jfloat* datas = jrt.env->GetFloatArrayElements(array, NULL);
  std::vector<float> out(datas, datas + size);
  jrt.env->ReleaseFloatArrayElements(array, datas, JNI_ABORT);
  return out;
}

template <>
jdouble cxx2lang<double, jdouble>(double in)
{
  return (jdouble)in;
}

template <>
double lang2cxx<jdouble, double>(jdouble in)
{
  return (double)in;
}

template <>
jarray cxx2lang_array<double, jdouble>(std::vector<double> in)
{
  jdoubleArray out = jrt.env->NewDoubleArray((jsize)in.size());
  jrt.env->SetDoubleArrayRegion(out, (jsize)0, (jsize)in.size(), (const jdouble*)in.data());
  return (jarray)out;
}

template <>
std::vector<double> lang2cxx_array<jdouble, double>(jobject in)
{
  jdoubleArray array = (jdoubleArray)in;
  jsize size = jrt.env->GetArrayLength(array);
  jdouble* datas = jrt.env->GetDoubleArrayElements(array, NULL);
  std::vector<double> out(datas, datas + size);
  jrt.env->ReleaseDoubleArrayElements(array, datas, JNI_ABORT);
  return out;
}

// String wrappers
template <>
jstring cxx2lang<std::string, jstring>(std::string in)
{
  return jrt.env->NewStringUTF(in.data());
}

template <>
std::string lang2cxx<jstring, std::string>(jstring in)
{
  jboolean is_copy;
  const jchar* datas = jrt.env->GetStringChars(in, &is_copy);
  jsize size = jrt.env->GetStringLength(in);
  std::string out((const char*)datas, (size_t)size);
  if (is_copy)
    jrt.env->ReleaseStringChars(in, datas);
  return out;
}

// Object array wrappers (assume Lang::class exists)
template <typename Cxx, typename Lang>
jarray cxx2lang_array(std::vector<Cxx> in)
{
  jobjectArray out = jrt.env->NewObjectArray((jsize)in.size(), Lang::Class(), NULL);
  for (size_t i = 0; i < in.size(); i++)
    jrt.env->SetObjectArrayElement(out, (jsize)i, cxx2lang<Cxx, jobject>(in[i]));
  return out;
}

template <typename Lang, typename Cxx>
std::vector<Cxx> lang2cxx_array(jobject in)
{
  jobjectArray array = (jobjectArray)in;
  size_t size = (size_t)jrt.env->GetArrayLength(array);
  std::vector<Cxx> out;
  for (size_t i = 0; i < size; i++)
    out.push_back(lang2cxx<jobject, Cxx>(jrt.env->GetObjectArrayElement(array, (jsize)i)));
  return out;
}

///
// Erreurs possibles
//
template<>
erreur lang2cxx<jobject, erreur>(jobject in)
{
  jmethodID ordinal = jrt.env->GetMethodID(Erreur::Class(), "ordinal", "()I");
  return erreur(lang2cxx<jint, int>(jrt.env->CallIntMethod(in, ordinal)));
}

template<>
jobject cxx2lang<erreur, jobject>(erreur in)
{
  jmethodID method = jrt.env->GetStaticMethodID(Erreur::Class(), "values", "()[LErreur;");
  jobjectArray values = (jobjectArray)jrt.env->CallStaticObjectMethod(Erreur::Class(), method);
  return jrt.env->GetObjectArrayElement(values, (jsize)in);
}


///
// Position sur la carte, donnée par deux coordonnées.
//
template <>
position lang2cxx<jobject, position>(jobject in)
{
  position out;
  out.x = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(Position::Class(), "x", "I")));
  out.y = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(Position::Class(), "y", "I")));
  return out;
}

template <>
jobject cxx2lang<position, jobject>(position in)
{
  jobject out = jrt.env->NewObject(Position::Class(), jrt.env->GetMethodID(Position::Class(), "<init>", "()V"));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(Position::Class(), "x", "I"), cxx2lang<int, jint>(in.x));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(Position::Class(), "y", "I"), cxx2lang<int, jint>(in.y));
  return out;
}


///
// Représente un lien existant.
//
template <>
lien lang2cxx<jobject, lien>(jobject in)
{
  lien out;
  out.extr1 = lang2cxx<jobject, position>(jrt.env->GetObjectField(in, jrt.env->GetFieldID(Lien::Class(), "extr1", "LPosition;")));
  out.extr2 = lang2cxx<jobject, position>(jrt.env->GetObjectField(in, jrt.env->GetFieldID(Lien::Class(), "extr2", "LPosition;")));
  out.joueur_l = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(Lien::Class(), "joueur_l", "I")));
  return out;
}

template <>
jobject cxx2lang<lien, jobject>(lien in)
{
  jobject out = jrt.env->NewObject(Lien::Class(), jrt.env->GetMethodID(Lien::Class(), "<init>", "()V"));
  jrt.env->SetObjectField(out, jrt.env->GetFieldID(Lien::Class(), "extr1", "LPosition;"), cxx2lang<position, jobject>(in.extr1));
  jrt.env->SetObjectField(out, jrt.env->GetFieldID(Lien::Class(), "extr2", "LPosition;"), cxx2lang<position, jobject>(in.extr2));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(Lien::Class(), "joueur_l", "I"), cxx2lang<int, jint>(in.joueur_l));
  return out;
}


///
// Représente un champ de contrôle existant.
//
template <>
champ lang2cxx<jobject, champ>(jobject in)
{
  champ out;
  out.som1 = lang2cxx<jobject, position>(jrt.env->GetObjectField(in, jrt.env->GetFieldID(Champ::Class(), "som1", "LPosition;")));
  out.som2 = lang2cxx<jobject, position>(jrt.env->GetObjectField(in, jrt.env->GetFieldID(Champ::Class(), "som2", "LPosition;")));
  out.som3 = lang2cxx<jobject, position>(jrt.env->GetObjectField(in, jrt.env->GetFieldID(Champ::Class(), "som3", "LPosition;")));
  out.joueur_c = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(Champ::Class(), "joueur_c", "I")));
  return out;
}

template <>
jobject cxx2lang<champ, jobject>(champ in)
{
  jobject out = jrt.env->NewObject(Champ::Class(), jrt.env->GetMethodID(Champ::Class(), "<init>", "()V"));
  jrt.env->SetObjectField(out, jrt.env->GetFieldID(Champ::Class(), "som1", "LPosition;"), cxx2lang<position, jobject>(in.som1));
  jrt.env->SetObjectField(out, jrt.env->GetFieldID(Champ::Class(), "som2", "LPosition;"), cxx2lang<position, jobject>(in.som2));
  jrt.env->SetObjectField(out, jrt.env->GetFieldID(Champ::Class(), "som3", "LPosition;"), cxx2lang<position, jobject>(in.som3));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(Champ::Class(), "joueur_c", "I"), cxx2lang<int, jint>(in.joueur_c));
  return out;
}


///
// Déplace votre agent sur la case passée en argument.
//
jobject deplacer(JNIEnv* _env, jobject _obj, jobject dest)
{
  return cxx2lang<erreur, jobject>(api_deplacer(lang2cxx<jobject, position>(dest)));
}


///
// Utilise un turbo.
//
jobject utiliser_turbo(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<erreur, jobject>(api_utiliser_turbo());
}


///
// Capture le portail où est positionné votre agent.
//
jobject capturer(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<erreur, jobject>(api_capturer());
}


///
// Crée un lien entre le portail où se trouve votre agent et le portail de destination donné en argument.
//
jobject lier(JNIEnv* _env, jobject _obj, jobject portail)
{
  return cxx2lang<erreur, jobject>(api_lier(lang2cxx<jobject, position>(portail)));
}


///
// Neutralise le portail où se trouve votre agent.
//
jobject neutraliser(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<erreur, jobject>(api_neutraliser());
}


///
// Ajoute un bouclier au portail sur lequel se trouve votre agent.
//
jobject ajouter_bouclier(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<erreur, jobject>(api_ajouter_bouclier());
}


///
// Renvoie la liste de tous les liens présents.
//
jarray liste_liens(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<lien, Lien>(api_liste_liens());
}


///
// Renvoie la liste de tous les champs de contrôle.
//
jarray liste_champs(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<champ, Champ>(api_liste_champs());
}


///
// Renvoie la liste de tous les portails de la carte.
//
jarray liste_portails(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_liste_portails());
}


///
// Renvoie la liste de tous les liens existants qui croisent un segment, entravant la création d'un lien.
//
jarray liens_bloquants(JNIEnv* _env, jobject _obj, jobject ext1, jobject ext2)
{
  return cxx2lang_array<lien, Lien>(api_liens_bloquants(lang2cxx<jobject, position>(ext1), lang2cxx<jobject, position>(ext2)));
}


///
// Prend les positions de deux portails, et renvoie un booléen indiquant s'ils sont reliés. Le résultat est `false` lorsque l'une des deux positions ne repère pas un portail.
//
jboolean lien_existe(JNIEnv* _env, jobject _obj, jobject ext1, jobject ext2)
{
  return cxx2lang<boolean, jboolean>(api_lien_existe(lang2cxx<jobject, position>(ext1), lang2cxx<jobject, position>(ext2)));
}


///
// Renvoie un booléen indiquant si les 3 positions repèrent bien 3 portails tous reliés entre eux.
//
jboolean champ_existe(JNIEnv* _env, jobject _obj, jobject som1, jobject som2, jobject som3)
{
  return cxx2lang<boolean, jboolean>(api_champ_existe(lang2cxx<jobject, position>(som1), lang2cxx<jobject, position>(som2), lang2cxx<jobject, position>(som3)));
}


///
// Renvoie un booléen indiquant si la case ``pos`` se trouve dans un champ.
//
jboolean case_dans_champ(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_case_dans_champ(lang2cxx<jobject, position>(pos)));
}


///
// Renvoie la liste des champs à l'intérieur desquels ``pos`` se trouve. Si la case est un portail, le résultat de ``case_champs`` sera disjoint de celui de ``champs_incidents_portail``.
//
jarray case_champs(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang_array<champ, Champ>(api_case_champs(lang2cxx<jobject, position>(pos)));
}


///
// Renvoie le numéro du joueur correspondant au portail donné, -1 si le portail est neutre, -2 si la case n'est pas un portail. Vous pouvez utiliser cette fonction pour vérifier qu'une case donnée est bien un portail.
//
jint portail_joueur(JNIEnv* _env, jobject _obj, jobject portail)
{
  return cxx2lang<int, jint>(api_portail_joueur(lang2cxx<jobject, position>(portail)));
}


///
// Renvoie le nombre de boucliers présents sur un portail (-2 si la case n'est pas un portail).
//
jint portail_boucliers(JNIEnv* _env, jobject _obj, jobject portail)
{
  return cxx2lang<int, jint>(api_portail_boucliers(lang2cxx<jobject, position>(portail)));
}


///
// Renvoie la liste de tous les liens dont le portail donné est une extrémité.
//
jarray liens_incidents_portail(JNIEnv* _env, jobject _obj, jobject portail)
{
  return cxx2lang_array<lien, Lien>(api_liens_incidents_portail(lang2cxx<jobject, position>(portail)));
}


///
// Renvoie la liste de tous les champs dont le portail donné est un sommet.
//
jarray champs_incidents_portail(JNIEnv* _env, jobject _obj, jobject portail)
{
  return cxx2lang_array<champ, Champ>(api_champs_incidents_portail(lang2cxx<jobject, position>(portail)));
}


///
// Renvoie la liste de tous les champs dont le lien donné est un côté. Si le segment n'est pas un lien présent, renvoie la liste de tous les champs que la création du lien ferait apparaître.
//
jarray champs_incidents_segment(JNIEnv* _env, jobject _obj, jobject ext1, jobject ext2)
{
  return cxx2lang_array<champ, Champ>(api_champs_incidents_segment(lang2cxx<jobject, position>(ext1), lang2cxx<jobject, position>(ext2)));
}


///
// Renvoie la liste des portails capturés par votre adversaire au dernier tour.
//
jarray hist_portails_captures(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_portails_captures());
}


///
// Renvoie la liste des portails neutralisés par votre adversaire au dernier tour.
//
jarray hist_portails_neutralises(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_portails_neutralises());
}


///
// Renvoie la liste des liens créés par votre adversaire au dernier tour.
//
jarray hist_liens_crees(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<lien, Lien>(api_hist_liens_crees());
}


///
// Renvoie la liste des champs créés par votre adversaire au dernier tour.
//
jarray hist_champs_crees(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<champ, Champ>(api_hist_champs_crees());
}


///
// Renvoie la liste des positions où votre adversaire a ajouté des boucliers au dernier tour.
//
jarray hist_boucliers_ajoutes(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_boucliers_ajoutes());
}


///
// Renvoie la distance de Manhattan entre deux positions.
//
jint distance(JNIEnv* _env, jobject _obj, jobject pos1, jobject pos2)
{
  return cxx2lang<int, jint>(api_distance(lang2cxx<jobject, position>(pos1), lang2cxx<jobject, position>(pos2)));
}


///
// Renvoie le nombre de points que rapporte(rait) chaque tour un champ existant ou hypothétique.
//
jint score_triangle(JNIEnv* _env, jobject _obj, jobject som1, jobject som2, jobject som3)
{
  return cxx2lang<int, jint>(api_score_triangle(lang2cxx<jobject, position>(som1), lang2cxx<jobject, position>(som2), lang2cxx<jobject, position>(som3)));
}


///
// Indique si deux segments se croisent. Cette fonction correspond exactement à la condition d'interférence entre liens, c'est-à-dire qu'elle renvoie ``false`` si l'intersection est une extrémité des deux segments.
//
jboolean intersection_segments(JNIEnv* _env, jobject _obj, jobject a1, jobject a2, jobject b1, jobject b2)
{
  return cxx2lang<boolean, jboolean>(api_intersection_segments(lang2cxx<jobject, position>(a1), lang2cxx<jobject, position>(a2), lang2cxx<jobject, position>(b1), lang2cxx<jobject, position>(b2)));
}


///
// Indique si un point se trouve à l'intérieur d'un triangle. Le critère coïncide avec celui de ``case_champs``.
//
jboolean point_dans_triangle(JNIEnv* _env, jobject _obj, jobject p, jobject som1, jobject som2, jobject som3)
{
  return cxx2lang<boolean, jboolean>(api_point_dans_triangle(lang2cxx<jobject, position>(p), lang2cxx<jobject, position>(som1), lang2cxx<jobject, position>(som2), lang2cxx<jobject, position>(som3)));
}


///
// Renvoie votre numéro de joueur.
//
jint moi(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<int, jint>(api_moi());
}


///
// Renvoie le numéro de votre adversaire.
//
jint adversaire(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<int, jint>(api_adversaire());
}


///
// Indique la position de l'agent du joueur désigné par le numéro ``id_joueur``.
//
jobject position_agent(JNIEnv* _env, jobject _obj, jint id_joueur)
{
  return cxx2lang<position, jobject>(api_position_agent(lang2cxx<jint, int>(id_joueur)));
}


///
// Indique votre nombre de points d'actions restants pour ce tour-ci.
//
jint points_action(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<int, jint>(api_points_action());
}


///
// Indique votre nombre de points de déplacement restants pour ce tour-ci.
//
jint points_deplacement(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<int, jint>(api_points_deplacement());
}


///
// Renvoie le score du joueur désigné par le numéro ``id_joueur``.
//
jint score(JNIEnv* _env, jobject _obj, jint id_joueur)
{
  return cxx2lang<int, jint>(api_score(lang2cxx<jint, int>(id_joueur)));
}


///
// Renvoie le numéro du tour actuel.
//
jint tour_actuel(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<int, jint>(api_tour_actuel());
}


///
// Annule la dernière action. Renvoie ``false`` quand il n'y a pas d'action à annuler ce tour-ci.
//
jboolean annuler(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<boolean, jboolean>(api_annuler());
}


///
// Affiche le contenu d'une valeur de type erreur
//
void afficher_erreur(JNIEnv* _env, jobject _obj, jobject v)
{
  api_afficher_erreur(lang2cxx<jobject, erreur>(v));
}


///
// Affiche le contenu d'une valeur de type position
//
void afficher_position(JNIEnv* _env, jobject _obj, jobject v)
{
  api_afficher_position(lang2cxx<jobject, position>(v));
}


///
// Affiche le contenu d'une valeur de type lien
//
void afficher_lien(JNIEnv* _env, jobject _obj, jobject v)
{
  api_afficher_lien(lang2cxx<jobject, lien>(v));
}


///
// Affiche le contenu d'une valeur de type champ
//
void afficher_champ(JNIEnv* _env, jobject _obj, jobject v)
{
  api_afficher_champ(lang2cxx<jobject, champ>(v));
}


///
// Fonction appelée au début de la partie.
//
extern "C" void partie_init()
{
  bool attached = jrt.function_enter();
  jmethodID method = jrt.env->GetMethodID(Prologin::Class(), "partie_init", "()V");
  jrt.env->CallVoidMethod(jrt.prologin, method);
  if (jrt.env->ExceptionOccurred())
  {
    jrt.env->ExceptionDescribe();
    exit(1);
  }
  jrt.function_exit(attached);
}


///
// Fonction appelée à chaque tour.
//
extern "C" void jouer_tour()
{
  bool attached = jrt.function_enter();
  jmethodID method = jrt.env->GetMethodID(Prologin::Class(), "jouer_tour", "()V");
  jrt.env->CallVoidMethod(jrt.prologin, method);
  if (jrt.env->ExceptionOccurred())
  {
    jrt.env->ExceptionDescribe();
    exit(1);
  }
  jrt.function_exit(attached);
}


///
// Fonction appelée à la fin de la partie.
//
extern "C" void partie_fin()
{
  bool attached = jrt.function_enter();
  jmethodID method = jrt.env->GetMethodID(Prologin::Class(), "partie_fin", "()V");
  jrt.env->CallVoidMethod(jrt.prologin, method);
  if (jrt.env->ExceptionOccurred())
  {
    jrt.env->ExceptionDescribe();
    exit(1);
  }
  jrt.function_exit(attached);
}


jclass Prologin::Class()
{
  return jrt.env->FindClass("Prologin");
}

jclass Erreur::Class()
{
  return jrt.env->FindClass("Erreur");
}

jclass Position::Class()
{
  return jrt.env->FindClass("Position");
}

jclass Lien::Class()
{
  return jrt.env->FindClass("Lien");
}

jclass Champ::Class()
{
  return jrt.env->FindClass("Champ");
}

static void _register_native_methods(JNIEnv* env)
{
  JNINativeMethod methods[] = {
    {(char*)"deplacer", (char*)"(LPosition;)LErreur;", (void*)&deplacer},
    {(char*)"utiliser_turbo", (char*)"()LErreur;", (void*)&utiliser_turbo},
    {(char*)"capturer", (char*)"()LErreur;", (void*)&capturer},
    {(char*)"lier", (char*)"(LPosition;)LErreur;", (void*)&lier},
    {(char*)"neutraliser", (char*)"()LErreur;", (void*)&neutraliser},
    {(char*)"ajouter_bouclier", (char*)"()LErreur;", (void*)&ajouter_bouclier},
    {(char*)"liste_liens", (char*)"()[LLien;", (void*)&liste_liens},
    {(char*)"liste_champs", (char*)"()[LChamp;", (void*)&liste_champs},
    {(char*)"liste_portails", (char*)"()[LPosition;", (void*)&liste_portails},
    {(char*)"liens_bloquants", (char*)"(LPosition;LPosition;)[LLien;", (void*)&liens_bloquants},
    {(char*)"lien_existe", (char*)"(LPosition;LPosition;)Z", (void*)&lien_existe},
    {(char*)"champ_existe", (char*)"(LPosition;LPosition;LPosition;)Z", (void*)&champ_existe},
    {(char*)"case_dans_champ", (char*)"(LPosition;)Z", (void*)&case_dans_champ},
    {(char*)"case_champs", (char*)"(LPosition;)[LChamp;", (void*)&case_champs},
    {(char*)"portail_joueur", (char*)"(LPosition;)I", (void*)&portail_joueur},
    {(char*)"portail_boucliers", (char*)"(LPosition;)I", (void*)&portail_boucliers},
    {(char*)"liens_incidents_portail", (char*)"(LPosition;)[LLien;", (void*)&liens_incidents_portail},
    {(char*)"champs_incidents_portail", (char*)"(LPosition;)[LChamp;", (void*)&champs_incidents_portail},
    {(char*)"champs_incidents_segment", (char*)"(LPosition;LPosition;)[LChamp;", (void*)&champs_incidents_segment},
    {(char*)"hist_portails_captures", (char*)"()[LPosition;", (void*)&hist_portails_captures},
    {(char*)"hist_portails_neutralises", (char*)"()[LPosition;", (void*)&hist_portails_neutralises},
    {(char*)"hist_liens_crees", (char*)"()[LLien;", (void*)&hist_liens_crees},
    {(char*)"hist_champs_crees", (char*)"()[LChamp;", (void*)&hist_champs_crees},
    {(char*)"hist_boucliers_ajoutes", (char*)"()[LPosition;", (void*)&hist_boucliers_ajoutes},
    {(char*)"distance", (char*)"(LPosition;LPosition;)I", (void*)&distance},
    {(char*)"score_triangle", (char*)"(LPosition;LPosition;LPosition;)I", (void*)&score_triangle},
    {(char*)"intersection_segments", (char*)"(LPosition;LPosition;LPosition;LPosition;)Z", (void*)&intersection_segments},
    {(char*)"point_dans_triangle", (char*)"(LPosition;LPosition;LPosition;LPosition;)Z", (void*)&point_dans_triangle},
    {(char*)"moi", (char*)"()I", (void*)&moi},
    {(char*)"adversaire", (char*)"()I", (void*)&adversaire},
    {(char*)"position_agent", (char*)"(I)LPosition;", (void*)&position_agent},
    {(char*)"points_action", (char*)"()I", (void*)&points_action},
    {(char*)"points_deplacement", (char*)"()I", (void*)&points_deplacement},
    {(char*)"score", (char*)"(I)I", (void*)&score},
    {(char*)"tour_actuel", (char*)"()I", (void*)&tour_actuel},
    {(char*)"annuler", (char*)"()Z", (void*)&annuler},
    {(char*)"afficher_erreur", (char*)"(LErreur;)V", (void*)&afficher_erreur},
    {(char*)"afficher_position", (char*)"(LPosition;)V", (void*)&afficher_position},
    {(char*)"afficher_lien", (char*)"(LLien;)V", (void*)&afficher_lien},
    {(char*)"afficher_champ", (char*)"(LChamp;)V", (void*)&afficher_champ}
  };
  env->RegisterNatives(Prologin::Class(), methods, sizeof(methods)/sizeof(methods[0]));
}

ProloginJavaRunTime jrt;

ProloginJavaRunTime::ProloginJavaRunTime()
{
 std::string classpath = "-Djava.class.path=";
  char* champion_path = getenv("CHAMPION_PATH");
  if (champion_path == NULL)
    champion_path = (char*)"./";
  classpath.append(champion_path);

  JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
  JavaVMOption options[2];
  options[0].optionString = (char*)classpath.c_str();
  options[1].optionString = (char*)"-ea";
  vm_args.version = JNI_VERSION_1_6;
  vm_args.nOptions = 2;
  vm_args.options = options;
  vm_args.ignoreUnrecognized = false;
  JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
  prologin = env->NewObject(Prologin::Class(), env->GetMethodID(Prologin::Class(), "<init>", "()V"));
  _register_native_methods(env);
}

ProloginJavaRunTime::~ProloginJavaRunTime()
{
  jvm->DestroyJavaVM();
}

bool ProloginJavaRunTime::function_enter()
{
  if (jvm->GetEnv((void**)&env, JNI_VERSION_1_6) == JNI_OK)
    return false;
  jvm->AttachCurrentThread((void**)&env, NULL);
  return true;
}

void ProloginJavaRunTime::function_exit(bool attached)
{
  if (attached)
    jvm->DetachCurrentThread();
}

