#ifndef VRPN_PHANTOM_H
#define VRPN_PHANTOM_H

#include  "vrpn_Configure.h"
#ifdef	VRPN_USE_PHANTOM_SERVER

// Hide the include files which use the old version of iostreams
// by only defining the types we need from them here and doing
// the includes in the .C file.  Yucky and frought with danger.
// I've asked SensAble to hide the includes.
#ifdef	VRPN_USE_HDAPI
typedef unsigned int HHD;
typedef unsigned long HDSchedulerHandle;
typedef void *HHLRC;
typedef unsigned int HLuint;
#else
class gstScene;
class gstSeparator;
class gstPHANToM;
#endif

class Plane;
class DynamicPlane;
class Trimesh;
class ConstraintEffect;
class ForceFieldEffect;

// XXX HDAPI uses Planes rather than DynamicPlanes because I couldn't debug the
// more complicated plane port.  Symptoms of the broken-ness for the Dynamic
// plane: The sphere_client program puts a plane facing
// in the positive Y direction (at Y=0) which never moves.  Check the
// updateDynamics() call, perhaps.
#ifdef	VRPN_USE_HDAPI
#undef	DYNAMIC_PLANES
#else
#define	DYNAMIC_PLANES
#endif

// ajout ONDIM
/*
# instantBuzzEffect : instantaneous buzz "custom" effect for Phantom server
# written by Sebastien MARAUX, ONDIM SA (France)
# maraux@ondim.fr
*/
const unsigned int NB_CUSTOM_EFFECTS = 1;
class InstantBuzzEffect;
const unsigned BUZZ_EFFECT_ID = 0;
// fin ajout ONDIM

#include "vrpn_Button.h"
#include "vrpn_Tracker.h"
#include "vrpn_ForceDeviceServer.h"

class vrpn_Plane_PHANTOMCB {
public:
  struct	timeval	msg_time;   // Time of the report
  float		SurfaceKspring;	    //surface spring coefficient
  float		SurfaceFdynamic;    //surface dynamic friction coefficient
  float		SurfaceFstatic;	    //surface static friction coefficient
  float		SurfaceKdamping;    //surface damping coefficient


  vrpn_int32	which_plane;
  float		plane[4];	// plane equation, ax+by+cz+d = 0
  vrpn_int32	numRecCycles;	// number of recovery cycles
};

typedef void (VRPN_CALLBACK *vrpn_PHANTOMPLANECHANGEHANDLER)(void *userdata,
					 const vrpn_Plane_PHANTOMCB &info);

