/*
-----------------------------------------------------------------------------
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.
-----------------------------------------------------------------------------
*/

/*
 Emotiv EPOC Developer Headset control
 First version : July 2010
 Author : Aymeric Suteau
*/

/*! @defgroup grpepoc Scol functions definition
 *  Scol functions definition
 *  @{
 */
/** @} */


#include "Plugin.h"

//!Scol machine declaration for MM macros
cbmachine ww;
HWND HScol = NULL;

//!Scol object declaration
int OBJEPOCSCOL;

//!Scol CallBacks declaration
int SCOL_EPOC_CONNECTED_CB                      = 0;    // Headset connected
int EPOC_CONNECTED_CB;

int SCOL_EPOC_DISCONNECTED_CB                   = 1;    // Headset disconnected
int EPOC_DISCONNECTED_CB;

int SCOL_EPOC_BAD_SIGNAL_CB                     = 2;    // Bad wireless signal
int EPOC_BAD_SIGNAL_CB;

int SCOL_EPOC_LOW_BATTERY_CB                    = 3;    // Low battery level
int EPOC_LOW_BATTERY_CB;

int SCOL_EPOC_HEADSET_DATA_CB                   = 4;    // New data related to Headset Setup
int EPOC_HEADSET_DATA_CB;

int SCOL_EPOC_AFFECTIV_DATA_CB                  = 5;    // New data from Affectiv Suite
int EPOC_AFFECTIV_DATA_CB;

int SCOL_EPOC_EXPRESSIV_DATA_CB                 = 6;    // New data from Expressiv Suite
int EPOC_EXPRESSIV_DATA_CB;

int SCOL_EPOC_COGNITIV_DATA_CB                  = 7;    // New data from Cognitiv Suite
int EPOC_COGNITIV_DATA_CB;

int SCOL_EPOC_EXPRESSIV_TRAINING_STARTED_CB     = 8;    // Expressive training started
int EPOC_EXPRESSIV_TRAINING_STARTED_CB;

int SCOL_EPOC_COGNITIV_TRAINING_STARTED_CB      = 9;    // Cognitive training started
int EPOC_COGNITIV_TRAINING_STARTED_CB;

int SCOL_EPOC_EXPRESSIV_TRAINING_COMPLETED_CB   = 10;   // Expressive training completed
int EPOC_EXPRESSIV_TRAINING_COMPLETED_CB;

int SCOL_EPOC_COGNITIV_TRAINING_COMPLETED_CB    = 11;   // Cognitive training completed
int EPOC_COGNITIV_TRAINING_COMPLETED_CB;

int SCOL_EPOC_EXPRESSIV_TRAINING_ERASED_CB      = 12;   // Expressive training completed
int EPOC_EXPRESSIV_TRAINING_ERASED_CB;

int SCOL_EPOC_COGNITIV_TRAINING_ERASED_CB       = 13;   // Cognitive training completed
int EPOC_COGNITIV_TRAINING_ERASED_CB;

int SCOL_EPOC_EXPRESSIV_TRAINING_REJECTED_CB    = 14;   // Expressive training rejected
int EPOC_EXPRESSIV_TRAINING_REJECTED_CB;

int SCOL_EPOC_COGNITIV_TRAINING_REJECTED_CB     = 15;   // Cognitive training rejected
int EPOC_COGNITIV_TRAINING_REJECTED_CB;

int SCOL_EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB   = 16;   // Expressive training succeeded
int EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB;

int SCOL_EPOC_COGNITIV_TRAINING_SUCCEEDED_CB    = 17;   // Cognitive training succeeded
int EPOC_COGNITIV_TRAINING_SUCCEEDED_CB;

int SCOL_EPOC_EXPRESSIV_TRAINING_FAILED_CB      = 18;   // Expressive training failed
int EPOC_EXPRESSIV_TRAINING_FAILED_CB;

int SCOL_EPOC_COGNITIV_TRAINING_FAILED_CB       = 19;   // Cognitive training failed
int EPOC_COGNITIV_TRAINING_FAILED_CB;

int SCOL_EPOC_RAW_EEG_CB                        = 20;   // New raw EEG data
int EPOC_RAW_EEG_CB;


// Extern variables
extern list<Epoc*> lEpocList;


/*! \mainpage Emotiv EPOC Scol Plugin
 *
 * \section intro_sec Introduction
 * This plugin allow Scol Virtual Machine to use and read Emotiv EPOC BCI Datas
 * 
*/


//!Scol CallBack for ObjEpoc destruction
int destroyEpocObj(mmachine m, int handsys, int epocTab) 
{
	// Read the first element of a TAB element (table of objects)
	Epoc* EpocObj = (Epoc*) MMfetch(m, MTOP(epocTab), 0);
	if (EpocObj == NULL)
  {
		// Write the first element in the stack, without pulling it
		MMset(m, 0, NIL); 
		return 0; 
	}

	// Safely dispose of "EpocObj" pointer
	SAFE_DELETE(EpocObj);
  MMechostr(MSKDEBUG, "destroyEpocObj ...SAFE_DELETE ok\n");

	// Write the first element of a TAB element
	MMstore(m, MTOP(epocTab), 0, NULL);

	// Display debug message
	MMechostr(MSKDEBUG, "EpocObj destroyed.\n");
	return 0;
}


