/*
This file contains lookup information on known controllers
*/

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>

#include "joymapping.h"
#include "menu.h"
#include "input.h"
#include "user_io.h"
#include "cfg.h"

#define DPAD_COUNT 4

/*****************************************************************************/
static void trim(char * s)
{
	char *p = s;
	int l = strlen(p);
	if (!l) return;

	while (p[l - 1] == ' ') p[--l] = 0;
	while (*p && (*p == ' ')) ++p, --l;

	memmove(s, p, l + 1);
}

static char joy_names[NUMBUTTONS][32];
static int joy_count = 0;

static char joy_nnames[NUMBUTTONS][32];
static char joy_pnames[NUMBUTTONS][32];
static int defaults = 0;

static void read_buttons()
{
	char *p;

	memset(joy_names, 0, sizeof(joy_names));
	memset(joy_nnames, 0, sizeof(joy_nnames));
	memset(joy_pnames, 0, sizeof(joy_pnames));
	joy_count = 0;
	defaults = 0;

	user_io_read_confstr();

	// this option used as default name map (unless jn/jp is supplied)
	p = get_buttons(0);
	if (p)
	{
		for (int n = 0; n < NUMBUTTONS - DPAD_COUNT; n++)
		{
			substrcpy(joy_names[n], p, n);
			if (!joy_names[n][0]) break;

			printf("joy_name[%d] = %s\n", n, joy_names[n]);

			memcpy(joy_nnames[n], joy_names[n], sizeof(joy_nnames[0]));
			char *sstr = strchr(joy_nnames[n], '(');
			if (sstr) *sstr = 0;
			trim(joy_nnames[n]);

			if (!joy_nnames[n][0]) break;
			joy_count++;
		}
		printf("\n");
	}

	// - supports empty name to skip the button from default map
	// - only base button names must be used (ABXYLR Start Select)

	// name default map
	p = get_buttons(1);
	if (p)
	{
		memset(joy_nnames, 0, sizeof(joy_nnames));
		for (int n = 0; n < joy_count; n++)
		{
			substrcpy(joy_nnames[n], p, n);
			trim(joy_nnames[n]);
			if (joy_nnames[n][0]) printf("joy_nname[%d] = %s\n", n, joy_nnames[n]);
		}
		printf("\n");
	}

	// positional default map
	p = get_buttons(2);
	if (p)
	{
		defaults = cfg.gamepad_defaults;
		for (int n = 0; n < joy_count; n++)
		{
			substrcpy(joy_pnames[n], p, n);
			trim(joy_pnames[n]);
			if (joy_pnames[n][0]) printf("joy_pname[%d] = %s\n", n, joy_pnames[n]);
		}
		printf("\n");
	}
}

static int is_fire(char* name)
{
	if (!strncasecmp(name, "fire", 4) || !strncasecmp(name, "button", 6))
	{
		if (!strcasecmp(name, "fire") || strchr(name, '1')) return 1;
		if (strchr(name, '2')) return 2;
		if (strchr(name, '3')) return 3;
		if (strchr(name, '4')) return 4;
	}

	return 0;
}

