/*
-----------------------------------------------------------------------------
This source file is part of OpenSpace3D
For the latest info, see http://www.openspace3d.com

Copyright (c) 2010 I-maginer

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

You may alternatively use this source under the terms of a specific version of
the OpenSpace3D Unrestricted License provided you have obtained such a license from
I-maginer.
-----------------------------------------------------------------------------
*/

/*
 5DT Data Glove library based on fglove library
 First version : april 2011
 Author : Aymeric Suteau
*/

/*! @defgroup grpglove Scol functions definition
 *  Scol functions definition
 *  @{
 */
/** @} */


// Include Header File
#include "Glove.h"

//!Scol machine declaration for MM macros
cbmachine ww;
HWND HScol = NULL;

//!Scol object declaration 
int OBJGLOVESCOL;

//!Scol CallBacks declaration 
//===== CB New data (without thumb) ===
int SCOL_GLOVE_NEWDATA_CB                 = 0;
int GLOVE_NEWDATA_CB;

//===== CB New data (with thumb) ===
int SCOL_GLOVE_NEWDATA_WITHOUT_THUMB_CB   = 1;
int GLOVE_NEWDATA_WITHOUT_THUMB_CB;

//===== CB New hand gesture ===
int SCOL_GLOVE_HAND_CB                    = 2;
int GLOVE_HAND_CB;

//===== CB Start of calibration process ===
int SCOL_GLOVE_CALIBRATION_START_CB       = 3;
int GLOVE_CALIBRATION_START_CB;

//===== CB End of calibration process ===
int SCOL_GLOVE_CALIBRATION_END_CB         = 4;
int GLOVE_CALIBRATION_END_CB;


/*! \mainpage 5DT Data Glove Scol Plugin
 *
 * \section intro_sec Introduction
 * This plugin allows Scol Virtual Machine to manage 5DT Data Glove device.
 * The 5DT Data Glove 5 Ultra measures finger flexure (1 or more sensor(s) per finger) of the user's hand, using optic fiber.
 * <br/>This plugin is based on fglove library available here : http://www.5dt.com/downloads/dataglove/ultra/5DTDataGloveUltra_SDK_Windows_32and64bit_v2.2_12Nov2010.zip
 * 
*/