/*! @ingroup grpepoc
* \brief _CREpoc : This function creates a new Emotiv EPOC Object
*
* <b>Prototype:</b> fun [Chn] ObjEpoc
* \param Chn : the current channel
*
* \return ObjEpoc : Emotiv EPOC Object
*/
int _CREpoc(mmachine m)
{
	#ifdef _SCOL_DEBUG_
		MMechostr(MSKDEBUG,"_CREpoc\n");
	#endif
	
	// Get Channel
	int channel = MMget(m, 0);

	// Test Channel
	if (channel == NIL) 
  { 
		MMechostr(MSKDEBUG, "Channel NIL\n");	  // Display Warning in Scol Console
		MMpull(m);
		MMpush(m, NIL);
		return 0;
	}

	// Create Emotiv EPOC instance
  Epoc* newEpoc = new Epoc();
  
  // Initialize the connection to Emotiv EPOC headset
  if (!newEpoc->Connect()) 
  {
		MMechostr(MSKDEBUG, "_CREpoc ...initialization failed\n");
		SAFE_DELETE(newEpoc);
		MMpull(m);								// Pull the channel
		MMpush(m, NIL);						// Push NIL on the stack
		return 0;
	}

  int epocTab = MMmalloc(m, 1, TYPETAB);
  if (epocTab == NIL) 
  {
		SAFE_DELETE(newEpoc); 
		MMpull(m);
		return MMpush(m, NIL);
	}
  MMstore(m, epocTab, 0, (int)newEpoc);
	MMpush(m, PTOM(epocTab));

	int k = OBJcreate(m, OBJEPOCSCOL, (int)newEpoc, -1, -1);

	#ifdef	_SCOL_DEBUG_
		MMechostr(MSKDEBUG,"ok\n");
	#endif

	return k;
}


/*! @ingroup grpepoc
* \brief _DSEpoc : This function destroys an Emotiv EPOC Object
*
* <b>Prototype:</b> fun [ObjEpoc] I
* \param ObjEpoc : the current ObjEpoc
*
* \return I : 0 if success
*/
int _DSEpoc(mmachine m) 
{
  #ifdef _SCOL_DEBUG_
	  MMechostr(MSKDEBUG, "_DSEpoc\n");
  #endif

  // Get the table of Emotiv EPOC objects into the stack (without pulling it)
	int epocTab = MMget(m, 0);
	if (epocTab == NIL) {
		MMechostr(MSKDEBUG, "ObjEpoc NIL\n");
		MMset(m, 0, -1);
		return 0;
	}

	OBJdelTM(m, OBJEPOCSCOL, epocTab);
	MMset(m, 0, 0);

  #ifdef	_SCOL_DEBUG_
	  MMechostr(MSKDEBUG, "ok\n");
  #endif
	return 0;
}