void map_joystick(uint32_t *map, uint32_t *mmap, int num)
{
	static char mapinfo[1024];
	/*
	attemps to centrally defined core joy mapping to the joystick declaredy by a core config string
	we use the names declared by core with some special handling for specific edge cases

	Input button order is "virtual SNES" i.e.:
		A, B, X, Y, L, R, Select, Start
	*/
	read_buttons();
	sprintf(mapinfo, "P%d map:", num);
	if (!num) sprintf(mapinfo, "Map:");

	map[SYS_BTN_RIGHT] = mmap[SYS_BTN_RIGHT] & 0xFFFF;
	map[SYS_BTN_LEFT]  = mmap[SYS_BTN_LEFT]  & 0xFFFF;
	map[SYS_BTN_DOWN]  = mmap[SYS_BTN_DOWN]  & 0xFFFF;
	map[SYS_BTN_UP]    = mmap[SYS_BTN_UP]    & 0xFFFF;

	if (mmap[SYS_AXIS_X])
	{
		uint32_t key = KEY_EMU + (((uint16_t)mmap[SYS_AXIS_X]) << 1);
		map[SYS_BTN_LEFT] = (key << 16) | map[SYS_BTN_LEFT];
		map[SYS_BTN_RIGHT] = ((key+1) << 16) | map[SYS_BTN_RIGHT];
	}

	if (mmap[SYS_AXIS_Y])
	{
		uint32_t key = KEY_EMU + (((uint16_t)mmap[SYS_AXIS_Y]) << 1);
		map[SYS_BTN_UP] = (key << 16) | map[SYS_BTN_UP];
		map[SYS_BTN_DOWN] = ((key + 1) << 16) | map[SYS_BTN_DOWN];
	}

	// loop through core requested buttons and construct result map
	for (int i=0, n=0; i<joy_count; i++)
	{
		if (!strcmp(joy_names[i], "-")) continue;

		int idx = i+DPAD_COUNT;
		char btn_name[32];
		strcpy(btn_name, defaults ? joy_pnames[n] : joy_nnames[n]);

		char *p = strchr(btn_name, '|');
		if (p) *p = 0;

		int mapped = 1;

		if(!strcasecmp(btn_name, "A")
		|| !strcasecmp(btn_name, "Jump")
		|| is_fire(btn_name) == 1)
		{
			map[idx] = mmap[SYS_BTN_A];
			strcat(mapinfo, "\n[A]");
		}

		else if(!strcasecmp(btn_name, "B")
		|| is_fire(btn_name) == 2)
		{
			map[idx] = mmap[SYS_BTN_B];
			strcat(mapinfo, "\n[B]");
		}

		else if(!strcasecmp(btn_name, "X")
		|| !strcasecmp(btn_name, "C")
		|| is_fire(btn_name) == 3)
		{
			map[idx] = mmap[SYS_BTN_X];
			strcat(mapinfo, "\n[X]");
		}

		else if(!strcasecmp(btn_name, "Y")
		|| !strcasecmp(btn_name, "D")
		|| is_fire(btn_name) == 4)
		{
			map[idx] = mmap[SYS_BTN_Y];
			strcat(mapinfo, "\n[Y]");
		}

		// Genesis C and Z  and TG16 V and VI
		else if(!strcasecmp(btn_name, "R")
		|| !strcasecmp(btn_name, "RT")
		|| !strcasecmp(btn_name, "Coin"))
		{
			map[idx] = mmap[SYS_BTN_R];
			strcat(mapinfo, "\n[R]");
		}

		else if(!strcasecmp(btn_name, "L")
		|| !strcasecmp(btn_name, "LT"))
		{
			map[idx] = mmap[SYS_BTN_L];
			strcat(mapinfo, "\n[L]");
		}

		else if(!strcasecmp(btn_name, "Select")
		|| !strcasecmp(btn_name, "Mode")
		|| !strcasecmp(btn_name, "Game Select")
		|| !strcasecmp(btn_name, "Start 2P"))
		{
			map[idx] = mmap[SYS_BTN_SELECT];
			strcat(mapinfo, "\n[\x96]");
		}

		else if(!strcasecmp(btn_name, "Start")
		|| !strcasecmp(btn_name, "Run")
		|| !strcasecmp(btn_name, "Pause")
		|| !strcasecmp(btn_name, "Start 1P"))
		{
			map[idx] = mmap[SYS_BTN_START];
			strcat(mapinfo, "\n[\x16]");
		}

		else mapped = 0;

		if (map[idx] && mapped)
		{
			strcat(mapinfo, ": ");
			strcat(mapinfo, joy_names[i]);
		}

		n++;
	}

	if (cfg.controller_info)
	{
		Info(mapinfo, cfg.controller_info*1000);
	}
}

int map_paddle_btn()
{
	read_buttons();
	for (int i = 0, n = 0; i < joy_count; i++)
	{
		if (!strcmp(joy_names[i], "-")) continue;
		char *p = strchr(defaults ? joy_pnames[n] : joy_nnames[n], '|');
		if (p && !strcasecmp(p, "|P")) return i + DPAD_COUNT;
		n++;
	}
	return DPAD_COUNT;
}

static const char* get_std_name(uint16_t code, uint32_t *mmap)
{
	if (code == mmap[SYS_BTN_A     ]) return "[A]";
	if (code == mmap[SYS_BTN_B     ]) return "[B]";
	if (code == mmap[SYS_BTN_X     ]) return "[X]";
	if (code == mmap[SYS_BTN_Y     ]) return "[Y]";
	if (code == mmap[SYS_BTN_L     ]) return "[L]";
	if (code == mmap[SYS_BTN_R     ]) return "[R]";
	if (code == mmap[SYS_BTN_SELECT]) return "[\x96]";
	if (code == mmap[SYS_BTN_START ]) return "[\x16]";

	return "[ ]";
}

void map_joystick_show(uint32_t *map, uint32_t *mmap, int num)
{
	static char mapinfo[1024];
	read_buttons();

	sprintf(mapinfo, "P%d, map:", num);
	if(!num) sprintf(mapinfo, "Map:");

	// loop through core requested buttons and construct result map
	for (int i = 0; i < joy_count; i++)
	{
		if (!strcmp(joy_names[i], "-")) continue;

		strcat(mapinfo, "\n");
		strcat(mapinfo, get_std_name((uint16_t)(map[i + DPAD_COUNT]), mmap));
		strcat(mapinfo, ": ");
		strcat(mapinfo, joy_names[i]);
	}

	if (cfg.controller_info)
	{
		Info(mapinfo, cfg.controller_info * 1000);
	}
}
