#include "input.h"
#include "SDL.h"
#include "halleystring.h"
#include "input_joystick_sdl.h"

#ifdef _MSC_VER
#include "input_joystick_xinput.h"
#endif

using namespace Halley;

Input::Input()
{
	keyboards.push_back(spInputKeyboard(new InputKeyboard));
	mice.push_back(spInputMouse(new InputMouse));

	// XInput controllers
#ifdef XINPUT_AVAILABLE
	for (int i=0; i<4; i++) {
		auto joy = spInputJoystick(new InputJoystickXInput(i));
		joy->update();
		joysticks.push_back(joy);
	}
#endif

	// SDL joysticks
	int nJoy = SDL_NumJoysticks();
	for (int i=0; i<nJoy; i++) {
		String name = SDL_JoystickName(i);
		// Don't add if it's a 360 controller
		if (name.find("XBOX 360") == String::npos && name.find("Xbox 360") == String::npos) {
			auto joy = spInputJoystick(new InputJoystickSDL(i));
			joysticks.push_back(joy);
			sdlJoys[i] = joy;
		} else {
			std::cout << "Skipping SDL handling of controller - XInput: " << name << std::endl;
		}
	}

	int val = SDL_JoystickEventState(SDL_QUERY);
	(void) val;
	SDL_JoystickEventState(SDL_ENABLE);
}

shared_ptr<Input> Input::instance;

spInputKeyboard Input::getKeyboard(int id)
{
	if (id < 0 || id >= (int)getNumberOfKeyboards()) return spInputKeyboard();
	return instance->keyboards[id];
}

spInputJoystick Input::getJoystick(int id)
{
	if (id < 0 || id >= (int)getNumberOfJoysticks()) {
		return spInputJoystick();
	} else {
		return instance->joysticks[id];
	}
}

spInputJoystick Input::getFirstJoystick()
{
	int n = getNumberOfJoysticks();
	for (int i=0; i<n; i++) {
		auto& joy = instance->joysticks[i];
		if (joy->isEnabled()) return joy;
	}
	return spInputJoystick();
}

spInputMouse Input::getMouse(int id)
{
	if (id < 0 || id >= (int)getNumberOfMice()) return spInputMouse();
	return instance->mice[id];
}

size_t Input::getNumberOfKeyboards()
{
	return instance->keyboards.size();
}

size_t Input::getNumberOfJoysticks()
{
	return instance->joysticks.size();
}

size_t Input::getNumberOfMice()
{
	return instance->mice.size();
}

void Input::beginEvents()
{
	Input& in = *instance;

	// Keyboards
	size_t n = in.getNumberOfKeyboards();
	for (size_t i=0; i < n; i++) {
		in.keyboards[i]->clearPresses();
	}

	// Joysticks
	n = in.getNumberOfJoysticks();
	for (size_t i=0; i < n; i++) {
		auto& j = in.joysticks[i];
		j->clearPresses();
		j->update();
	}

	// Mice
	n = in.getNumberOfMice();
	for (size_t i=0; i < n; i++) {
	}
}

void Input::processEvent(SDL_Event& event)
{
	Input& in = *instance;

	switch (event.type) {
		case SDL_KEYDOWN:
		case SDL_KEYUP:
			{
				size_t n = in.getNumberOfKeyboards();
				for (size_t i=0; i < n; i++) {
					in.keyboards[i]->processEvent(event);
				}
				break;
			}

		case SDL_JOYAXISMOTION:
			processJoyEvent(event.jaxis.which, event);
			break;
		case SDL_JOYBUTTONDOWN:
		case SDL_JOYBUTTONUP:
			processJoyEvent(event.jbutton.which, event);
			break;
		case SDL_JOYHATMOTION:
			processJoyEvent(event.jhat.which, event);
			break;
		case SDL_JOYBALLMOTION:
			processJoyEvent(event.jball.which, event);
			break;

		default:
			break;
	}
}

void Input::processJoyEvent(int n, SDL_Event& event)
{
	Input& in = *instance;
	auto& joy = in.sdlJoys[n];
	if (joy) joy->processEvent(event);
}
