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


/// Types de cases
template<>
case_type lang2cxx<jobject, case_type>(jobject in)
{
  jmethodID ordinal = jrt.env->GetMethodID(CaseType::Class(), "ordinal", "()I");
  return case_type(lang2cxx<jint, int>(jrt.env->CallIntMethod(in, ordinal)));
}

template<>
jobject cxx2lang<case_type, jobject>(case_type in)
{
  jmethodID method = jrt.env->GetStaticMethodID(CaseType::Class(), "values", "()[LCaseType;");
  jobjectArray values = (jobjectArray)jrt.env->CallStaticObjectMethod(CaseType::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 pulsar existant.
template <>
pulsar_info lang2cxx<jobject, pulsar_info>(jobject in)
{
  pulsar_info out;
  out.periode = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(PulsarInfo::Class(), "periode", "I")));
  out.puissance = lang2cxx<jdouble, double>(jrt.env->GetDoubleField(in, jrt.env->GetFieldID(PulsarInfo::Class(), "puissance", "D")));
  out.pulsations_restantes = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(PulsarInfo::Class(), "pulsations_restantes", "I")));
  out.pulsations_totales = lang2cxx<jint, int>(jrt.env->GetIntField(in, jrt.env->GetFieldID(PulsarInfo::Class(), "pulsations_totales", "I")));
  return out;
}

template <>
jobject cxx2lang<pulsar_info, jobject>(pulsar_info in)
{
  jobject out = jrt.env->NewObject(PulsarInfo::Class(), jrt.env->GetMethodID(PulsarInfo::Class(), "<init>", "()V"));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(PulsarInfo::Class(), "periode", "I"), cxx2lang<int, jint>(in.periode));
  jrt.env->SetDoubleField(out, jrt.env->GetFieldID(PulsarInfo::Class(), "puissance", "D"), cxx2lang<double, jdouble>(in.puissance));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(PulsarInfo::Class(), "pulsations_restantes", "I"), cxx2lang<int, jint>(in.pulsations_restantes));
  jrt.env->SetIntField(out, jrt.env->GetFieldID(PulsarInfo::Class(), "pulsations_totales", "I"), cxx2lang<int, jint>(in.pulsations_totales));
  return out;
}


/// Construit un tuyau sur une case donnée.
jobject construire(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<erreur, jobject>(api_construire(lang2cxx<jobject, position>(pos)));
}


/// Améliore un tuyau en Super Tuyau™.
jobject ameliorer(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<erreur, jobject>(api_ameliorer(lang2cxx<jobject, position>(pos)));
}


/// Détruit un tuyau sur une case donnée.
jobject detruire(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<erreur, jobject>(api_detruire(lang2cxx<jobject, position>(pos)));
}


/// Déplace une unité de puissance d'aspiration d'une case de votre base vers une autre.
jobject deplacer_aspiration(JNIEnv* _env, jobject _obj, jobject source, jobject destination)
{
  return cxx2lang<erreur, jobject>(api_deplacer_aspiration(lang2cxx<jobject, position>(source), lang2cxx<jobject, position>(destination)));
}


/// Déblaye une case de débris.
jobject deblayer(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<erreur, jobject>(api_deblayer(lang2cxx<jobject, position>(pos)));
}


/// Renvoie le type d'une case donnée.
jobject type_case(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<case_type, jobject>(api_type_case(lang2cxx<jobject, position>(pos)));
}


/// Renvoie la liste de tous les pulsars présents.
jarray liste_pulsars(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_liste_pulsars());
}


/// Renvoie la liste des cases contenant du plasma.
jarray liste_plasmas(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_liste_plasmas());
}


/// Renvoie la liste des cases contenant un tuyau ou Super Tuyau™.
jarray liste_tuyaux(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_liste_tuyaux());
}


/// Renvoie la liste des cases contenant un Super Tuyau™.
jarray liste_super_tuyaux(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_liste_super_tuyaux());
}


/// Renvoie la liste des cases contenant des débris.
jarray liste_debris(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_liste_debris());
}


/// Renvoie vrai si et seulement si la case contient un pulsar.
jboolean est_pulsar(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_est_pulsar(lang2cxx<jobject, position>(pos)));
}


/// Renvoie vrai si et seulement si la case contient un tuyau ou un Super Tuyau™.
jboolean est_tuyau(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_est_tuyau(lang2cxx<jobject, position>(pos)));
}


