 /*************************************************************************/
 /*                                                                       */
 /*                Centre for Speech Technology Research                  */
 /*                     University of Edinburgh, UK                       */
 /*                      Copyright (c) 1995,1996                          */
 /*                        All Rights Reserved.                           */
 /*                                                                       */
 /*  Permission is hereby granted, free of charge, to use and distribute  */
 /*  this software and its documentation without restriction, including   */
 /*  without limitation the rights to use, copy, modify, merge, publish,  */
 /*  distribute, sublicense, and/or sell copies of this work, and to      */
 /*  permit persons to whom this work is furnished to do so, subject to   */
 /*  the following conditions:                                            */
 /*   1. The code must retain the above copyright notice, this list of    */
 /*      conditions and the following disclaimer.                         */
 /*   2. Any modifications must be clearly marked as such.                */
 /*   3. Original authors' names are not deleted.                         */
 /*   4. The authors' names are not used to endorse or promote products   */
 /*      derived from this software without specific prior written        */
 /*      permission.                                                      */
 /*                                                                       */
 /*  THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK        */
 /*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
 /*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
 /*  SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE     */
 /*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
 /*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
 /*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
 /*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
 /*  THIS SOFTWARE.                                                       */
 /*                                                                       */
 /*************************************************************************/
 /*                                                                       */
 /*                 Author: Richard Caley <rjc@cstr.ed.ac.uk>             */
 /* -------------------------------------------------------------------   */
 /* Interface between java and C++ for EST_Features.                  */
 /*                                                                       */
 /*************************************************************************/


#include <stdio.h>
#include "jni_Features.h"
#include "EST_Features.h"

static jclass features_class;
static jmethodID features_cons;
static jclass string_class;
static jclass float_class;
static jmethodID float_cons;
static jclass int_class;
static jmethodID int_cons;
static jfieldID handle_field;

static inline short abs(short s) { return s>0?s:-s; }

JNIEXPORT jboolean JNICALL
Java_cstr_est_Features_initialise_1cpp (JNIEnv *env, jclass myclass)
{
  features_class = (jclass)env->NewGlobalRef(myclass);
  handle_field = env->GetFieldID(myclass, "cpp_handle", "J");

  if (!handle_field)
    {
    printf("can't find handle!\n");
    return 0;
    }

  features_cons = env->GetMethodID(features_class, "<init>", "(J)V");

  if (!features_cons)
    {
    printf("can't find features_cons!\n");
    return 0;
    }

   string_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/String"));
   float_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/Float"));
   float_cons = env->GetMethodID(float_class, "<init>", "(F)V");

   if (!float_cons)
     {
       printf("can't find float_cons!\n");
       return 0;
     }
   int_class = (jclass)env->NewGlobalRef(env->FindClass("java/lang/Integer"));

   int_cons = env->GetMethodID(int_class, "<init>", "(I)V");
  return 1;
}

JNIEXPORT jboolean JNICALL 
Java_cstr_est_Features_finalise_1cpp (JNIEnv *env, jclass myclass)
{
  (void)env;
  (void)myclass;
  return 1;
}

JNIEXPORT jboolean JNICALL 
Java_cstr_est_Features_create_1cpp_1features(JNIEnv *env, 
						  jobject self,
						  jlong handle
						  )
{
  EST_Features *features = (handle==0L
			    ? (new EST_Features)
			    : (EST_Features *)handle
			    );

  // printf("create features %p\n", features);

  env->SetLongField(self, handle_field, (jlong)features);

  return 1;
}

JNIEXPORT jboolean JNICALL 
Java_cstr_est_Features_destroy_1cpp_1features (JNIEnv *env, jobject self)
{
  EST_Features *features = (EST_Features *) env->GetLongField(self, handle_field);

  // printf("destroy features  %p\n", features);

  delete features;
  return 1;
}

JNIEXPORT jobjectArray JNICALL 
Java_cstr_est_Features_cpp_1featureNames (JNIEnv *env, jobject self)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  
  int n;
  EST_Features::Entries p;

  n=0;
  for (p.begin(*f); p != 0; ++p)
      n++;

  jobjectArray names = env->NewObjectArray(n, string_class, NULL);

  p.beginning();

  for(int i=0; i<n; i++)
    {
      jstring fn = env->NewStringUTF(p->k);
      env->SetObjectArrayElement(names, i, fn);
      ++p;
    }
  return names;
}


JNIEXPORT jstring JNICALL 
Java_cstr_est_Features_cpp_1getS(JNIEnv *env, 
	jobject self, 
	jstring jname,
	jstring jdef)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  const char *name = env->GetStringUTFChars(jname, 0);
  
  EST_Val def;
  const EST_Val &val = f->val_path(name, def);

  env->ReleaseStringUTFChars(jname, name);
  
  if (&def == &val)
    return jdef;

  return  env->NewStringUTF(val.S());
}

JNIEXPORT jfloat JNICALL 
Java_cstr_est_Features_cpp_1getF(JNIEnv *env, 
	jobject self, 
	jstring jname,
	jfloat  def)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  const char *name = env->GetStringUTFChars(jname, 0);
  
  float val = f->F(name, def);

  env->ReleaseStringUTFChars(jname, name);
  
  return  val;
  
}

JNIEXPORT jobject JNICALL 
Java_cstr_est_Features_cpp_1get(JNIEnv *env, 
	jobject self, 
	jstring jname,
	jobject  jdef)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  const char *name = env->GetStringUTFChars(jname, 0);
  
  EST_Val def("hidden");
  const EST_Val &val = f->val(name, def);

  env->ReleaseStringUTFChars(jname, name);
  
  if (&def == &val)
    {
      //fprintf(stderr, "get %s =%s\n", name, "def");
      return jdef;
    }

  jobject jval;

  val_type t = val.type();

  //fprintf(stderr, "get %s =%s (%s)\n", name, (const char *)val.S(), t);

  if (t==val_type_feats)
    {
      jval = env->NewObject(features_class, features_cons, (jlong)feats(val));
    }
  else if (t==val_float)
    {
      jval = env->NewObject(float_class, float_cons, (jfloat)val.F());
    }
  else if (t==val_int)
    {
      jval = env->NewObject(int_class, int_cons, (jint)val.I());
    }
  else
    {
      jval = env->NewStringUTF(val.S());
    }
    

  return  jval;
}

JNIEXPORT void JNICALL 
Java_cstr_est_Features_cpp_1set__Ljava_lang_String_2F(JNIEnv *env, jobject self, jstring jname, jfloat val)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  const char *name = env->GetStringUTFChars(jname, 0);

  f->set(name, val);
  
  env->ReleaseStringUTFChars(jname, name);
}

JNIEXPORT void JNICALL 
Java_cstr_est_Features_cpp_1set__Ljava_lang_String_2Ljava_lang_String_2(JNIEnv *env, jobject self, jstring jname, jstring jval)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  const char *name = env->GetStringUTFChars(jname, 0);
  const char *val = env->GetStringUTFChars(jval, 0);

  f->set(name, val);
  
  env->ReleaseStringUTFChars(jname, name);
  env->ReleaseStringUTFChars(jval, val);
}

JNIEXPORT jboolean JNICALL 
Java_cstr_est_Features_cpp_1present(JNIEnv *env, jobject self, jstring jname)
{
  EST_Features *f = (EST_Features *) env->GetLongField(self, handle_field);
  const char *name = env->GetStringUTFChars(jname, 0);
  
  int val = f->present(name);

  env->ReleaseStringUTFChars(jname, name);

  return  val;
}





