// Burner Game Input
#include "fba.h"

// Player Default Controls
int nPlayerDefaultControls[4] = {0, 1, 2, 3};

// Mapping of PC inputs to game inputs
struct GameInp* GameInp = NULL;
unsigned int nGameInpCount = 0;

int GameInpBlank(int bDipSwitch)
{
	unsigned int i = 0;
	struct GameInp* pgi = NULL;

	// Reset all inputs to undefined (even dip switches, if bDipSwitch==1)
	if (GameInp == NULL) {
		return 1;
	}

	// Get the targets in the library for the Input Values
	for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
		struct BurnInputInfo bii;
		memset(&bii, 0, sizeof(bii));
		BurnDrvGetInputInfo(&bii, i);
		if (bDipSwitch == 0 && (bii.nType >= 2 && bii.nType <= 3)) {	// Don't blank the dip switches
			continue;
		}

		memset(pgi, 0, sizeof(*pgi));
		pgi->nType = bii.nType;											// store input type
		pgi->pVal = bii.pVal;											// store input pointer to value
	}
	return 0;
}

int GameInpInit()
{
	int nRet = 0;
	// Count the number of inputs
	nGameInpCount=0;
	for (unsigned int i = 0; i < 0x1000; i++) {
		nRet = BurnDrvGetInputInfo(NULL,i);
		if (nRet) {														// end of input list
			nGameInpCount = i;
			break;
		}
	}

	// Allocate space for all the inputs
	GameInp = (struct GameInp*)malloc(nGameInpCount * sizeof(struct GameInp));
	if (GameInp == NULL) {
		return 1;
	}
	GameInpBlank(1);

	return 0;
}

int GameInpExit()
{
	if (GameInp != NULL) {
		free(GameInp);
		GameInp = NULL;
	}
	nGameInpCount = 0;
	
	return 0;
}

static char* InpToString(struct GameInp* pgi)
{
	static char szString[80];
	if (pgi->nInput == 0) {
		return "undefined";
	}
	if (pgi->nInput == 1) {
		sprintf(szString, "constant 0x%.2X", pgi->nConst);
		return szString;
	}
	if (pgi->nInput == 2) {
		sprintf(szString, "switch 0x%.2X", pgi->nCode);
		return szString;
	}
	if (pgi->nInput == 3) {
		sprintf(szString, "joyaxis %d %d", pgi->nJoy, pgi->nAxis);
		return szString;
	}
	if (pgi->nInput == 4) {
		sprintf(szString, "joyaxis-neg %d %d", pgi->nJoy, pgi->nAxis);
		return szString;
	}
	if (pgi->nInput == 5) {
		sprintf(szString, "joyaxis-pos %d %d", pgi->nJoy, pgi->nAxis);
		return szString;
	}
	if (pgi->nInput == 6) {
		sprintf(szString, "slider 0x%.2x 0x%.2x speed 0x%x center %d", pgi->nSlider[0], pgi->nSlider[1], pgi->nSliderSpeed, pgi->nSliderCenter);
		return szString;
	}
	if (pgi->nInput == 7) {
		sprintf(szString, "joyslider %d %d speed 0x%x center %d", pgi->nJoy, pgi->nAxis, pgi->nSliderSpeed, pgi->nSliderCenter);
		return szString;
	}
	
	return "unknown";
}

/*char* InpToDesc(struct GameInp* pgi)
{
	if (pgi->nInput == 0) {
		return "";
	}
	if (pgi->nInput == 1 && pgi->nConst == 0) {
		return "-";
	}
	if (pgi->nInput == 2) {
		return InputCodeDesc(pgi->nCode);
	}
	if (pgi->nInput >= 3 && pgi->nInput <= 5) {
		static char szInputName[64] = "";
		char szAxis[8][3] = {"X", "Y", "Z", "rX", "rY", "rZ", "s0", "s1"};
		char szRange[3][16] = {"full", "negative", "positive"};
		sprintf(szInputName, "Joy %d %s axis (%s range)", pgi->nJoy, szAxis[pgi->nAxis], szRange[pgi->nInput - 3]);
		return szInputName;
	}

	return InpToString(pgi);							// Just do the rest as they are in the config file
}*/

