/*  $Id: input_device_linuxjoystick.cpp,v 1.3 2004/04/20 21:50:23 harry Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This library 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
**  Lesser General Public License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/joystick.h>
#include <iostream>
#include <errno.h>


#include "API/Core/Math/point.h"
#include "API/Core/System/clanstring.h"
#include "API/Core/System/error.h"
#include "API/Display/input_event.h"

#include "input_device_linuxjoystick.h"

CL_InputDevice_LinuxJoystick::CL_InputDevice_LinuxJoystick(const std::string& device)
{
	type = CL_InputDevice::joystick;

	fd = open(device.c_str(), O_RDONLY | O_NONBLOCK);

	if (fd == -1)
	{
		throw CL_Error(strerror(errno));
	}

	char number_of_axes;
	char number_of_buttons;

	ioctl(fd, JSIOCGBUTTONS, &number_of_buttons );
	ioctl(fd, JSIOCGAXES,    &number_of_axes );
  
	char name_cstr[256];
	if (ioctl(fd, JSIOCGNAME(sizeof(name_cstr)), name_cstr) < 0)
		strncpy(name_cstr, "Unknown", sizeof(name_cstr));

	name = name_cstr;

	axes_states.resize(number_of_axes);
	button_states.resize(number_of_buttons);
}

CL_InputDevice_LinuxJoystick::~CL_InputDevice_LinuxJoystick()
{
	close(fd);
}

void
CL_InputDevice_LinuxJoystick::process_event(struct js_event event)
{
	// We don't threat JS_EVENT_INIT special, so this should do
	if (event.type & JS_EVENT_BUTTON) 
	{
		button_states[event.number] = event.value;
		send_button_event(event);
	}
	else if (event.type & JS_EVENT_AXIS) 
	{
		axes_states[event.number] = float(event.value)/32767;
		send_axis_event(event);
	}
}

void
CL_InputDevice_LinuxJoystick::send_button_event(const struct js_event& event)
{
	CL_InputEvent e; 
			
	e.device = CL_InputDevice(this);
	e.id     = event.number;
	e.repeat_count = 0;

	if (event.value)
	{
		e.type = CL_InputEvent::pressed;
		sig_key_down(e);
	}
	else
	{
		e.type = CL_InputEvent::released;
		sig_key_up(e);
	}
}

void
CL_InputDevice_LinuxJoystick::send_axis_event(const struct js_event& event)
{
	CL_InputEvent e; 
		
	e.device   = CL_InputDevice(this);
	e.type     = CL_InputEvent::axis_moved;
	e.id       = event.number;
	e.axis_pos = float(event.value)/32767;
	e.repeat_count = 0;

	sig_axis_move(e);
}

void
CL_InputDevice_LinuxJoystick::keep_alive()
{
	struct js_event event;

	while (read(fd, &event, sizeof(struct js_event)) != -1)
	{
		process_event(event);
	}
	/* EAGAIN is returned when the queue is empty */
	if (errno != EAGAIN) {
		throw CL_Error(strerror(errno));
	}
}

std::string
CL_InputDevice_LinuxJoystick::get_key_name(int num) const
{
	return CL_String::from_int(num);
}

// Local Variables: ***
// mode: clanlib ***
// End: ***