class vrpn_Phantom: public vrpn_ForceDeviceServer,public vrpn_Tracker,
					public vrpn_Button_Filter {
	friend void phantomErrorHandler( int errnum, char *description,
                                         void *userdata);
protected:
	double update_rate;
#ifdef	VRPN_USE_HDAPI
	HHD		  phantom;	    //< The Phantom hardware device we are using
        HHLRC             hHLRC;            //< handle to haptic rendering context
        HLuint            effectId;         //< Effect ID of HL custom force effect
        int   button_0_bounce_count, button_1_bounce_count; //< Used to remove button "bounce"
	// Jean SIMARD <jean.simard@limsi.fr>
	// Add a field which contain the name of the PHANToM configuration
	char sconf[512];

#else
	gstScene *scene;
	gstSeparator *rootH;	    //< The haptics root separator attached to the scene.
	gstSeparator *hapticScene;  //< The next separator containing the entire scene graph.
	gstSeparator *phantomAxis;	//< The axis of the phantom is moved
	gstPHANToM *phantom;
#endif
	struct timeval timestamp;
#ifdef	DYNAMIC_PLANES
	DynamicPlane *planes[MAXPLANE];
#else
	Plane *planes[MAXPLANE];
#endif
//	Trimesh *trimesh;
				       
	ConstraintEffect *pointConstraint;  // this is a force appended to
					    // other forces exerted by phantom
					    // (Superceded by ForceFieldEffect)
	ForceFieldEffect *forceField; //< general purpose force field approximation

	// ajout ONDIM
	// add each effect pointer
	InstantBuzzEffect *instantBuzzEffect;
	// fin ajout ONDIM
	
	typedef	struct vrpn_RPCS {
		void				*userdata;
		vrpn_PHANTOMPLANECHANGEHANDLER	handler;
		struct vrpn_RPCS		*next;
	} vrpn_PHANTOMCHANGELIST;
	vrpn_PHANTOMCHANGELIST	*plane_change_list;

	static int VRPN_CALLBACK handle_plane_change_message(void *userdata, 
					       vrpn_HANDLERPARAM p);
	static int VRPN_CALLBACK handle_effects_change_message(void *userdata,
							vrpn_HANDLERPARAM p);
	static int VRPN_CALLBACK handle_forcefield_change_message(void *userdata,
						vrpn_HANDLERPARAM p);
	static int VRPN_CALLBACK handle_custom_effect_change_message(void *userdata,
						vrpn_HANDLERPARAM p);
	static int VRPN_CALLBACK handle_dropConnection (void *, vrpn_HANDLERPARAM);

	// from vrpn_Tracker

	static int VRPN_CALLBACK handle_update_rate_request (void *, vrpn_HANDLERPARAM);
	static int VRPN_CALLBACK handle_resetOrigin_change_message(void * userdata,
							vrpn_HANDLERPARAM p);

	// Add an object to the haptic scene as root (parent -1 = default) or as child (ParentNum =the number of the parent)
	virtual bool addObject(vrpn_int32 objNum, vrpn_int32 ParentNum); 
	// Add an object next to the haptic scene as root 
	virtual bool addObjectExScene(vrpn_int32 objNum); 
	// vertNum normNum and triNum start at 0
	virtual bool setVertex(vrpn_int32 objNum, vrpn_int32 vertNum,vrpn_float32 x,vrpn_float32 y,vrpn_float32 z);
    // NOTE: ghost doesn't take normals, 
    //       and normals still aren't implemented for Hcollide
    virtual bool setNormal(vrpn_int32 objNum, vrpn_int32 normNum,vrpn_float32 x,vrpn_float32 y,vrpn_float32 z);
    virtual bool setTriangle(vrpn_int32 objNum, vrpn_int32 triNum,vrpn_int32 vert0,vrpn_int32 vert1,vrpn_int32 vert2,
		  vrpn_int32 norm0,vrpn_int32 norm1,vrpn_int32 norm2);
    virtual bool removeTriangle(vrpn_int32 objNum, vrpn_int32 triNum); 
    // should be called to incorporate the above changes into the 
    // displayed trimesh 
    virtual bool updateTrimeshChanges(vrpn_int32 objNum,vrpn_float32 kspring, vrpn_float32 kdamp, vrpn_float32 fdyn, vrpn_float32 fstat);
	// set the type of trimesh
	virtual bool setTrimeshType(vrpn_int32 objNum,vrpn_int32 type);
    // set the trimesh's homogen transform matrix (in row major order)
    virtual bool setTrimeshTransform(vrpn_int32 objNum, vrpn_float32 homMatrix[16]);
	// set position of an object
	virtual bool setObjectPosition(vrpn_int32 objNum, vrpn_float32 Pos[3]);
	// set orientation of an object
	virtual bool setObjectOrientation(vrpn_int32 objNum, vrpn_float32 axis[3], vrpn_float32 angle);
	// set Scale of an object
	virtual bool setObjectScale(vrpn_int32 objNum, vrpn_float32 Scale[3]);
	// remove an object from the scene
	virtual bool removeObject(vrpn_int32 objNum);
    virtual bool clearTrimesh(vrpn_int32 objNum);
  
	/** Functions to organize the scene	**********************************************************/
	// Change The parent of an object
	virtual bool moveToParent(vrpn_int32 objNum, vrpn_int32 ParentNum);
	// Set the Origin of the haptic scene
	virtual bool setHapticOrigin(vrpn_float32 Pos[3], vrpn_float32 axis[3], vrpn_float32 angle);    
	// Set the Scale factor of the haptic scene
	virtual bool setHapticScale(vrpn_float32 Scale);
	// Set the Origin of the haptic scene
	virtual bool setSceneOrigin(vrpn_float32 Pos[3], vrpn_float32 axis[3], vrpn_float32 angle);    
	// get new ID, use only if wish to use vrpn ids and do not want to manage them yourself: ids need to be unique
	//virtual vrpn_int32 getNewObjectID();
	// make an object touchable or not
	virtual bool setObjectIsTouchable(vrpn_int32 objNum, vrpn_bool IsTouchable);

#ifdef VRPN_USE_HDAPI
        void initHL(HHD phantom);
        void tearDownHL(void);
#else
        gstSeparator *GetObject(vrpn_int32 objNum);
#endif
	Trimesh *GetObjectMesh(vrpn_int32 objNum);
public:
	// Jean SIMARD <jean.simard@limsi.fr>
	// Modification of the constructor
	// The default value is the default value use by the tool of SensAble
	vrpn_Phantom(char *name, vrpn_Connection *c, float hz=1.0, const char * newsconf="Default PHANToM");
	~vrpn_Phantom();

	virtual void mainloop(void);
	virtual void reset();
	void resetPHANToM(void);
	void getPosition(double *vec, double *quat);
	virtual void print_report(void);
	virtual int register_change_handler(void *userdata,
		vrpn_PHANTOMPLANECHANGEHANDLER handler,
		vrpn_PHANTOMCHANGELIST	*&change_list);
	virtual int unregister_change_handler(void *userdata,
		vrpn_PHANTOMPLANECHANGEHANDLER handler,
		vrpn_PHANTOMCHANGELIST	*&change_list);

	virtual int register_plane_change_handler(void *userdata,
		vrpn_PHANTOMPLANECHANGEHANDLER handler);
	virtual int unregister_plane_change_handler(void *userdata,
		vrpn_PHANTOMPLANECHANGEHANDLER handler);

	static void VRPN_CALLBACK handle_plane(void *userdata,const vrpn_Plane_PHANTOMCB &p);
	static void VRPN_CALLBACK check_parameters(vrpn_Plane_PHANTOMCB *p);
};

#endif
#endif