static char* SliderInfo(struct GameInp* pgi, char* s)
{
	char* szRet = NULL;
/*	pgi->nSliderSpeed = 0x700;							// defaults
	pgi->nSliderCenter = 0;
	pgi->nSliderValue = 0x8000;

	szRet = LabelCheck(s, "speed");
	s = szRet;
	if (s == NULL) {
		return s;
	}
	pgi->nSliderSpeed = (short)strtol(s, &szRet, 0);
	s = szRet;
	if (s==NULL) {
		return s;
	}
	szRet = LabelCheck(s, "center");
	s = szRet;
	if (s == NULL) {
		return s;
	}
	pgi->nSliderCenter = (short)strtol(s, &szRet, 0);
	s = szRet;
	if (s == NULL) {
		return s;
	} */
	
	return szRet; 
}

static int StringToJoyAxis(struct GameInp* pgi, char* s)
{
	char* szRet = s;

	pgi->nJoy = (unsigned char)strtol(s, &szRet, 0);
	if (szRet == NULL) {
		return 1;
	}
	s = szRet;
	pgi->nAxis = (unsigned char)strtol(s, &szRet, 0);
	if (szRet == NULL) {
		return 1;
	}
	
	return 0;
}

/*static int StringToInp(struct GameInp* pgi, char* s)
{
	char* szRet = NULL;

	SKIP_WS(s);													// skip whitespace
	szRet = LabelCheck(s, "undefined");
	if (szRet) {
		pgi->nInput = 0;
		return 0;
	}

	szRet = LabelCheck(s, "constant");
	if (szRet) {
		pgi->nInput = 1;
		s = szRet;
		pgi->nConst=(unsigned char)strtol(s, &szRet, 0);
		*(pgi->pVal) = pgi->nConst;
		return 0;
	}

	szRet = LabelCheck(s, "switch");
	if (szRet) {
		pgi->nInput = 2;
		s = szRet;
		pgi->nCode = (unsigned short)strtol(s, &szRet, 0);
		return 0;
	}

	// Analog using joystick axis:
	szRet = LabelCheck(s, "joyaxis-neg");
	if (szRet) {
		pgi->nInput = 4;
		return StringToJoyAxis(pgi, szRet);
	}
	szRet = LabelCheck(s, "joyaxis-pos");
	if (szRet) {
		pgi->nInput = 5;
		return StringToJoyAxis(pgi, szRet);
	}
	szRet = LabelCheck(s, "joyaxis");
	if (szRet) {
		pgi->nInput = 3;
		return StringToJoyAxis(pgi, szRet);
	}

	// Analog using keyboard slider
	szRet = LabelCheck(s, "slider");
	if (szRet) {
		s = szRet;
		pgi->nInput = 6;
		pgi->nSlider[0] = 0; // defaults
		pgi->nSlider[1] = 0; //
		pgi->nSlider[0] = (unsigned short)strtol(s, &szRet, 0);
		s = szRet;
		if (s == NULL) {
			return 1;
		}
		pgi->nSlider[1] = (unsigned short)strtol(s, &szRet, 0);
		s = szRet;
		if (s == NULL) {
			return 1;
		}
		szRet = SliderInfo(pgi, s);
		s = szRet;
		if (s == NULL) {												// Get remaining slider info
			return 1;
		}
		return 0;
	}

	// Analog using joystick slider
	szRet = LabelCheck(s, "joyslider");
	if (szRet) {
		s = szRet;
		pgi->nInput = 7;
		pgi->nJoy = 0;	// defaults
		pgi->nAxis = 0;	//
		pgi->nJoy = (unsigned char)strtol(s, &szRet, 0);
		s = szRet;
		if (s == NULL) {
			return 1;
		}
		pgi->nAxis = (unsigned char)strtol(s, &szRet, 0);
		s = szRet;
		if (s == NULL) {
			return 1;
		}
		szRet = SliderInfo(pgi, s);										// Get remaining slider info
		s = szRet;
		if (s == NULL) {
			return 1;
		}
		return 0;
	}

	return 1;
} */