/// Renvoie vrai si et seulement si la case contient un simple tuyau.
jboolean est_simple_tuyau(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_est_simple_tuyau(lang2cxx<jobject, position>(pos)));
}


/// Renvoie vrai si et seulement si la case contient un Super Tuyau™.
jboolean est_super_tuyau(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_est_super_tuyau(lang2cxx<jobject, position>(pos)));
}


/// Renvoie vrai si et seulement si la case contient un débris.
jboolean est_debris(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_est_debris(lang2cxx<jobject, position>(pos)));
}


/// Renvoie vrai si et seulement s'il est possible de construire sur cette case.
jboolean est_libre(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<boolean, jboolean>(api_est_libre(lang2cxx<jobject, position>(pos)));
}


/// Renvoie les informations propres au pulsar à la position donnée.
jobject info_pulsar(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<pulsar_info, jobject>(api_info_pulsar(lang2cxx<jobject, position>(pos)));
}


/// Renvoie la quantité de plasma sur une case donnée.
jdouble charges_presentes(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<double, jdouble>(api_charges_presentes(lang2cxx<jobject, position>(pos)));
}


/// Renvoie le numéro du joueur ayant dernièrement construit ou amélioré un tuyau sur une case.
jint constructeur_tuyau(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<int, jint>(api_constructeur_tuyau(lang2cxx<jobject, position>(pos)));
}


/// Renvoie le numéro du propriétaire d'une case de base.
jint proprietaire_base(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<int, jint>(api_proprietaire_base(lang2cxx<jobject, position>(pos)));
}


/// Renvoie la liste des cases composant votre base.
jarray ma_base(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_ma_base());
}


/// Renvoie la liste des cases composant la base de votre ennemi.
jarray base_ennemie(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_base_ennemie());
}


/// Renvoie la puissance d'aspiration d'une case de base donnée. Renvoie -1 si la position n'est pas celle d'une base.
jint puissance_aspiration(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang<int, jint>(api_puissance_aspiration(lang2cxx<jobject, position>(pos)));
}


/// Renvoie pour une case donnée la liste des cases vers lesquelles le plasma se propagera. Renvoie la liste vide si la case n'est pas une case contenant un tuyau ou si elle n'est reliée à aucune base.
jarray directions_plasma(JNIEnv* _env, jobject _obj, jobject pos)
{
  return cxx2lang_array<position, Position>(api_directions_plasma(lang2cxx<jobject, position>(pos)));
}


/// Renvoie la valeur du coût de la prochaine modification de vos puissances d'aspiration.
jint cout_prochaine_modification_aspiration(JNIEnv* _env, jobject _obj)
{
  return cxx2lang<int, jint>(api_cout_prochaine_modification_aspiration());
}


/// Renvoie la liste des tuyaux construits par votre adversaire au dernier tour.
jarray hist_tuyaux_construits(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_tuyaux_construits());
}


/// Renvoie la liste des tuyaux détruits par votre adversaire au dernier tour.
jarray hist_tuyaux_detruits(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_tuyaux_detruits());
}


/// Renvoie la liste des tuyaux améliorés par votre adversaire au dernier tour.
jarray hist_tuyaux_ameliores(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_tuyaux_ameliores());
}


/// Renvoie la liste des débris déblayés par votre adversaire au dernier tour.
jarray hist_debris_deblayes(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_debris_deblayes());
}


/// Renvoie la liste des cases de base de votre adversaire qui ont reçu un point d'aspiration (une même case peut apparaître plusieurs fois).
jarray hist_points_aspiration_ajoutes(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_points_aspiration_ajoutes());
}


/// Renvoie la liste des cases de base de votre adversaire qui ont perdu un point d'aspiration (une même case peut apparaître plusieurs fois).
jarray hist_points_aspiration_retires(JNIEnv* _env, jobject _obj)
{
  return cxx2lang_array<position, Position>(api_hist_points_aspiration_retires());
}


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


