/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2006 Robert Beckebans <trebor_7@users.sourceforge.net>

This file is part of XreaL source code.

XreaL source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

XreaL source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with XreaL source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
/*
** linux_joystick.c
**
** This file contains ALL Linux specific stuff having to do with the
** Joystick input.  When a port is being made the following functions
** must be implemented by the port:
**
** Authors: mkv, bk
**
*/

#ifndef __x86_64__
#include <linux/joystick.h>
#endif

#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>				// bk001204

#include "../client/client.h"
#include "linux_local.h"

/* We translate axes movement into keypresses. */
int             joy_keys[16] = {
	K_LEFTARROW, K_RIGHTARROW,
	K_UPARROW, K_DOWNARROW,
	K_JOY16, K_JOY17,
	K_JOY18, K_JOY19,
	K_JOY20, K_JOY21,
	K_JOY22, K_JOY23,

	K_JOY24, K_JOY25,
	K_JOY26, K_JOY27
};

/* Our file descriptor for the joystick device. */
static int      joy_fd = -1;


// bk001130 - from linux_glimp.c
extern cvar_t  *in_joystick;
extern cvar_t  *in_joystickDebug;
extern cvar_t  *joy_threshold;


/**********************************************/
/* Joystick routines.                         */
/**********************************************/
// bk001130 - from cvs1.17 (mkv), removed from linux_glimp.c
void IN_StartupJoystick(void)
{
#ifndef __x86_64__
	int             i = 0;

	joy_fd = -1;

	if(!in_joystick->integer)
	{
		Com_Printf("Joystick is not active.\n");
		return;
	}

	for(i = 0; i < 4; i++)
	{
		char            filename[PATH_MAX];

		snprintf(filename, PATH_MAX, "/dev/js%d", i);

		joy_fd = open(filename, O_RDONLY | O_NONBLOCK);

		if(joy_fd != -1)
		{
			struct js_event event;
			char            axes = 0;
			char            buttons = 0;
			char            name[128];
			int             n = -1;

			Com_Printf("Joystick %s found\n", filename);

			/* Get rid of initialization messages. */
			do
			{
				n = read(joy_fd, &event, sizeof(event));

				if(n == -1)
				{
					break;
				}

			} while((event.type & JS_EVENT_INIT));

			/* Get joystick statistics. */
			ioctl(joy_fd, JSIOCGAXES, &axes);
			ioctl(joy_fd, JSIOCGBUTTONS, &buttons);

			if(ioctl(joy_fd, JSIOCGNAME(sizeof(name)), name) < 0)
			{
				strncpy(name, "Unknown", sizeof(name));
			}

			Com_Printf("Name:    %s\n", name);
			Com_Printf("Axes:    %d\n", axes);
			Com_Printf("Buttons: %d\n", buttons);

			/* Our work here is done. */
			return;
		}

	}

	/* No soup for you. */
	if(joy_fd == -1)
	{
		Com_Printf("No joystick found.\n");
		return;
	}
#endif
}

void IN_JoyMove(void)
{
#ifndef __x86_64__
	/* Store instantaneous joystick state. Hack to get around
	 * event model used in Linux joystick driver.
	 */
	static int      axes_state[16];

	/* Old bits for Quake-style input compares. */
	static unsigned int old_axes = 0;

	/* Our current goodies. */
	unsigned int    axes = 0;
	int             i = 0;

	if(joy_fd == -1)
	{
		return;
	}

	/* Empty the queue, dispatching button presses immediately
	 * and updating the instantaneous state for the axes.
	 */
	do
	{
		int             n = -1;
		struct js_event event;

		n = read(joy_fd, &event, sizeof(event));

		if(n == -1)
		{
			/* No error, we're non-blocking. */
			break;
		}

		if(event.type & JS_EVENT_BUTTON)
		{
			Sys_QueEvent(0, SE_KEY, K_JOY1 + event.number, event.value, 0, NULL);
		}
		else if(event.type & JS_EVENT_AXIS)
		{

			if(event.number >= 16)
			{
				continue;
			}

			axes_state[event.number] = event.value;
		}
		else
		{
			Com_Printf("Unknown joystick event type\n");
		}

	} while(1);


	/* Translate our instantaneous state to bits. */
	for(i = 0; i < 16; i++)
	{
		float           f = ((float)axes_state[i]) / 32767.0f;

		if(f < -joy_threshold->value)
		{
			axes |= (1 << (i * 2));
		}
		else if(f > joy_threshold->value)
		{
			axes |= (1 << ((i * 2) + 1));
		}

	}

	/* Time to update axes state based on old vs. new. */
	for(i = 0; i < 16; i++)
	{

		if((axes & (1 << i)) && !(old_axes & (1 << i)))
		{
			Sys_QueEvent(0, SE_KEY, joy_keys[i], qtrue, 0, NULL);
		}

		if(!(axes & (1 << i)) && (old_axes & (1 << i)))
		{
			Sys_QueEvent(0, SE_KEY, joy_keys[i], qfalse, 0, NULL);
		}
	}

	/* Save for future generations. */
	old_axes = axes;
#endif
}