//!Scol CallBack for ObjGlove destruction
int destroyGloveObj(mmachine m, int handsys, int gloveTab) 
{
	// Read the first element of a TAB element (table of objects)
	GloveObject* GloveObj = (GloveObject*) MMfetch(m, MTOP(gloveTab), 0);
	if (GloveObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

	// Safely dispose of "GloveObj" pointer
	SAFE_DELETE(GloveObj);
	// Write the first element of a TAB element
	MMstore(m, MTOP(gloveTab), 0, NULL);

	// Display debug message
	MMechostr(MSKDEBUG, "GloveObj destroyed.\n");
	return 0;
}


/*! @ingroup grpglove
* \brief _OpenGloveDevice : This function opens, initializes and calibrates a 5DTData Glove device
*
* <b>Prototype:</b> fun [Chn I] ObjGlove
* \param Chn : the current channel
* \param I : gesture mode (0 to get original data without thumb, 1 to get data including thumb)
*
* \return ObjGlove : The 5DT Data Glove object or NIL if creation fails
*/
int _OpenGloveDevice(mmachine m) 
{
	#ifdef	_SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_OpenGloveDevice\n");
	#endif

	// Declare local variables
	int k = 0;
  int gestureMode;

  // Test channel
  if (MMget(m, 1) == NIL)   // NOTE: Channel is the first parameter, so on the top of the stack... 
  {   
    MMechostr(MSKDEBUG,"_OpenFusionDevice : channel NIL\n");
    m->pp += 1;
    return 0;
  }

  // Retrieve data type (raw or orientation)
	if ((gestureMode = MTOI(MMpull(m))) == NIL)
		gestureMode = GESTURE_WITH_THUMB;  // Default gesture mode : thumb included

	// Create glove instance
	GloveObject * glove = new GloveObject();
  MMechostr(MSKDEBUG, "_OpenGloveDevice ...new glove instance created !\n");

	// Open glove on USB port
  if (!glove->Init(gestureMode)) 
  {
		MMechostr(MSKDEBUG, "_OpenGloveDevice ...initialization failed\n");
		SAFE_DELETE(glove) ;
		MMpull(m);								// Pull the channel
		MMpush(m, NIL);						// Push NIL on the stack
		return 0;
	}
  // Start data glove initialization procedure (for the sensors values)
  glove->SetInitValuesDone(false);
	MMechostr(MSKDEBUG, "_OpenGloveDevice ...initialization successful\n");

  // TEST : Display data glove serial number and USB index port
  MMechostr(MSKDEBUG, "_OpenGloveDevice ...serial number : %s\tUSB index : %d\n", glove->GetSerialNumber(), glove->GetUSBIndex());

  // Start callback
  glove->SetCallback();

	// Allocate a block in the stack for a table of glove objects
	int gloveTab = MMmalloc(m, 1, TYPETAB);
	if (gloveTab == NIL) 
  {
		MMechostr(MSKDEBUG, "_OpenGloveDevice ...MMmalloc failed\n");
		SAFE_DELETE(glove); 
		MMpull(m);								// Pull the channel
		return MMpush(m, NIL);		// Push NIL on the stack
	}
	MMechostr(MSKDEBUG, "_OpenGloveDevice ...MMmalloc successful\n");

	// Push the TAB glove object into the stack
	MMstore(m, gloveTab, 0, (int)glove);
	MMpush(m, PTOM(gloveTab));

	// Create a new glove object
	k = OBJcreate(m, OBJGLOVESCOL, (int)glove, NULL, NULL);
	MMechostr(MSKDEBUG, "_OpenGloveDevice ...object creation successful\n");

	#ifdef	_SCOL_DEBUG_
		MMechostr(MSKDEBUG,"ok\n");
	#endif

	// Return glove object
	return k;
}


/*! @ingroup grpglove
* \brief _CloseGloveDevice : This function closes a 5DTData Glove device
*
* <b>Prototype:</b> fun [ObjGlove I]
* \param ObjGlove : the current ObjGlove
*
* \return I : 0 if success, NIL otherwise
*/
int _CloseGloveDevice(mmachine m) 
{
	#ifdef	_SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_CloseGloveDevice\n");
	#endif

	// Get the table of glove objects into the stack (without pulling it)
	int gloveTab = MMget(m, 0);
  MMechostr(MSKDEBUG, "\n_CloseGloveDevice\n");
	if (gloveTab == NIL) 
  {
		MMechostr(MSKDEBUG, "_CloseGloveDevice ...ObjGlove NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

	// Destroy glove object according to its type and magma object
  OBJdelTM(m, OBJGLOVESCOL, gloveTab);

	// Reinitialize the stack
	MMset(m, 0, 0);

	#ifdef	_SCOL_DEBUG_
		MMechostr(MSKDEBUG,"ok\n");
	#endif

	return 0;
}


/*! @ingroup grpglove
* \brief _GetSerialNumber : This function gets the data glove serial number
*
* <b>Prototype:</b> fun [ObjGlove] S
* \param ObjGlove : the current ObjGlove
*
* \return S : data glove serial number
*/
int _GetSerialNumber(mmachine m)
{
	#ifdef _SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_GetSerialNumber\n");
	#endif

  // Get the table of glove objects into the stack (without pulling it)
	int gloveTab = MMget(m, 0);
  MMechostr(MSKDEBUG, "_GetSerialNumber\n");
	if (gloveTab == NIL)
  {
		MMechostr(MSKDEBUG, "_GetSerialNumber ...ObjGlove NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

  // Read the first element of a TAB element (table of objects)
	GloveObject* GloveObj = (GloveObject*) MMfetch(m, MTOP(gloveTab), 0);
	if (GloveObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

  // Remove param from stack
	MMpull(m);

	// Put in the stack the return of the function call  
  Mpushstrbloc(m, (char*)(GloveObj->GetSerialNumber().c_str()));

  #ifdef _SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

  return 0;
}


/*! @ingroup grpglove
* \brief _GetSerialNumber : This function gets the data glove type (5, 14 or 16 sensors)
*
* <b>Prototype:</b> fun [ObjGlove] S
* \param ObjGlove : the current ObjGlove
*
* \return S : data glove type
*/
int _GetType(mmachine m) 
{
	#ifdef _SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_GetType\n");
	#endif

  // Get the table of glove objects into the stack (without pulling it)
	int gloveTab = MMget(m, 0);
  MMechostr(MSKDEBUG, "_GetType\n");
	if (gloveTab == NIL) 
  {
		MMechostr(MSKDEBUG, "_GetType ...ObjGlove NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

  // Read the first element of a TAB element (table of objects)
	GloveObject* GloveObj = (GloveObject*) MMfetch(m, MTOP(gloveTab), 0);
	if (GloveObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

  // Remove param from stack
	MMpull(m);

	// Put in the stack the return of the function call  
  Mpushstrbloc(m, GloveObj->GetType());

  #ifdef _SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

  return 0;
}


/*! @ingroup grpglove
* \brief _GetUSBIndex : This function gets the index of the USB port on which the data glove is opened
*
* <b>Prototype:</b> fun [ObjGlove] I
* \param ObjGlove : the current ObjGlove
*
* \return I : USB port index
*/
int _GetUSBIndex(mmachine m) 
{
	#ifdef _SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_GetUSBIndex\n");
	#endif

  // Get the table of glove objects into the stack (without pulling it)
	int gloveTab = MMget(m, 0);
  MMechostr(MSKDEBUG, "_GetUSBIndex\n");
	if (gloveTab == NIL) 
  {
		MMechostr(MSKDEBUG, "_GetUSBIndex ...ObjGlove NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

  // Read the first element of a TAB element (table of objects)
	GloveObject* GloveObj = (GloveObject*) MMfetch(m, MTOP(gloveTab), 0);
	if (GloveObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

  // Put USB index into the stack
  MMset(m, 0, ITOM(GloveObj->GetUSBIndex()));
 
  #ifdef _SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

  return 0;
}


/*! @ingroup grpglove
* \brief _Calibrate : This function starts the calibration for the data glove
*
* <b>Prototype:</b> fun [ObjGlove] I
* \param ObjGlove : the current ObjGlove
*
* \return I : 0 if success, NIL otherwise
*/
int _Calibrate(mmachine m)
{
	#ifdef _SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_Calibrate\n");
	#endif

  // Get the table of glove objects into the stack (without pulling it)
	int gloveTab = MMget(m, 0);
  MMechostr(MSKDEBUG, "_Calibrate\n");
	if (gloveTab == NIL) 
  {
		MMechostr(MSKDEBUG, "_Calibrate ...ObjGlove NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

  // Read the first element of a TAB element (table of objects)
	GloveObject* GloveObj = (GloveObject*) MMfetch(m, MTOP(gloveTab), 0);
	if (GloveObj == NULL) 
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

  // Calibrate the data glove
  GloveObj->SetCalibrationDone(false);
  MMset(m, 0, ITOM(0));
  
  #ifdef _SCOL_DEBUG_
		MMechostr(0,"ok\n");
	#endif

  return 0;
}


/*! @ingroup grpglove
* \brief _CBGloveNewDataWithThumb : This function sets the Callback for new data (including thumb) received from data glove 
*
* <b>Prototype:</b> fun [ObjGlove fun [ObjGlove u0 [I I] [I I] [I I] [I I] [I I] I] u1 u0] ObjGlove
* \param ObjGlove : the current ObjGlove
* \param fun [ObjGlove u0 [I I] [I I] [I I] [I I] [I I] I] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjGlove if success
*/
int _CBGloveNewDataWithThumb(mmachine m) 
{
	// Add a reflex
	MMechostr(MSKDEBUG, "_CBGloveNewDataWithThumb ...adding reflex\n");
	return OBJaddreflex(m, OBJGLOVESCOL, SCOL_GLOVE_NEWDATA_CB);
}


int getGloveNewDataCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	int thumbNear = 0, thumbFar = 0;		// Initialize sensors values
	int indexNear = 0, indexFar = 0;
	int middleNear = 0, middleFar = 0;
	int ringNear = 0, ringFar = 0;
	int littleNear = 0, littleFar = 0;
	int gestureIndex = 0;					      // Initialize gesture index

	// Cast id parameter to GloveObj type
	GloveObject * GloveObj = (GloveObject*) id;
  
	// Use : OBJbeginreflex(mmachine, type of object, ptr object, callback type)
	if (OBJbeginreflex(m, OBJGLOVESCOL, (int)GloveObj, SCOL_GLOVE_NEWDATA_CB)) 
  {
		//MMechostr(MSKDEBUG, "getGloveNewDataCb ...ObjGlove not found\n");
		return 0;
	}
	
	// Retrieve sensors values
	thumbNear = GloveObj->pValues[FD_THUMBNEAR];
	thumbFar = GloveObj->pValues[FD_THUMBFAR];

	indexNear = GloveObj->pValues[FD_INDEXNEAR];
	indexFar = GloveObj->pValues[FD_INDEXFAR];

	middleNear = GloveObj->pValues[FD_MIDDLENEAR];
	middleFar = GloveObj->pValues[FD_MIDDLEFAR];

	ringNear = GloveObj->pValues[FD_RINGNEAR];
	ringFar = GloveObj->pValues[FD_RINGFAR];

	littleNear = GloveObj->pValues[FD_LITTLENEAR];
	littleFar = GloveObj->pValues[FD_LITTLEFAR];

	// 1. Create tuple for Thumb sensors
	int tupleThumb = MMmalloc(m, 2, TYPETAB);
	if (tupleThumb == NIL) 
  {
		MMpush(m, NIL);		// Reinitialize the stack	
		return MERRMEM;		// Return an error code (-1)
	}
	// Write TAB object field by field
	MMstore(m, tupleThumb, 0, ITOM(thumbNear));
	MMstore(m, tupleThumb, 1, ITOM(thumbFar));

	// Push tuple on the stack
  MMpush(m, PTOM(tupleThumb));

	// 2. Create tuple for Index sensors
	int tupleIndex = MMmalloc(m, 2, TYPETAB);
	if (tupleIndex == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleIndex, 0, ITOM(indexNear));
	MMstore(m, tupleIndex, 1, ITOM(indexFar));
  MMpush(m, PTOM(tupleIndex));

	// 3. Create tuple for Middle sensors
	int tupleMiddle = MMmalloc(m, 2, TYPETAB);
	if (tupleMiddle == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleMiddle, 0, ITOM(middleNear));
	MMstore(m, tupleMiddle, 1, ITOM(middleFar));
  MMpush(m, PTOM(tupleMiddle));	

	// 4. Create tuple for Ring sensors
	int tupleRing = MMmalloc(m, 2, TYPETAB);
	if (tupleRing == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleRing, 0, ITOM(ringNear));
	MMstore(m, tupleRing, 1, ITOM(ringFar));
  MMpush(m, PTOM(tupleRing));	

	// 5. Create tuple for Little sensors
	int tupleLittle = MMmalloc(m, 2, TYPETAB);
	if (tupleLittle == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleLittle, 0, ITOM(littleNear));
	MMstore(m, tupleLittle, 1, ITOM(littleFar));
  MMpush(m, PTOM(tupleLittle));

	// 6. Current full gesture index (including thumb)
  gestureIndex = GloveObj->GetGestureWithThumbIndex();
	MMpush(m, ITOM(gestureIndex));

	// Call reflex previously defined (second parameter = number of user parameters)
	k = OBJcallreflex(m, 6);
	return k;
}


/*! @ingroup grpglove
* \brief _CBGloveNewDataWithoutThumb : This function sets the Callback for new data (excluding thumb) received from data glove 
*
* <b>Prototype:</b> fun [ObjGlove fun [ObjGlove u0 [I I] [I I] [I I] [I I] I] u1 u0] ObjGlove
* \param ObjGlove : the current ObjGlove
* \param fun [ObjGlove u0 [I I] [I I] [I I] [I I] I] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjGlove if success
*/
int _CBGloveNewDataWithoutThumb(mmachine m) 
{
	// Add a reflex
	MMechostr(MSKDEBUG, "_CBGloveNewDataWithoutThumb ...adding reflex\n");
	return OBJaddreflex(m, OBJGLOVESCOL, SCOL_GLOVE_NEWDATA_WITHOUT_THUMB_CB);
}


int getGloveNewDataWithoutThumbCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret) {
	int k = 0;	
	int indexNear = 0, indexFar = 0;    // Initialize sensors values
	int middleNear = 0, middleFar = 0;
	int ringNear = 0, ringFar = 0;
	int littleNear = 0, littleFar = 0;
	int gestureIndex = 0;					      // Initialize gesture index

	// Cast id parameter to GloveObj type
	GloveObject * GloveObj = (GloveObject*) id;
  
	// Use : OBJbeginreflex(mmachine, type of object, ptr object, callback type)
	if (OBJbeginreflex(m, OBJGLOVESCOL, (int)GloveObj, SCOL_GLOVE_NEWDATA_WITHOUT_THUMB_CB)) 
  {
		MMechostr(MSKDEBUG, "getGloveNewDataWithoutThumbCb ...ObjGlove not found\n");
		return 0;
	}
	
	// Retrieve sensors values
	indexNear = GloveObj->pValues[FD_INDEXNEAR];
	indexFar = GloveObj->pValues[FD_INDEXFAR];

	middleNear = GloveObj->pValues[FD_MIDDLENEAR];
	middleFar = GloveObj->pValues[FD_MIDDLEFAR];

	ringNear = GloveObj->pValues[FD_RINGNEAR];
	ringFar = GloveObj->pValues[FD_RINGFAR];

	littleNear = GloveObj->pValues[FD_LITTLENEAR];
	littleFar = GloveObj->pValues[FD_LITTLEFAR];

	// 1. Create tuple for Index sensors
	int tupleIndex = MMmalloc(m, 2, TYPETAB);
	if (tupleIndex == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleIndex, 0, ITOM(indexNear));
	MMstore(m, tupleIndex, 1, ITOM(indexFar));
  MMpush(m, PTOM(tupleIndex));

	// 2. Create tuple for Middle sensors
	int tupleMiddle = MMmalloc(m, 2, TYPETAB);
	if (tupleMiddle == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleMiddle, 0, ITOM(middleNear));
	MMstore(m, tupleMiddle, 1, ITOM(middleFar));
  MMpush(m, PTOM(tupleMiddle));	

	// 3. Create tuple for Ring sensors
	int tupleRing = MMmalloc(m, 2, TYPETAB);
	if (tupleRing == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleRing, 0, ITOM(ringNear));
	MMstore(m, tupleRing, 1, ITOM(ringFar));
  MMpush(m, PTOM(tupleRing));	

	// 4. Create tuple for Little sensors
	int tupleLittle = MMmalloc(m, 2, TYPETAB);
	if (tupleLittle == NIL) 
  {
		MMpush(m, NIL);
		return MERRMEM;
	}
	MMstore(m, tupleLittle, 0, ITOM(littleNear));
	MMstore(m, tupleLittle, 1, ITOM(littleFar));
  MMpush(m, PTOM(tupleLittle));

	// 5. Current gesture index (excluding thumb)
	gestureIndex = GloveObj->GetGestureIndex();
	MMpush(m, ITOM(gestureIndex));

	// Call reflex previously defined (second parameter = number of user parameters)
	k = OBJcallreflex(m, 5);
	return k;
}


/*! @ingroup grpglove
* \brief _CBGloveHand : This function sets the Callback for new hand gesture received from data glove 
*
* <b>Prototype:</b> fun [ObjGlove fun [ObjGlove u0 I] u1 u0] ObjGlove
* \param ObjGlove : the current ObjGlove
* \param fun [ObjGlove u0 I] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjGlove if success
*/
int _CBGloveHand(mmachine m) 
{
	// Add a reflex
	MMechostr(MSKDEBUG, "_CBGloveHand ...adding reflex\n");
	return OBJaddreflex(m, OBJGLOVESCOL, SCOL_GLOVE_HAND_CB);
}


int getGloveHandCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret) 
{
	int k = 0;
	int gestureIndex = 0;   // Initialize gesture index

	// Cast id parameter to GloveObj type
	GloveObject * GloveObj = (GloveObject*) id;

	// Use : OBJbeginreflex(mmachine, type of object, ptr object, callback type)
	if (OBJbeginreflex(m, OBJGLOVESCOL, (int)GloveObj, SCOL_GLOVE_HAND_CB)) 
  {
    //MMechostr(MSKDEBUG, "getGloveHandCb ...ObjGlove not found\n");
		return 0;
	}

	// Retrieve current gesture index (recognized gestures : 0 for closed hand, 15 for flat hand)
	//gestureIndex = GloveObj->GetGestureIndex();           // Get gesture index
  gestureIndex = GloveObj->GetGestureWithThumbIndex();    // Get new gesture index (including thumb)
	//MMechostr(MSKDEBUG, "...gestureIndex (with thumb) = %d\n", gestureIndex);
	MMpush(m, ITOM(gestureIndex));

	// Call reflex previously defined
	k = OBJcallreflex(m, 1);
	return k;
}


/*! @ingroup grpglove
* \brief _CBCalibrationStart : This function sets the Callback for a calibration started event
*
* <b>Prototype:</b> fun [ObjGlove fun [ObjGlove u0] u1 u0] ObjGlove
* \param ObjGlove : the current ObjGlove
* \param fun [ObjGlove u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjGlove if success
*/
int _CBCalibrationStart(mmachine m) 
{
	// Add a reflex
	MMechostr(MSKDEBUG, "_CBCalibrationStart ...adding reflex\n");
	return OBJaddreflex(m, OBJGLOVESCOL, SCOL_GLOVE_CALIBRATION_START_CB);
}


int getCalibrationStartCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret) 
{
  int k = 0;	
  
  // Cast id parameter to GloveObj type
	GloveObject * GloveObj = (GloveObject*) id;

	// Use : OBJbeginreflex(mmachine, type of object, ptr object, callback type)
	if (OBJbeginreflex(m, OBJGLOVESCOL, (int)GloveObj, SCOL_GLOVE_CALIBRATION_START_CB)) 
  {
    MMechostr(MSKDEBUG, "getCalibrationStartCb ...ObjGlove not found\n");
		return 0;
	}

	// Call reflex previously defined
	k = OBJcallreflex(m, 0);
	return k;
}


/*! @ingroup grpglove
* \brief _CBCalibrationEnd : This function sets the Callback for a calibration ended event
*
* <b>Prototype:</b> fun [ObjGlove fun [ObjGlove u0] u1 u0] ObjGlove
* \param ObjGlove : the current ObjGlove
* \param fun [ObjGlove u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjGlove if success
*/
int _CBCalibrationEnd(mmachine m) 
{
	// Add a reflex
	MMechostr(MSKDEBUG, "_CBCalibrationEnd ...adding reflex\n");
	return OBJaddreflex(m, OBJGLOVESCOL, SCOL_GLOVE_CALIBRATION_END_CB);
}


int getCalibrationEndCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
  int k = 0;

	// Cast id parameter to GloveObj type
	GloveObject * GloveObj = (GloveObject*) id;

	// Use : OBJbeginreflex(mmachine, type of object, ptr object, callback type)
	if (OBJbeginreflex(m, OBJGLOVESCOL, (int)GloveObj, SCOL_GLOVE_CALIBRATION_END_CB)) 
  {
    MMechostr(MSKDEBUG, "getCalibrationEndCb ...ObjGlove not found\n");
		return 0;
	}

	// Call reflex previously defined
	k = OBJcallreflex(m, 0);
	return k;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											                                                         ////
///										                  DECLARATION OF FUNCTIONS (FOR SCOL)											                    ///
////																											                                                         ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//! Nb of Scol functions or types
#define NbTplPKG	12


/*!
*	Scol function names
*/
char	*TplName[NbTplPKG] =
{
	"ObjGlove",
	"_OpenGloveDevice",
	"_CloseGloveDevice",
	"_CBGloveNewDataWithThumb",
  "_CBGloveNewDataWithoutThumb",
	"_CBGloveHand",
  "_CBCalibrationStart",
  "_CBCalibrationEnd",
  "_GetSerialNumber",
  "_GetType",
  "_GetUSBIndex",
  "_Calibrate"
};


/*!
*	Pointers to C functions that manipulate the VM for each scol function previously defined
*/
int (*TplFunc[NbTplPKG])(mmachine m)=
{
	NULL,																				// ObjGlove
	_OpenGloveDevice,														// _OpenGloveDevice
	_CloseGloveDevice,													// _CloseGloveDevice
	_CBGloveNewDataWithThumb,										// _CBGloveNewDataWithThumb
  _CBGloveNewDataWithoutThumb,								// _CBGloveNewDataWithoutThumb
	_CBGloveHand,																// _CBGloveHand
  _CBCalibrationStart,                        // _CBCalibrationStart
  _CBCalibrationEnd,                          // _CBCalibrationEnd
  _GetSerialNumber,                           // _GetSerialNumber
  _GetType,                                   // _GetType
  _GetUSBIndex,                               // _GetUSBIndex
  _Calibrate                                  // _Calibrate
};


/*!
*	Nb of arguments of each scol function
*/
int TplNArg[NbTplPKG]=
{
	TYPTYPE,																		// ObjGlove
	2,																					// _OpenGloveDevice
	1,																					// _CloseGloveDevice
	3,																					// _CBGloveNewDataWithThumb
  3,																					// _CBGloveNewDataWithoutThumb
	3,																					// _CBGloveHand
  3,                                          // _CBCalibrationStart
  3,                                          // _CBCalibrationEnd
  1,                                          // _GetSerialNumber
  1,                                          // _GetType
  1,                                          // _GetUSBIndex
  1                                           // _Calibrate
};


/*!
*	Prototypes of the scol functions
*/
char* TplType[NbTplPKG]=
{
	NULL,																				                                        // ObjGlove
	"fun [Chn I] ObjGlove",																                              // _OpenGloveDevice
	"fun [ObjGlove] I",																	                                // _CloseGloveDevice
	"fun [ObjGlove fun [ObjGlove u0 [I I] [I I] [I I] [I I] [I I] I] u1 u0] ObjGlove",	// _CBGloveNewDataWithThumb
  "fun [ObjGlove fun [ObjGlove u0 [I I] [I I] [I I] [I I] I] u1 u0] ObjGlove",	      // _CBGloveNewDataWithoutThumb
	"fun [ObjGlove fun [ObjGlove u0 I] u1 u0] ObjGlove",									              // _CBGloveHand
  "fun [ObjGlove fun [ObjGlove u0] u1 u0] ObjGlove",	                                // _CBCalibrationStart
  "fun [ObjGlove fun [ObjGlove u0] u1 u0] ObjGlove",	                                // _CBCalibrationEnd
  "fun [ObjGlove] S",                                                                 // _GetSerialNumber
  "fun [ObjGlove] S",                                                                 // _GetType
  "fun [ObjGlove] I",                                                                 // _GetUSBIndex
  "fun [ObjGlove] I"                                                                  // _Calibrate
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											                                                         ////
///												                        DLL CALL FUNCTIONS													                      ///
////																											                                                         ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Everything inside _cond and _endcond is ignored by doxygen
//! \cond

/*!
* \brief Load the packages in Scol virtual machine
* \param mmachine : the scol machine
*/
int LoadGlove(mmachine m) 
{
  // Return variable for PKhardpak function
	int k;

	// Declare a new type of object ("OBJGLOVESCOL")
	OBJGLOVESCOL = OBJregister(5, 1, destroyGloveObj, "OBJGLOVESCOL");

	// Get new user events and associate these events with a callback
	GLOVE_NEWDATA_CB = OBJgetUserEvent();
	OBJdefEvent(GLOVE_NEWDATA_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getGloveNewDataCb);
  
  GLOVE_NEWDATA_WITHOUT_THUMB_CB = OBJgetUserEvent();
	OBJdefEvent(GLOVE_NEWDATA_WITHOUT_THUMB_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getGloveNewDataWithoutThumbCb);

	GLOVE_HAND_CB = OBJgetUserEvent();
	OBJdefEvent(GLOVE_HAND_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getGloveHandCb);

  GLOVE_CALIBRATION_START_CB = OBJgetUserEvent();
	OBJdefEvent(GLOVE_CALIBRATION_START_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getCalibrationStartCb);

  GLOVE_CALIBRATION_END_CB = OBJgetUserEvent();
	OBJdefEvent(GLOVE_CALIBRATION_END_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getCalibrationEndCb);

	// Load package
	k = PKhardpak(m, "GloveEngine", NbTplPKG, TplName, TplFunc, TplNArg, TplType);
	return k;
}
//! \endcond


/*! 
* \brief Starting point of the DLL
* Function to add in Scol usm.ini for loading dll
*/
extern "C" __declspec (dllexport) int ScolLoadPlugin(mmachine m, cbmachine w) 
{
	SCOLinitplugin(w);

	// Get Scol window handle (for message callback)
	HScol = (HWND)SCgetExtra("hscol");	
	LoadGlove(m);
	return 0;
}


/*! 
* \brief Ending point of the DLL
* Function to add in Scol usm.ini for free dll
*/
extern "C" __declspec (dllexport) int ScolUnloadPlugin() 
{
	return 0;
}