/*! @ingroup grpepoc
* \brief _CBEpocConnected : This function sets the Callback for Connection from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocConnected(mmachine m)
{
	return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_CONNECTED_CB);
}

int getEpocConnectedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_CONNECTED_CB))
		return 0;

	if ((k=OBJcallreflex(m, 0))) 
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocDisconnected : This function sets the Callback for disconnected state from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocDisconnected(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_DISCONNECTED_CB);
}

int getEpocDisconnectedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_DISCONNECTED_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0))) 
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocBadSignal : This function sets the Callback for bad wireless signal from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocBadSignal(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_BAD_SIGNAL_CB);
}

int getEpocBadSignalCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_BAD_SIGNAL_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0))) 
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocLowBattery : This function sets the Callback for low battery level from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocLowBattery(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_LOW_BATTERY_CB);
}

int getEpocLowBatteryCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_LOW_BATTERY_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0))) 
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocHeadsetData : This function sets the Callback for new headset data received from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0 [I I] [I I I I I I I] [I I I I I I I] [F F] F] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0 [I I] [I I I I I I I] [I I I I I I I] [F F] F] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocHeadsetData(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_HEADSET_DATA_CB);
}

int getEpocHeadsetDataCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
  int cms = 0, drl = 0;
  int af3 = 0, f7 = 0, f3 = 0, fc5 = 0, t7 = 0, p7 = 0, o1 = 0;
  int af4 = 0, f8 = 0, f4 = 0, fc6 = 0, t8 = 0, p8 = 0, o2 = 0;
  float xGyro = 0.f, yGyro = 0.f;
  float systemUpTime = 0.f;

  // Retrieve Emotiv EPOC instance
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_HEADSET_DATA_CB))
		return 0;

  // Retrieve sensors pads quality
  cms = EpocObj->iContactQuality[0];   // Reference pads
  drl = EpocObj->iContactQuality[1];

  af3 = EpocObj->iContactQuality[3];   // Left hemisphere
  f7 = EpocObj->iContactQuality[4];
  f3 = EpocObj->iContactQuality[5];
  fc5 = EpocObj->iContactQuality[6];
  t7 = EpocObj->iContactQuality[7];
  p7 = EpocObj->iContactQuality[8];
  o1 = EpocObj->iContactQuality[9];

  af4 = EpocObj->iContactQuality[16];  // Right hemisphere
  f8 = EpocObj->iContactQuality[15];
  f4 = EpocObj->iContactQuality[14];
  fc6 = EpocObj->iContactQuality[13];
  t8 = EpocObj->iContactQuality[12];
  p8 = EpocObj->iContactQuality[11];
  o2 = EpocObj->iContactQuality[10];

  // Update gyroscope values
  xGyro = EpocObj->GetGyroX();
  yGyro = EpocObj->GetGyroY();

  // Update system up time
  systemUpTime = EpocObj->GetSystemUpTime();

  // Create tuples
  int tupleRef = MMmalloc(m, 2, TYPETAB);     // Reference pads
	if (tupleRef == NIL) 
  {	
    MMset(m, 0, NIL);		
    return MERRMEM;	
  }
  MMstore(m, tupleRef, 0, ITOM(cms));
	MMstore(m, tupleRef, 1, ITOM(drl));
  MMpush(m, PTOM(tupleRef));

  int tupleLeft = MMmalloc(m, 7, TYPETAB);    // Left hemisphere
	if (tupleLeft == NIL) 
  {	
    MMset(m, 0, NIL);		
    return MERRMEM;	
  }
  MMstore(m, tupleLeft, 0, ITOM(af3));
	MMstore(m, tupleLeft, 1, ITOM(f7));
  MMstore(m, tupleLeft, 2, ITOM(f3));
	MMstore(m, tupleLeft, 3, ITOM(fc5));
  MMstore(m, tupleLeft, 4, ITOM(t7));
	MMstore(m, tupleLeft, 5, ITOM(p7));
  MMstore(m, tupleLeft, 6, ITOM(o1));
  MMpush(m, PTOM(tupleLeft));

  int tupleRight = MMmalloc(m, 7, TYPETAB);   // Right hemisphere
	if (tupleRight == NIL) 
  {	
    MMset(m, 0, NIL);
    return MERRMEM;
  }
  MMstore(m, tupleRight, 0, ITOM(af4));
	MMstore(m, tupleRight, 1, ITOM(f8));
  MMstore(m, tupleRight, 2, ITOM(f4));
	MMstore(m, tupleRight, 3, ITOM(fc6));
  MMstore(m, tupleRight, 4, ITOM(t8));
	MMstore(m, tupleRight, 5, ITOM(p8));
  MMstore(m, tupleRight, 6, ITOM(o2));
  MMpush(m, PTOM(tupleRight));

  // Gyro
  int tupleGyro = MMmalloc(m, 2, TYPETAB);
	if (tupleGyro == NIL) 
  {
    MMset(m, 0, NIL);
    return MERRMEM;
  }
  MMstore(m, tupleGyro, 0, FTOM(xGyro));
	MMstore(m, tupleGyro, 1, FTOM(yGyro));
  MMpush(m, PTOM(tupleGyro));

  // System up time
  MMpush(m, FTOM(systemUpTime));

	k = OBJcallreflex(m, 5);
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocAffectivData : This function sets the Callback for new affectiv data received from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0 F F F F F] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0 F F F F F] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocAffectivData(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_AFFECTIV_DATA_CB);
}

int getEpocAffectivDataCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
  float engagement = 0.f, frustration = 0.f, meditation = 0.f, shortExcitement = 0.f, longExcitement = 0.f;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_AFFECTIV_DATA_CB))
		return 0;

  // Retrieve data related to Affectiv Suite
  engagement = EpocObj->GetEngagementBoredom();
  frustration = EpocObj->GetFrustration();
  meditation = EpocObj->GetMeditation();
  shortExcitement = EpocObj->GetInstantaneousExcitement();
  longExcitement = EpocObj->GetLongTermExcitement();

  // Push Affective data into the stack
	MMpush(m, FTOM(engagement));
  MMpush(m, FTOM(frustration));
  MMpush(m, FTOM(meditation));
  MMpush(m, FTOM(shortExcitement));
  MMpush(m, FTOM(longExcitement));

	k = OBJcallreflex(m, 5);
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivData : This function sets the Callback for new expressiv data received from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0 I I F I F] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0 I I F I F] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivData(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_DATA_CB);
}

int getEpocExpressivDataCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
  unsigned int eyeType = 0, upperFaceType = 0, lowerFaceType = 0;
  float upperFacePower = 0.f, lowerFacePower = 0.f;

	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_DATA_CB))
		return 0;

  // Retrieve data from Expressiv Suite
  eyeType = EpocObj->GetEyeExpressionType();
  upperFaceType = EpocObj->GetUpperFaceExpressionType();
  upperFacePower = EpocObj->GetUpperFaceExpressionPower();
  lowerFaceType = EpocObj->GetLowerFaceExpressionType();
  lowerFacePower = EpocObj->GetLowerFaceExpressionPower();

  // Push Expressiv data into the stack
	MMpush(m, ITOM(eyeType));
  MMpush(m, ITOM(upperFaceType));
  MMpush(m, FTOM(upperFacePower));
  MMpush(m, ITOM(lowerFaceType));
  MMpush(m, FTOM(lowerFacePower));
	k = OBJcallreflex(m, 5);
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivData : This function sets the Callback for new cognitiv data received from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0 [I F]] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0 [I F]] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivData(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_COGNITIV_DATA_CB);
}

int getEpocCognitivDataCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
  unsigned int actionType = 0;
  float actionPower = 0.f;

	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_DATA_CB))
		return 0;

  // Retrieve data from Cognitiv Suite
  actionType = EpocObj->GetActionType();
  actionPower = EpocObj->GetActionPower();

  // Push Affective data into the stack
	MMpush(m, ITOM(actionType));
  MMpush(m, FTOM(actionPower));

	k = OBJcallreflex(m, 2);
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivTrainingStarted : This function sets the Callback for Expressiv Training Started event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivTrainingStarted(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_STARTED_CB);
}

int getEpocExpressivTrainingStartedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_TRAINING_STARTED_CB))
		return 0;

	if ((k=OBJcallreflex(m, 0))) 
    return k;

  // DEBUG
  MMechostr(MSKDEBUG, "<<< getEpocExpressivTrainingStartedCb OK\n");

	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivTrainingStarted : This function sets the Callback for Cognitiv Training Started event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivTrainingStarted(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_COGNITIV_TRAINING_STARTED_CB);
}

int getEpocCognitivTrainingStartedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_TRAINING_STARTED_CB))
		return 0;

	if ((k=OBJcallreflex(m, 0))) 
    return k;

  // DEBUG
  MMechostr(MSKDEBUG, "<<< getEpocCognitivTrainingStartedCb OK\n");

	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivTrainingCompleted : This function sets the Callback for Expressiv Training Completed event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivTrainingCompleted(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_COMPLETED_CB);
}

int getEpocExpressivTrainingCompletedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
  // DEBUG
  MMechostr(MSKDEBUG, "<<< starting getEpocExpressivTrainingCompletedCb...\n");
	
  int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_TRAINING_COMPLETED_CB))
		return 0;

	if ((k=OBJcallreflex(m, 0))) 
    return k;

  // DEBUG
  MMechostr(MSKDEBUG, "<<< getEpocExpressivTrainingCompletedCb OK\n");
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivTrainingCompleted : This function sets the Callback for Cognitiv Training Completed event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivTrainingCompleted(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_COGNITIV_TRAINING_COMPLETED_CB);
}

int getEpocCognitivTrainingCompletedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
  // DEBUG
  MMechostr(MSKDEBUG, "<<< starting getEpocCognitivTrainingCompletedCb...\n");
  
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
	if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_TRAINING_COMPLETED_CB))
		return 0;

	if ((k=OBJcallreflex(m, 0))) 
    return k;

  // DEBUG
  MMechostr(MSKDEBUG, "<<< getEpocCognitivTrainingCompletedCb OK\n");
	return k;
}


/*! @ingroup grpepoc
* \brief _StartExpressivTraining : This function starts Expressiv Suite training for Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc I] I
* \param ObjEpoc : the current ObjEpoc
* \param I : index for Expressiv Suite action to be trained
*
* \return I : ObjEpoc if success
*/
int _StartExpressivTraining(mmachine m)
{
	unsigned int expressionIndex = 0;
	expressionIndex = MTOI(MMpull(m));

	int epocTab = MTOP(MMget(m, 0));
	if (epocTab == NIL) 
  { 
    MMset(m, 0, NIL); 
    return 0; 
  }

  // Retrieve Emotiv EPOC instance
  Epoc * EpocObj = (Epoc*) MMfetch(m, epocTab, 0);
  if (!EpocObj) 
  { 
    MMset(m, 0, NIL); 
    return 0; 
  }

  // Start Expressiv training procedure for selected expression
  EpocObj->StartExpressivSuiteTraining((EE_ExpressivAlgo_t) expressionIndex);
	MMset(m, 0, 0);
	
  return 0;
}


