// This DLL is not thread safe.
//

#include <jni.h>

#include "fantom/iNXT.h"
#include "fantom/iNXTIterator.h"
#include "fantom/tStatus.h"

#include <string.h>
#include <stdio.h>

//#pragma comment(lib, "fantom.lib")


/*********************************************************************************/
/* Enumerating devices                                     */
/*********************************************************************************/

nFANTOM100::iNXTIterator* nxtIteratorPtr = NULL;
ViChar name[256];

extern "C" JNIEXPORT jstring JNICALL Java_sivantoledo_nxt_FantomInterface_scanFirst
  (JNIEnv *env, jclass C)
{
  nFANTOM100::tStatus status;
  nFANTOM100::iNXT* nxtPtr = NULL;

  nxtIteratorPtr = nFANTOM100::iNXT::createNXTIterator(
         true, // search over Bluetooth
         15,   // timeout for Bluetooth discovery ignored 
         status); 
   if (status.isFatal() || status.getCode() == nFANTOM100::kStatusNoMoreItemsFound) {
    nFANTOM100::iNXT::destroyNXTIterator(nxtIteratorPtr);
    return NULL;
   }

   nxtIteratorPtr->getName(name,status);
   if (status.isFatal()) {
    nFANTOM100::iNXT::destroyNXTIterator(nxtIteratorPtr);
    return NULL;
   }

   return (*env).NewStringUTF(name);
}

extern "C" JNIEXPORT jstring JNICALL Java_sivantoledo_nxt_FantomInterface_scanNext
  (JNIEnv *env, jclass C)
{
  nFANTOM100::tStatus status;
  nFANTOM100::iNXT* nxtPtr = NULL;

  nxtIteratorPtr->advance(status);
   if (status.isFatal() || status.getCode() == nFANTOM100::kStatusNoMoreItemsFound) {
    nFANTOM100::iNXT::destroyNXTIterator(nxtIteratorPtr);
    return NULL;
   }

   nxtIteratorPtr->getName(name,status);
   if (status.isFatal()) {
    nFANTOM100::iNXT::destroyNXTIterator(nxtIteratorPtr);
    return NULL;
   }

   return env->NewStringUTF(name);
}

/*********************************************************************************/
/* connect/disconnect                                     */
/*********************************************************************************/

nFANTOM100::iNXT* nxtPtr = NULL;

extern "C" JNIEXPORT jint JNICALL Java_sivantoledo_nxt_FantomInterface_connect
  (JNIEnv *env, jclass C, jstring name)
{
  nFANTOM100::tStatus status;
  //nFANTOM100::iNXT* nxtPtr = NULL;

  const char *resource_name = env->GetStringUTFChars(name, 0);
  nxtPtr = NULL;

  int is_paired = nFANTOM100::iNXT::isPaired(resource_name,status);
  if (status.isNotFatal()) {
    printf("is paired? %d\n",is_paired);
  }

  nxtPtr = nFANTOM100::iNXT::createNXT(resource_name,
                                       status,
                                       true);

  //printf("code %d\n",status.getCode());
  return status.getCode();
}

extern "C" JNIEXPORT void JNICALL Java_sivantoledo_nxt_FantomInterface_disconnect
  (JNIEnv *env, jclass C)
{
  nFANTOM100::tStatus status;

  nFANTOM100::iNXT::destroyNXT(nxtPtr);

  nxtPtr = NULL;
}

/*********************************************************************************/
/* send/receive                                                                  */
/*********************************************************************************/

unsigned char buffer[256];
unsigned char response[256];

extern "C" JNIEXPORT jint JNICALL Java_sivantoledo_nxt_FantomInterface_rawreceive
  (JNIEnv *env, jclass C, jbyteArray outbuffer)
{
  nFANTOM100::tStatus status;
  jint error;

  int bytes_read = nxtPtr->read(buffer,256,status);
  if (status.isFatal()) {
    //printf("receive code %d: %s\n",status.getCode(), status_string(status.getCode()));
    return -1;
  }

  //printf("fantom read %d bytes from the nxt\n",bytes_read);

  env->SetByteArrayRegion(outbuffer, 0, bytes_read, (jbyte*) buffer);

  return bytes_read;
}

extern "C" JNIEXPORT jint JNICALL Java_sivantoledo_nxt_FantomInterface_rawsend
  (JNIEnv *env, jclass C, jbyteArray inbuffer, jint length)
{
  nFANTOM100::tStatus status;
  jint error;

  env->GetByteArrayRegion(inbuffer, 0, length, (jbyte*) buffer);

  int bytes_written = nxtPtr->write(buffer,length,status);
  if (status.isFatal())
    return -1;

  //printf("fantom wrote %d bytes to the nxt\n",bytes_written);

  return bytes_written;
}

extern "C" JNIEXPORT jint JNICALL Java_sivantoledo_nxt_FantomInterface_directCommand
  (JNIEnv *env, jclass C, jbyteArray command_buffer,  jint command_length, 
                          jbyteArray response_buffer, jint response_length)
{
  nFANTOM100::tStatus status;
  jint error;

  env->GetByteArrayRegion(command_buffer, 0, command_length, (jbyte*) buffer);

  int bytes_read = nxtPtr->sendDirectCommand( (response_length != 0),
                                              buffer, command_length,
                                              (response_length != 0) ? response : NULL,
                                              response_length,
                                              status );
  if (status.isFatal()) {
    //printf("receive code %d: %s\n",status.getCode(), status_string(status.getCode()));
    return -1;
  }

  //printf("fantom read %d bytes from the nxt\n",bytes_read);

  env->SetByteArrayRegion(response_buffer, 0, bytes_read, (jbyte*) response);

  return bytes_read;
}
