#include "src/gamepad/Gamepad.h"

/*
struct Gamepad_device {
	// Unique device identifier for application session, starting at 0 for the first device attached and
	// incrementing by 1 for each additional device. If a device is removed and subsequently reattached
	// during the same application session, it will have a new deviceID.
	unsigned int deviceID;
	
	// Human-readable device name
	const char * description;
	
	// USB vendor/product IDs as returned by the driver. Can be used to determine the particular model of device represented.
	int vendorID;
	int productID;
	
	// Number of axis elements belonging to the device
	unsigned int numAxes;
	
	// Number of button elements belonging to the device
	unsigned int numButtons;
	
	// Array[numAxes] of values representing the current state of each axis, in the range [-1..1]
	float * axisStates;
	
	// Array[numButtons] of values representing the current state of each button
	bool * buttonStates;
	
	// Platform-specific device data storage. Don't touch unless you know what you're doing and don't
	// mind your code breaking in future versions of this library.
	void * privateData;
};
*/


bool verbose = false;

char *verboseMessage=(char*)malloc(1000);

void onButtonDown(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) {
	//buttonId is base 0

	if (verbose) {		
		sprintf(verboseMessage,"Button %u down on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
		cout<<verboseMessage;
	}

	int button = buttonID;

	int32 di,controller;
        controller=0;
        for(di=1;di<=device_last;di++){
          static device_struct *d;
          d=&devices[di];
          if (d->used==1){
          if (d->type==1){
          controller++;
	  if (d->handle_int==device->deviceID){

            //ON STRIG event
            static int32 i;
            if (controller<=256&&button<=255){//within supported range
              i=(controller-1)*256+button;
              if (onstrig[i].active){
            if (onstrig[i].id){
              if (onstrig[i].active==1){//(1)ON
                onstrig[i].state++;
              }else{//(2)STOP
                onstrig[i].state=1;
              }
              qbevent=1;
            }
              }
            }//within supported range

	    int32 eventIndex=createDeviceEvent(d);
	    setDeviceEventButtonValue(d,eventIndex,button,1);
            commitDeviceEvent(d);

            //set STRIG_button_pressed for button
            if (button>=0&&button<=255){
              d->STRIG_button_pressed[button]=1;
            }
          }//js index
        }//type==1
          }//used
        }//di

}

void onButtonUp(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) {
	if (verbose) {
		sprintf(verboseMessage,"Button %u up on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
		cout<<verboseMessage;
	}


	int button = buttonID;

	int32 di;
        for(di=1;di<=device_last;di++){
          static device_struct *d;
          d=&devices[di];
          if (d->used==1){
        if (d->type==1){
	  if (d->handle_int==device->deviceID){

	    int32 eventIndex=createDeviceEvent(d);
	    setDeviceEventButtonValue(d,eventIndex,button,0);
            commitDeviceEvent(d);

          }//js index
        }//type==1
          }//used
        }//di

}

void onAxisMoved(struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, void * context) {
	if (verbose) {
		sprintf(verboseMessage,"Axis %u moved from %f to %f on device %u at %f with context %p\n", axisID, lastValue, value, device->deviceID, timestamp, context);
		cout<<verboseMessage;
	}

	int axis=axisID;

	int32 di;

        for(di=1;di<=device_last;di++){
          static device_struct *d;
          d=&devices[di];
          if (d->used==1){
        if (d->type==1){
	  if (d->handle_int==device->deviceID){

            float f;
            f=value;
	    /*
            if (f==-32768) f=-32767;
            f/=32767.0;
	    */
            if (f>1.0) f=1.0;
            if (f<-1.0) f=-1.0;

	    int32 eventIndex=createDeviceEvent(d);
	    setDeviceEventAxisValue(d,eventIndex,axis,f);
            commitDeviceEvent(d);

          }//js index
        }//type==1
          }//used
        }//di

}

void onDeviceAttached(struct Gamepad_device * device, void * context) {
	if (verbose) {
		sprintf(verboseMessage,"Device ID %u attached (vendor = 0x%X; product = 0x%X) with context %p\n", device->deviceID, device->vendorID, device->productID, context);
		cout<<verboseMessage;
	}

int i,x,x2;

//re-aquire a potentially dropped device in its original index
for (i=1;i<=device_last;i++){
if (devices[i].used){
if (devices[i].type==1){//it's a joystick/gamepad
if (!devices[i].connected){

if (device->productID==devices[i].product_id){
if (device->vendorID==devices[i].vendor_id){
if (device->numAxes==devices[i].axes){
if (device->numButtons==devices[i].buttons){
//(sometimes when gamepads are re-plugged they receieve a generic name)
//if (strlen(device->description)==strlen(devices[i].description)){//same name length
//if (strcmp(device->description,devices[i].description)==0){//same name content
	//re-acquire device
	devices[i].handle_int=device->deviceID;
	if (!devices[i].connected){
		devices[i].connected=1;
		devices[i].name[strlen(devices[i].name)-14]=0;//Remove "[DISCONNECTED]"
	}
	devices[i].used=1;
	return;
//}
//}
}
}
}
}
}

}
}
}//i

//add new device
i=device_last+1;
if (i>device_max){
	device_struct *devices=(device_struct*)realloc(devices,(device_max*2+1)*sizeof(device_struct));
	device_max*=2;
}
memset(&devices[i],0,sizeof(device_struct));
devices[i].type=DEVICETYPE_CONTROLLER;
devices[i].description=strdup(device->description);
devices[i].handle_int=device->deviceID;
devices[i].buttons=device->numButtons;
devices[i].lastbutton=devices[i].buttons;
devices[i].axes=device->numAxes;
devices[i].lastaxis=devices[i].axes;
devices[i].product_id=device->productID;
devices[i].vendor_id=device->vendorID;
char name[1000];
strcpy (name,"[CONTROLLER][[NAME][");
strcat (name,devices[i].description);
strcat (name,"]]");
if (devices[i].lastbutton) strcat (name,"[BUTTON]");
if (devices[i].lastaxis) strcat (name,"[AXIS]");
if (devices[i].lastwheel) strcat (name,"[WHEEL]");
devices[i].name=strdup(name);

setupDevice(&devices[i]);

device_last=i;

}

void onDeviceRemoved(struct Gamepad_device * device, void * context) {
	if (verbose) {
		sprintf(verboseMessage,"Device ID %u removed with context %p\n", device->deviceID, context);
		cout<<verboseMessage;
	}

int i;
for (i=1;i<=device_last;i++){
if (devices[i].used){
if (devices[i].type==1){//it's a joystick/gamepad
if (devices[i].handle_int==device->deviceID){

  char name[1000];
  strcpy(name,devices[i].name);
  strcat(name,"[DISCONNECTED]");
  char *oldname=devices[i].name;
  devices[i].name=strdup(name);
  free(oldname);
  devices[i].connected=0;
}
}
}
}//i


}

static void initGamepad() {
	Gamepad_deviceAttachFunc(onDeviceAttached, (void *) 0x1);
	Gamepad_deviceRemoveFunc(onDeviceRemoved, (void *) 0x2);
	Gamepad_buttonDownFunc(onButtonDown, (void *) 0x3);
	Gamepad_buttonUpFunc(onButtonUp, (void *) 0x4);
	Gamepad_axisMoveFunc(onAxisMoved, (void *) 0x5);
	Gamepad_init();
}

void QB64_GAMEPAD_INIT(){
	initGamepad();
}

void QB64_GAMEPAD_POLL(){
	Gamepad_detectDevices();
	Gamepad_processEvents();
}

void QB64_GAMEPAD_SHUTDOWN(){
	Gamepad_deviceAttachFunc(NULL, (void *) 0x1);
	Gamepad_deviceRemoveFunc(NULL, (void *) 0x2);
	Gamepad_buttonDownFunc(NULL, (void *) 0x3);
	Gamepad_buttonUpFunc(NULL, (void *) 0x4);
	Gamepad_axisMoveFunc(NULL, (void *) 0x5);
	Gamepad_shutdown();
}