/*! @ingroup grpepoc
* \brief _EraseExpressivTraining : This function erases training for a specific expression of Expressiv Suite
*
* <b>Prototype:</b> fun [ObjEpoc I] I
* \param ObjEpoc : the current ObjEpoc
* \param I : index for Expressiv Suite action to be erased
*
* \return I : ObjEpoc if success
*/
int _EraseExpressivTraining(mmachine m)
{
	unsigned int expressionIndex = 0;
	expressionIndex = MTOI(MMpull(m));

	int epocTab = MTOP(MMget(m, 0));
	if (epocTab == NIL)
  { 
    MMset(m, 0, NIL);
    return 0;
  }

  // Retrieve Emotiv EPOC instance
  Epoc * EpocObj = (Epoc*) MMfetch(m, epocTab, 0);
  if (!EpocObj)
  { 
    MMset(m, 0, NIL);
    return 0;
  }

  // Erase Expressiv training for selected expression
  EpocObj->EraseExpressivSuiteTraining((EE_ExpressivAlgo_t) expressionIndex);
	MMset(m, 0, 0);
	
  return 0;
}


/*! @ingroup grpepoc
* \brief _StartCognitivTraining : This function starts Cognitiv Suite training for Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc I] I
* \param ObjEpoc : the current ObjEpoc
* \param I : index for Cognitiv Suite action to be trained
*
* \return I : ObjEpoc if success
*/
int _StartCognitivTraining(mmachine m)
{
	unsigned int cognitivAction = 0;
	cognitivAction = MTOI(MMpull(m));

	int epocTab = MTOP(MMget(m, 0));
	if (epocTab == NIL) 
  { 
    MMset(m, 0, NIL); 
    return 0; 
  }

  // Retrieve Emotiv EPOC instance
  Epoc * EpocObj = (Epoc*) MMfetch(m, epocTab, 0);
  if (!EpocObj) 
  { 
    MMset(m, 0, NIL); 
    return 0; 
  }

  // Start Cognitiv training procedure for selected action
  EpocObj->StartCognitivSuiteTraining((EE_CognitivAction_t) cognitivAction);
	MMset(m, 0, 0);
	
  return 0;
}