/// Renvoie le score du joueur désigné par le numéro ``id_joueur``. Renvoie -1 si ``id_joueur`` est invalide.
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 case_type
void afficher_case_type(JNIEnv* _env, jobject _obj, jobject v)
{
  api_afficher_case_type(lang2cxx<jobject, case_type>(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 pulsar_info
void afficher_pulsar_info(JNIEnv* _env, jobject _obj, jobject v)
{
  api_afficher_pulsar_info(lang2cxx<jobject, pulsar_info>(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 CaseType::Class()
{
  return jrt.env->FindClass("CaseType");
}

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

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

static void _register_native_methods(JNIEnv* env)
{
  JNINativeMethod methods[] = {
    {(char*)"construire", (char*)"(LPosition;)LErreur;", (void*)&construire},
    {(char*)"ameliorer", (char*)"(LPosition;)LErreur;", (void*)&ameliorer},
    {(char*)"detruire", (char*)"(LPosition;)LErreur;", (void*)&detruire},
    {(char*)"deplacer_aspiration", (char*)"(LPosition;LPosition;)LErreur;", (void*)&deplacer_aspiration},
    {(char*)"deblayer", (char*)"(LPosition;)LErreur;", (void*)&deblayer},
    {(char*)"type_case", (char*)"(LPosition;)LCaseType;", (void*)&type_case},
    {(char*)"liste_pulsars", (char*)"()[LPosition;", (void*)&liste_pulsars},
    {(char*)"liste_plasmas", (char*)"()[LPosition;", (void*)&liste_plasmas},
    {(char*)"liste_tuyaux", (char*)"()[LPosition;", (void*)&liste_tuyaux},
    {(char*)"liste_super_tuyaux", (char*)"()[LPosition;", (void*)&liste_super_tuyaux},
    {(char*)"liste_debris", (char*)"()[LPosition;", (void*)&liste_debris},
    {(char*)"est_pulsar", (char*)"(LPosition;)Z", (void*)&est_pulsar},
    {(char*)"est_tuyau", (char*)"(LPosition;)Z", (void*)&est_tuyau},
    {(char*)"est_simple_tuyau", (char*)"(LPosition;)Z", (void*)&est_simple_tuyau},
    {(char*)"est_super_tuyau", (char*)"(LPosition;)Z", (void*)&est_super_tuyau},
    {(char*)"est_debris", (char*)"(LPosition;)Z", (void*)&est_debris},
    {(char*)"est_libre", (char*)"(LPosition;)Z", (void*)&est_libre},
    {(char*)"info_pulsar", (char*)"(LPosition;)LPulsarInfo;", (void*)&info_pulsar},
    {(char*)"charges_presentes", (char*)"(LPosition;)D", (void*)&charges_presentes},
    {(char*)"constructeur_tuyau", (char*)"(LPosition;)I", (void*)&constructeur_tuyau},
    {(char*)"proprietaire_base", (char*)"(LPosition;)I", (void*)&proprietaire_base},
    {(char*)"ma_base", (char*)"()[LPosition;", (void*)&ma_base},
    {(char*)"base_ennemie", (char*)"()[LPosition;", (void*)&base_ennemie},
    {(char*)"puissance_aspiration", (char*)"(LPosition;)I", (void*)&puissance_aspiration},
    {(char*)"directions_plasma", (char*)"(LPosition;)[LPosition;", (void*)&directions_plasma},
    {(char*)"cout_prochaine_modification_aspiration", (char*)"()I", (void*)&cout_prochaine_modification_aspiration},
    {(char*)"hist_tuyaux_construits", (char*)"()[LPosition;", (void*)&hist_tuyaux_construits},
    {(char*)"hist_tuyaux_detruits", (char*)"()[LPosition;", (void*)&hist_tuyaux_detruits},
    {(char*)"hist_tuyaux_ameliores", (char*)"()[LPosition;", (void*)&hist_tuyaux_ameliores},
    {(char*)"hist_debris_deblayes", (char*)"()[LPosition;", (void*)&hist_debris_deblayes},
    {(char*)"hist_points_aspiration_ajoutes", (char*)"()[LPosition;", (void*)&hist_points_aspiration_ajoutes},
    {(char*)"hist_points_aspiration_retires", (char*)"()[LPosition;", (void*)&hist_points_aspiration_retires},
    {(char*)"moi", (char*)"()I", (void*)&moi},
    {(char*)"adversaire", (char*)"()I", (void*)&adversaire},
    {(char*)"points_action", (char*)"()I", (void*)&points_action},
    {(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_case_type", (char*)"(LCaseType;)V", (void*)&afficher_case_type},
    {(char*)"afficher_position", (char*)"(LPosition;)V", (void*)&afficher_position},
    {(char*)"afficher_pulsar_info", (char*)"(LPulsarInfo;)V", (void*)&afficher_pulsar_info}
  };
  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();
}

