#include "maslab_camera_Camera.h"
#include "camera.h"

#include <stdlib.h>
#include <assert.h>

/* a table mapping camera descriptors (int) to camera_t pointers */
static camera_t  **camdescriptors=NULL;

/* number of entries in table, above */
static int       camdescriptors_size=0;

/* number of populated entries in table */
static int       camdescriptors_count=0;

/* given a camera descriptor, return the camera_t pointer. returns null
   if cd is invalid.
*/
static camera_t *get_cam(int cd)
{
  if (cd<0 || cd>=camdescriptors_size)
    return NULL;

  return camdescriptors[cd];
}

/* Double the size of the camdescriptors table, or allocate a new one
   if no table is allocated.
*/
static void realloc_camdescriptors()
{
  int oldsize=camdescriptors_size;
  int newsize=oldsize*2;
  int i;

  if (newsize<16)
    newsize=16;

  camdescriptors=(camera_t**) realloc(camdescriptors, sizeof(camera_t*)*newsize);
  for (i=oldsize;i<newsize;i++)
    camdescriptors[i]=0;

  camdescriptors_size=newsize;
}

/* allocate a new camera descriptor, which will map to the specified camera_t object */
static int alloc_cd(camera_t *cam)
{
  int i;

  if (camdescriptors_count>=camdescriptors_size)
    realloc_camdescriptors();

  for (i=0;i<camdescriptors_size;i++)
    {
      if (camdescriptors[i]==0)
	{
	  camdescriptors[i]=cam;
	  camdescriptors_count++;
	  return i;
	}
    }

  assert(1);
  return -1;
}

/* free a camera descriptor. */
static void free_cd(int cd)
{
  if (cd<0 || cd>=camdescriptors_size)
    return;

  if (camdescriptors[cd]==0)
    return;

  camdescriptors[cd]=0;
  camdescriptors_count--;
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_open
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1open
(JNIEnv *jenv, jclass c, jstring devname)
{
  const char *str=(*jenv)->GetStringUTFChars(jenv, devname, 0);
  camera_t *cam = camera_open(str);
  if (cam == NULL)
    return -1;

  jint ref = alloc_cd(cam);

  (*jenv)->ReleaseStringUTFChars(jenv, devname, str);

  return ref;
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_close
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1close
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_close(cam);

  free_cd(ref);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_capture
 * Signature: ([B)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1capture
(JNIEnv *jenv, jclass c, jint ref, jintArray image)
{
  int *buf;

  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  buf = (*jenv)->GetIntArrayElements(jenv, image, 0);
  camera_capture(cam, (unsigned char *)buf);
  (*jenv)->ReleaseIntArrayElements(jenv, image, buf, 0);
}


/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_capture_settings
 * Signature: (IIII)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1capture_1settings
(JNIEnv *jenv, jclass c, jint ref, jint width, jint height, jint fps)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;
  
  camera_set_capture_settings(cam, width, height,fps);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_width
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1width
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return cam->width;
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_height
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1height
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return cam->height;
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_fps
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1fps
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return cam->fps;
}


/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_white_balance
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1white_1balance
(JNIEnv *jenv, jclass c, jint ref, jint mode, jint red, jint blue)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_white_balance(cam, mode, red, blue);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_led
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1led
(JNIEnv *jenv, jclass c, jint ref, jint on_time, jint off_time)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_led(cam, on_time, off_time);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_led_on
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1led_1on
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_led_on(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_led_off
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1led_1off
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_led_off(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_white_balance
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1white_1balance
(JNIEnv *jenv, jclass c, jint ref, jint field)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_white_balance(cam, field);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_quality
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1quality
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_quality(cam, value);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_quality
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1quality
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_quality(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_contour
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1contour
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_contour(cam, value);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_contour
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1contour
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_contour(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_backlight
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1backlight
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_backlight(cam, value);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_backlight
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1backlight
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_backlight(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_flicker
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1flicker
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_flicker(cam, value);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_flicker
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1flicker
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_flicker(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_noisereduction
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1noisereduction
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_noisereduction(cam, value);
}  

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_noisereduction
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1noisereduction
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_noisereduction(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_gain
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1gain
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_gain(cam, value);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_get_gain
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_maslab_camera_Camera_camera_1get_1gain
(JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return 0;

  return camera_get_gain(cam);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    camera_set_shutter
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1shutter
(JNIEnv *jenv, jclass c, jint ref, jint value)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_shutter(cam, value);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    rgb_to_hsv
 * Signature: ([I)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_rgb_1to_1hsv
(JNIEnv *jenv, jclass c, jintArray image, jint width, jint height)
{
  int *buf;

  buf = (*jenv)->GetIntArrayElements(jenv, image, 0);
  rgb_to_hsv((unsigned char *) buf, width, height);
  (*jenv)->ReleaseIntArrayElements(jenv, image, buf, 0);

}

/*
 * Class:     maslab_camera_Camera
 * Method:    rgb_to_rgv
 * Signature: ([III)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_rgb_1to_1rgv
(JNIEnv *jenv, jclass c, jintArray image, jint width, jint height)
{
  int *buf;

  buf = (*jenv)->GetIntArrayElements(jenv, image, 0);
  rgb_to_rgv((unsigned char *) buf, width, height);
  (*jenv)->ReleaseIntArrayElements(jenv, image, buf, 0);
}

/*
 * Class:     maslab_camera_Camera
 * Method:    channel_select
 * Signature: ([IIII)V
 */
JNIEXPORT void JNICALL Java_maslab_camera_Camera_channel_1select
(JNIEnv *jenv, jclass c, jintArray image, jint width, jint height, jint channel)
{
  int *buf;

  buf = (*jenv)->GetIntArrayElements(jenv, image, 0);
  channel_select((unsigned char *) buf, width, height, channel);
  (*jenv)->ReleaseIntArrayElements(jenv, image, buf, 0);

}


JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1get_1factory
  (JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_get_factory(cam);

}

JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1get_1user
  (JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_get_user(cam);

}

JNIEXPORT void JNICALL Java_maslab_camera_Camera_camera_1set_1user
  (JNIEnv *jenv, jclass c, jint ref)
{
  camera_t *cam = get_cam(ref);
  if (cam == NULL)
    return;

  camera_set_user(cam);

}