/*! @ingroup grpepoc
* \brief _EraseCognitivTraining : This function erases training for a specific action of Cognitiv Suite
*
* <b>Prototype:</b> fun [ObjEpoc I] I
* \param ObjEpoc : the current ObjEpoc
* \param I : index for Cognitiv Suite action to be erased
*
* \return I : ObjEpoc if success
*/
int _EraseCognitivTraining(mmachine m)
{
	unsigned int cognitivAction = 0;
	cognitivAction = MTOI(MMpull(m));

	int epocTab = MTOP(MMget(m, 0));
	if (epocTab == NIL) 
  {
    MMset(m, 0, NIL); 
    return 0; 
  }

  // Retrieve Emotiv EPOC instance
  Epoc * EpocObj = (Epoc*) MMfetch(m, epocTab, 0);
  if (!EpocObj)
  { 
    MMset(m, 0, NIL);
    return 0;
  }

  // Erases Cognitiv training for selected action
  EpocObj->EraseCognitivSuiteTraining((EE_CognitivAction_t) cognitivAction);
	MMset(m, 0, 0);
	
  return 0;
}


/*! @ingroup grpepoc
* \brief _LoadProfile : This function loads a profile (*.emu) and assigns it to the current user
*
* <b>Prototype:</b> fun [ObjEpoc S] I
* \param ObjEpoc : the current ObjEpoc
* \param S : path to the user profile file name
*
* \return I : ObjEpoc if success
*/
int _LoadProfile(mmachine m)
{
  int fileName = MMpull(m);
	int epocTab = MTOP(MMget(m, 0));
	if (epocTab == NIL) 
  { 
    MMset(m, 0, NIL);
    return 0;
  }

  // Retrieve Emotiv EPOC instance
  Epoc * EpocObj = (Epoc*) MMfetch(m, epocTab, 0);
  if (!EpocObj) 
  { 
    MMset(m, 0, NIL);
    return 0;
  }

  // Convert parameter to char*
  char* strFileName = (char*) MMstartstr(m, MTOP(fileName));

  // DEBUG
  MMechostr(MSKDEBUG, "LOAD: strFileName = %s\n", strFileName);

  // Set path name and load user profile
  EpocObj->SetUserProfileFileName(strFileName);
  EpocObj->SetProfileLoadingDone(false);

	MMset(m, 0, 0);
  return 0;
}


/*! @ingroup grpepoc
* \brief _SaveProfile : This function save current user profile to file (*.emu)
*
* <b>Prototype:</b> fun [ObjEpoc S] I
* \param ObjEpoc : the current ObjEpoc
* \param S : path to the user profile file name
*
* \return I : ObjEpoc if success
*/
int _SaveProfile(mmachine m)
{
  int fileName = MMpull(m);
	int epocTab = MTOP(MMget(m, 0));
	if (epocTab == NIL) 
  { 
    MMset(m, 0, NIL); 
    return 0; 
  }

  // Retrieve Emotiv EPOC instance
  Epoc * EpocObj = (Epoc*) MMfetch(m, epocTab, 0);
  if (!EpocObj) 
  { 
    MMset(m, 0, NIL);
    return 0;
  }

  // Convert parameter to char*
  char* strFileName = (char*) MMstartstr(m, MTOP(fileName));

  // Eventually update path name and save user profile
  MMechostr(MSKDEBUG, "SAVE: strFileName = %s\n", strFileName);
  if (strcmp(strFileName, "") != 0)
    EpocObj->SetUserProfileFileName(strFileName);
  EpocObj->SetProfileSavingDone(false);

	MMset(m, 0, 0);
  return 0;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivTrainingErased : This function sets the Callback for Expressiv Training Erased event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivTrainingErased(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_ERASED_CB);
}

int getEpocExpressivTrainingErasedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_TRAINING_ERASED_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0)))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivTrainingErased : This function sets the Callback for Cognitiv Training Erased event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivTrainingErased(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_COGNITIV_TRAINING_ERASED_CB);
}

int getEpocCognitivTrainingErasedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_TRAINING_ERASED_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0)))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivTrainingRejected : This function sets the Callback for Expressiv Training Rejected event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivTrainingRejected(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_REJECTED_CB);
}

int getEpocExpressivTrainingRejectedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_TRAINING_REJECTED_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0)))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivTrainingRejected : This function sets the Callback for Cognitiv Training Rejected event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivTrainingRejected(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_COGNITIV_TRAINING_REJECTED_CB);
}

int getEpocCognitivTrainingRejectedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_TRAINING_REJECTED_CB))
		return 0;

	if ((k = OBJcallreflex(m, 0)))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivTrainingSucceeded : This function sets the Callback for Expressiv Training Succeeded event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivTrainingSucceeded(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB);
}

int getEpocExpressivTrainingSucceededCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB))
		return 0;

  if ((k = OBJcallreflex(m, 0)))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivTrainingSucceeded : This function sets the Callback for Cognitiv Training Succeeded event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivTrainingSucceeded(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB);
}

int getEpocCognitivTrainingSucceededCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_TRAINING_SUCCEEDED_CB))
		return 0;

	if (k = OBJcallreflex(m, 0))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocExpressivTrainingFailed : This function sets the Callback for Expressiv Training Failed event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocExpressivTrainingFailed(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_EXPRESSIV_TRAINING_FAILED_CB);
}

int getEpocExpressivTrainingFailedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_EXPRESSIV_TRAINING_FAILED_CB))
		return 0;

	if (k = OBJcallreflex(m, 0))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocCognitivTrainingFailed : This function sets the Callback for Cognitiv Training Failed event from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocCognitivTrainingFailed(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_COGNITIV_TRAINING_FAILED_CB);
}

int getEpocCognitivTrainingFailedCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0;
	Epoc * EpocObj = (Epoc*) id;
	
	// OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_COGNITIV_TRAINING_FAILED_CB))
		return 0;

	if (k = OBJcallreflex(m, 0))
    return k;
	return k;
}


/*! @ingroup grpepoc
* \brief _CBEpocRawEEGData : This function sets the Callback for new raw EEG data received from Emotiv EPOC 
*
* <b>Prototype:</b> fun [ObjEpoc fun [ObjEpoc u0 [F r1]] u1 u0] ObjEpoc
* \param ObjEpoc : the current ObjEpoc
* \param fun [ObjEpoc u0 [F r1]] : SCOL CallBack function to call
* \param u1 : user parameter
* \param u0 : user parameter
*
* \return I : ObjEpoc if success
*/
int _CBEpocRawEEGData(mmachine m)
{
  return OBJaddreflex(m, OBJEPOCSCOL, SCOL_EPOC_RAW_EEG_CB);
}