// Find the input number by
static unsigned int InputNameToNum(char *szName)
{
	for (unsigned int i = 0; i < nGameInpCount; i++) {
		struct BurnInputInfo bii;
		BurnDrvGetInputInfo(&bii, i);
		if (stricmp(szName, bii.szName) == 0) {
			return i;
		}
	}
	return ~0U;
}

static char *InputNumToName(unsigned int i)
{
	struct BurnInputInfo bii;
	bii.szName = NULL;
	BurnDrvGetInputInfo(&bii, i);
	if (bii.szName == NULL) {
		return "unknown";
	}
	return bii.szName;
}

static int GameInpAutoOne(struct GameInp *pgi, char *szi)
{

	for (int i = 0; i < nMaxPlayers; i++) {
		int nSlide = nPlayerDefaultControls[i] >> 4;
		switch (nPlayerDefaultControls[i] & 0x0F) {
 
			case 0:									// XBoxGamePad 1
				GamcAnalogJoy(pgi, szi, i, 0, nSlide);
				
				if (m_Config.GetJoyType(0) != 2)
					GamcXboxPlayer(pgi, szi, i, 0);
				else
					GamcXArcade(pgi, szi, i, 0);

				GamcMisc(pgi, szi, i);
				break;
			case 1:									// XBoxGamePad 2
				GamcAnalogJoy(pgi, szi, i, 1, nSlide);
				
				if (m_Config.GetJoyType(1) != 2)
					GamcXboxPlayer(pgi, szi, i, 1);
				else
					GamcXArcade(pgi, szi, i, 1);

				GamcMisc(pgi, szi, i);
				break;
			case 2:									// XBoxGamePad 3
				GamcAnalogJoy(pgi, szi, i, 2, nSlide);
				
				if (m_Config.GetJoyType(1) != 2)
					GamcXboxPlayer(pgi, szi, i, 2);
				else
					GamcXArcade(pgi, szi, i, 2);
				
				GamcMisc(pgi, szi, i);
				break;
			case 3:									// XBoxGamePad 4
				GamcAnalogJoy(pgi, szi, i, 3, nSlide);
				
				if (m_Config.GetJoyType(3) != 2)
					GamcXboxPlayer(pgi, szi, i, 3);
				else
					GamcXArcade(pgi, szi, i, 3);
				
				GamcMisc(pgi, szi, i);
				break;

		}
	}

	return 0;
}

// Auto-configure any undefined inputs to defaults
int GameInpDefault()
{
	struct GameInp* pgi = NULL;
	unsigned int i;

	// Write input types
	for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
		struct BurnInputInfo bii;
		if (pgi->nInput) {				// Already defined - leave it alone
			continue;
		}
		pgi->nInput = 0;				// Default to undefined

		// Get the extra info about the input
		bii.szInfo = NULL;
		BurnDrvGetInputInfo(&bii, i);
		if (bii.szInfo == NULL) {
			bii.szInfo = "";
		}
		GameInpAutoOne(pgi, bii.szInfo);
	}
	
	return 0;
}

// Write all the GameInps out to config file 'h'
int GameInpWrite(FILE* h)
{
	// Write input types
	for (unsigned int i = 0; i < nGameInpCount; i++) {
		char *szName = NULL;
		int nPad = 0;
		szName = InputNumToName(i);
		fprintf(h, "input \"%s\" ", szName);
		nPad = 16 - strlen(szName);
		for (int j = 0; j < nPad; j++) {
			fprintf(h, " ");
		}
		fprintf(h, "%s\n", InpToString(GameInp + i));
	}
	
	return 0;
}


#ifndef _XBOX

// Read a GameInp in
int GameInpRead(char* szVal, bool bOverWrite)
{
	int nRet;
	char* szQuote = NULL;
	char* szEnd = NULL;
	unsigned int i = 0;

	nRet = QuoteRead(&szQuote, &szEnd, szVal);
	if (nRet) {
		return 1;
	}
	
	// Find which input number this refers to
	i = InputNameToNum(szQuote);
	if (i == ~0U) {
		return 1;
	}

	if (bOverWrite || GameInp[i].nInput == 0) {
		// Parse the input description into the GameInp structure
		StringToInp(GameInp + i, szEnd);
	}
	
	return 0;
}

#endif