/* Copyright (C) 2007  Mikko Sysikaski <mikko.sysikaski@gmail.com>
 * This program is free software distributed under GNU General Public License
 * version 3 or (at your option) any later version.
 * No warranty of any kind is provided. See the accompanying file COPYING for details.
 */

#include "eventhandler.h"
#include "physics.h"
#include "renderer.h"
#include "glscreen.h"
#include "SDL.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

static const float JTURN = 1.0f/20.0f;
static const float MTURN = 2.0f;

EventHandler::EventHandler(Physics& physics, Renderer& graphics):
	m_physics(physics), m_graphics(graphics), m_joystick(0),
	m_msensitivity(1.0f), m_jsensitivity(1.0f), m_grabMouse(0)
{
	// Load joystick
	int amount = SDL_NumJoysticks();
	for(int i=0; i<amount; ++i) {
		if (!strcmp("hdaps", SDL_JoystickName(i))) {
			printf("Loading aps joystick js%i\n", i);
			m_joystick = SDL_JoystickOpen(i);
			break;
		}
	}
//	SDL_ShowCursor(SDL_DISABLE);
	if (!m_joystick) {
		fprintf(stderr, "Warning: Failed loading aps joystick!\n");
		m_grabMouse = 1;
	} else {
		int xa = SDL_JoystickGetAxis(m_joystick, 0);
		int ya = SDL_JoystickGetAxis(m_joystick, 1);
		m_physics.setAngleX(xa*JTURN);
		m_physics.setAngleY(ya*JTURN);
		SDL_JoystickEventState(SDL_ENABLE);
	}
}

inline
void EventHandler::keyDown(SDL_KeyboardEvent& e)
{
	switch(e.keysym.sym) {
		case 'a':
			m_graphics.moveCamera(0.2f);
			break;
		case 's':
			m_graphics.moveCamera(-0.2f);
			break;
		case SDLK_ESCAPE:
			m_retVal = QUIT;
			break;
		case SDLK_SPACE:
			m_retVal = MENU;
			break;
		case 'r':
			m_retVal = RESET;
		default:
			break;
	}
}
namespace {int MIDX=320, MIDY=240;}
inline
void EventHandler::resize(SDL_ResizeEvent& e)
{
	GLScreen::resize(e.w, e.h);
	MIDX=e.w/2;
	MIDY=e.h/2;
}
inline
void EventHandler::joyAxis(SDL_JoyAxisEvent& e)
{
	if (m_grabMouse)
		return;
	if (e.axis == 0)
		m_physics.setAngleX(e.value*JTURN*m_jsensitivity);
	else
		m_physics.setAngleY(e.value*JTURN*m_jsensitivity);
}
inline
void EventHandler::mouseMove(SDL_MouseMotionEvent& e)
{
	if (m_grabMouse) {
		if (e.x == MIDX && e.y == MIDY)
			return;
		m_mouseX += (e.x-MIDX)*m_msensitivity;
		m_mouseY += (e.y-MIDY)*m_msensitivity;
		m_mouseX = -m_physics.setAngleX(-m_mouseX*MTURN)/MTURN;
		m_mouseY = -m_physics.setAngleY(-m_mouseY*MTURN)/MTURN;
		SDL_WarpMouse(MIDX, MIDY);
	}
}
inline
void EventHandler::mousePress(SDL_MouseButtonEvent& e)
{
	(void)e;
	if (!m_grabMouse) {
		m_grabMouse = 1;
		m_mouseX = m_mouseY = 0;
		if (!m_joystick)
			SDL_ShowCursor(SDL_DISABLE);
		SDL_WarpMouse(MIDX, MIDY);
	} else {
		if (!m_joystick)
			SDL_ShowCursor(SDL_ENABLE);
		m_grabMouse = 0;
	}
}

inline
void EventHandler::handleEvent(SDL_Event& e)
{
//	printf("event: %i\n", e.type);
	switch(e.type) {
		case SDL_JOYAXISMOTION:
			joyAxis(e.jaxis); break;
		case SDL_MOUSEMOTION:
			mouseMove(e.motion); break;
		case SDL_MOUSEBUTTONDOWN:
			mousePress(e.button); break;
		case SDL_KEYDOWN:
			keyDown(e.key); break;
		case SDL_VIDEORESIZE:
			resize(e.resize); break;
		case SDL_QUIT:
			exit(0);
		default:
			break;
	}
}

EventHandler::State EventHandler::processEvents()
{
	MIDX = GLScreen::getResX()/2;
	MIDY = GLScreen::getResY()/2;
//	printf("reading events\n");
	m_retVal = NORMAL;
	SDL_Event e;
	while(SDL_PollEvent(&e)) {
		handleEvent(e);
	}
	return m_retVal;
}

void EventHandler::resetMouse()
{
	SDL_ShowCursor(SDL_DISABLE);
	MIDX = GLScreen::getResX()/2;
	MIDY = GLScreen::getResY()/2;
	if (m_grabMouse) {
		m_mouseX = m_mouseY = 0;
		SDL_WarpMouse(MIDX, MIDY);
		m_physics.setAngleX(0);
		m_physics.setAngleY(0);
	} else if (m_joystick) {
		int xa = SDL_JoystickGetAxis(m_joystick, 0);
		int ya = SDL_JoystickGetAxis(m_joystick, 1);
		m_physics.setAngleX(xa*JTURN);
		m_physics.setAngleY(ya*JTURN);
	}
}

void EventHandler::handleMouseMove(int x, int y)
{
	MIDX = GLScreen::getResX()/2;
	MIDY = GLScreen::getResY()/2;
	if (m_grabMouse && x != MIDX  && y != MIDY) {
		SDL_WarpMouse(MIDX, MIDY);
	}
}