int getEpocRawEEGDataCb(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{
	int k = 0, i = 0;
	Epoc* EpocObj = (Epoc*) id;
  
  // OBJbeginreflex(mmachine, objecttype, objectptr, cbtype)
  if (OBJbeginreflex(m, OBJEPOCSCOL, (int)EpocObj, SCOL_EPOC_RAW_EEG_CB))
		return 0;

  // Browse raw EEG data
  //MMechostr(MSKDEBUG, ">>> EEG data size = %d\n", sizeof(EpocObj->fEEGData));
  for (i = 0; i < 14; i++)
  {
    if (MMpush(m, FTOM(EpocObj->fEEGData[i])))
      return MERRMEM;
  }

	if (MMpush(m, NIL))
    return MERRMEM;

	for (i = 0; i < 14; i++)
	{
    if (MMpush(m, 2*2))		
      return MERRMEM;
		if (k = MBdeftab(m))		
      return k;
	}
  
	// Call reflex previously defined
	k = OBJcallreflex(m, 1);
	return k;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											                                                         ////
///										                  DECLARATION OF FUNCTIONS (FOR SCOL)											                    ///
////																											                                                         ////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//! Nb of Scol functions or types
#define NbTplPKG 30


/*!
*	Scol function names
*/
char	*TplName[NbTplPKG] =
{
	"ObjEpoc",
  "_CREpoc",
	"_DSEpoc",
  "_CBEpocConnected",
  "_CBEpocDisconnected",
  "_CBEpocBadSignal",
  "_CBEpocLowBattery",
  "_CBEpocHeadsetData",
  "_CBEpocAffectivData",
  "_CBEpocExpressivData",
  "_CBEpocCognitivData",
  "_CBEpocExpressivTrainingStarted",
  "_CBEpocCognitivTrainingStarted",
  "_CBEpocExpressivTrainingCompleted",
  "_CBEpocCognitivTrainingCompleted",
  "_CBEpocExpressivTrainingErased",
  "_CBEpocCognitivTrainingErased",
  "_CBEpocExpressivTrainingRejected",
  "_CBEpocCognitivTrainingRejected",
  "_CBEpocExpressivTrainingSucceeded",
  "_CBEpocCognitivTrainingSucceeded",
  "_CBEpocExpressivTrainingFailed",
  "_CBEpocCognitivTrainingFailed",
  "_CBEpocRawEEGData",
  "_StartExpressivTraining",
  "_EraseExpressivTraining",
  "_StartCognitivTraining",
  "_EraseCognitivTraining",
  "_LoadProfile",
  "_SaveProfile"
};


/*!
*	Pointers to C functions that manipulate the VM for each scol function previously defined
*/
int (*TplFunc[NbTplPKG])(mmachine m)=
{
	NULL,																				// ObjEpoc
  _CREpoc,													          // _CREpoc
	_DSEpoc,													          // _DSEpoc
  _CBEpocConnected,                           // _CBEpocConnected
  _CBEpocDisconnected,                        // _CBEpocDisconnected
  _CBEpocBadSignal,                           // _CBEpocBadSignal    
  _CBEpocLowBattery,                          // _CBEpocLowBattery  
  _CBEpocHeadsetData,                         // _CBEpocHeadsetData
  _CBEpocAffectivData,                        // _CBEpocAffectivData
  _CBEpocExpressivData,                       // _CBEpocExpressivData
  _CBEpocCognitivData,                        // _CBEpocCognitivData
  _CBEpocExpressivTrainingStarted,            // _CBEpocExpressivTrainingStarted
  _CBEpocCognitivTrainingStarted,             // _CBEpocCognitivTrainingStarted
  _CBEpocExpressivTrainingCompleted,          // _CBEpocExpressivTrainingCompleted
  _CBEpocCognitivTrainingCompleted,           // _CBEpocCognitivTrainingCompleted
  _CBEpocExpressivTrainingErased,             // _CBEpocExpressivTrainingErased
  _CBEpocCognitivTrainingErased,              // _CBEpocCognitivTrainingErased
  _CBEpocExpressivTrainingRejected,           // _CBEpocExpressivTrainingRejected
  _CBEpocCognitivTrainingRejected,            // _CBEpocCognitivTrainingRejected
  _CBEpocExpressivTrainingSucceeded,          // _CBEpocExpressivTrainingSucceeded
  _CBEpocCognitivTrainingSucceeded,           // _CBEpocCognitivTrainingSucceeded
  _CBEpocExpressivTrainingFailed,             // _CBEpocExpressivTrainingFailed
  _CBEpocCognitivTrainingFailed,              // _CBEpocCognitivTrainingFailed
  _CBEpocRawEEGData,                          // _CBEpocRawEEGData
  _StartExpressivTraining,									  // _StartExpressivTraining
  _EraseExpressivTraining,									  // _EraseExpressivTraining
  _StartCognitivTraining,                     // _StartCognitivTraining
  _EraseCognitivTraining,									    // _EraseCognitivTraining
  _LoadProfile,                               // _LoadProfile
  _SaveProfile                                // _SaveProfile
};


/*!
*	Nb of arguments of each scol function
*/
int TplNArg[NbTplPKG]=
{
	TYPTYPE,																		// ObjEpoc
  1,																					// _CREpoc
	1,																					// _DSEpoc
  3,                                          // _CBEpocConnected
  3,                                          // _CBEpocDisconnected
  3,                                          // _CBEpocBadSignal
  3,                                          // _CBEpocLowBattery
  3,                                          // _CBEpocHeadsetData
  3,                                          // _CBEpocAffectivData
  3,                                          // _CBEpocExpressivData
  3,                                          // _CBEpocCognitivData
  3,                                          // _CBEpocExpressivTrainingStarted
  3,                                          // _CBEpocCognitivTrainingStarted
  3,                                          // _CBEpocExpressivTrainingCompleted
  3,                                          // _CBEpocCognitivTrainingCompleted
  3,                                          // _CBEpocExpressivTrainingErased
  3,                                          // _CBEpocCognitivTrainingErased
  3,                                          // _CBEpocExpressivTrainingRejected
  3,                                          // _CBEpocCognitivTrainingRejected
  3,                                          // _CBEpocExpressivTrainingSucceeded
  3,                                          // _CBEpocCognitivTrainingSucceeded
  3,                                          // _CBEpocExpressivTrainingFailed
  3,                                          // _CBEpocCognitivTrainingFailed
  3,                                          // _CBEpocRawEEGData
  2,                                          // _StartExpressivTraining
  2,                                          // _EraseExpressivTraining
  2,                                          // _StartCognitivTraining
  2,                                          // _EraseCognitivTraining
  2,                                          // _LoadProfile
  2                                           // _SaveProfile
};


/*!
*	Prototypes of the scol functions
*/
char* TplType[NbTplPKG]=
{
	NULL,																			                    // ObjEpoc
  "fun [Chn] ObjEpoc",										                      // _CREpoc
	"fun [ObjEpoc] I",											                      // _DSEpoc
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",	              // _CBEpocConnected
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",	              // _CBEpocDisconnected
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocBadSignal
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocLowBattery
  "fun [ObjEpoc fun [ObjEpoc u0 [I I] [I I I I I I I] [I I I I I I I] [F F] F] u1 u0] ObjEpoc",       // _CBEpocHeadsetData
  "fun [ObjEpoc fun [ObjEpoc u0 F F F F F] u1 u0] ObjEpoc",     // _CBEpocAffectivData
  "fun [ObjEpoc fun [ObjEpoc u0 I I F I F] u1 u0] ObjEpoc",     // _CBEpocExpressivData
  "fun [ObjEpoc fun [ObjEpoc u0 I F] u1 u0] ObjEpoc",           // _CBEpocCognitivData
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocExpressivTrainingStarted
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocCognitivTrainingStarted
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocExpressivTrainingCompleted
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocCognitivTrainingCompleted
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocExpressivTrainingErased
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocCognitivTrainingErased
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocExpressivTrainingRejected
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocCognitivTrainingRejected
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocExpressivTrainingSucceeded
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocCognitivTrainingSucceeded
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocExpressivTrainingFailed
  "fun [ObjEpoc fun [ObjEpoc u0] u1 u0] ObjEpoc",               // _CBEpocCognitivTrainingFailed
  "fun [ObjEpoc fun [ObjEpoc u0 [F r1]] u1 u0] ObjEpoc",        // _CBEpocRawEEGData
  "fun [ObjEpoc I] I",													                // _StartExpressivTraining
  "fun [ObjEpoc I] I",													                // _EraseExpressivTraining
  "fun [ObjEpoc I] I",                                          // _StartCognitivTraining
  "fun [ObjEpoc I] I",                                          // _EraseCognitivTraining
  "fun [ObjEpoc S] I",                                          // _LoadProfile
  "fun [ObjEpoc S] I"                                           // _SaveProfile
};



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////																											                                                         ////
///												                        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 LoadEpoc(mmachine m) 
{
  // Return variable for PKhardpak function
	int k;

	// Declare a new type of object ("OBJEPOCSCOL")
	OBJEPOCSCOL = OBJregister(21, 1, destroyEpocObj, "OBJEPOCSCOL");

  EPOC_CONNECTED_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_CONNECTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocConnectedCb);

  EPOC_DISCONNECTED_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_DISCONNECTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocDisconnectedCb);

  EPOC_BAD_SIGNAL_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_BAD_SIGNAL_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocBadSignalCb);

  EPOC_LOW_BATTERY_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_LOW_BATTERY_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocLowBatteryCb);

  EPOC_HEADSET_DATA_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_HEADSET_DATA_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocHeadsetDataCb);

  EPOC_AFFECTIV_DATA_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_AFFECTIV_DATA_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocAffectivDataCb);

  EPOC_EXPRESSIV_DATA_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_EXPRESSIV_DATA_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivDataCb);

  EPOC_COGNITIV_DATA_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_COGNITIV_DATA_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivDataCb);

  EPOC_EXPRESSIV_TRAINING_STARTED_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_EXPRESSIV_TRAINING_STARTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivTrainingStartedCb);

  EPOC_COGNITIV_TRAINING_STARTED_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_COGNITIV_TRAINING_STARTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivTrainingStartedCb);

  EPOC_EXPRESSIV_TRAINING_COMPLETED_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_EXPRESSIV_TRAINING_COMPLETED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivTrainingCompletedCb);

  EPOC_COGNITIV_TRAINING_COMPLETED_CB = OBJgetUserEvent();
	OBJdefEvent(EPOC_COGNITIV_TRAINING_COMPLETED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivTrainingCompletedCb);

  EPOC_EXPRESSIV_TRAINING_ERASED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_EXPRESSIV_TRAINING_ERASED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivTrainingErasedCb);

  EPOC_COGNITIV_TRAINING_ERASED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_COGNITIV_TRAINING_ERASED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivTrainingErasedCb);

  EPOC_EXPRESSIV_TRAINING_REJECTED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_EXPRESSIV_TRAINING_REJECTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivTrainingRejectedCb);

  EPOC_COGNITIV_TRAINING_REJECTED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_COGNITIV_TRAINING_REJECTED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivTrainingRejectedCb);

  EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivTrainingSucceededCb);

  EPOC_COGNITIV_TRAINING_SUCCEEDED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_COGNITIV_TRAINING_SUCCEEDED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivTrainingSucceededCb);

  EPOC_EXPRESSIV_TRAINING_FAILED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_EXPRESSIV_TRAINING_FAILED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocExpressivTrainingFailedCb);

  EPOC_COGNITIV_TRAINING_FAILED_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_COGNITIV_TRAINING_FAILED_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocCognitivTrainingFailedCb);
  
  EPOC_RAW_EEG_CB = OBJgetUserEvent();
  OBJdefEvent(EPOC_RAW_EEG_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getEpocRawEEGDataCb);

  // Load package
	k = PKhardpak(m, "EpocEngine", NbTplPKG, TplName, TplFunc, TplNArg, TplType);
	return k;
}

//! \endcond


// Clean all connections to an Emotiv EPOC headset
void CleanDirtyConnections()
{
  std::list<Epoc*>::iterator iEpocList = lEpocList.begin();
  while (iEpocList != lEpocList.begin())
  {
    (*iEpocList)->Disconnect();
    iEpocList++;
  }
}


/*! 
* \brief Starting point of the DLL
*/
extern "C" __declspec (dllexport) int ScolLoadPlugin(mmachine m, cbmachine w) 
{
	SCOLinitplugin(w);

	// Get Scol window handle (for message callback)
	HScol = (HWND)SCgetExtra("hscol");
	LoadEpoc(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() 
{
  // Clean all connections to an Emotiv EPOC headset
  CleanDirtyConnections();
	return 0;
}
