/************************************************************
* Copyright (C) 2006-2008 Masahiko SAWAI All Rights Reserved. 
************************************************************/

#include "wiiremote.h"
#include "wiiremote_impl.h"
#include "DebugLog.h"

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

#define DEFAULT_SPEAKER_VOLUME 0x40 /* 0 - 0xff */
#define DEFAULT_SPEAKER_SAMPLE_RATE SPEAKER_SAMPLE_RATE_3920


/**
* speaker sample rate id
* 11 (0x0B) = 4200 Hz
* 12 (0x0C) = 3920 Hz
* 13 (0x0D) = 3640 Hz
* 14 (0x0E) = 3360 Hz
* 15 (0x0F) = 3080 Hz 
**/
#define SPEAKER_SAMPLE_RATE_4200 0x0B
#define SPEAKER_SAMPLE_RATE_3920 0x0C
#define SPEAKER_SAMPLE_RATE_3640 0x0D
#define SPEAKER_SAMPLE_RATE_3360 0x0E
#define SPEAKER_SAMPLE_RATE_3080 0x0F


/* type definitions */
struct wrmt_wiiremote
{
	WRMT_WiiRemoteImpl *impl;
	int device_index;
	/* buffers */
	unsigned char *output_buffer;
	unsigned char *input_buffer;
	/* device mode */
	int function_flag[WRMT_NUMBER_OF_FUNCTIONS];
	/* device state */
	int device_state[WRMT_NUMBER_OF_DATA_TYPE];
};

#define WRMT_WiiRemote_Invaliant(self) \
{ \
	assert((self) != NULL); \
	assert((self)->impl != NULL); \
	assert(((self)->device_index >= 0) && \
		((self)->device_index < WRMT_MAX_DEVICES)); \
	assert((self)->output_buffer != NULL); \
	assert((self)->input_buffer != NULL); \
	assert( ((self)->function_flag[WRMT_FUNCTION_CONTINUOUS] == 0) || \
		((self)->function_flag[WRMT_FUNCTION_CONTINUOUS] == 1)); \
	assert( ((self)->function_flag[WRMT_FUNCTION_MOTION] == 0) || \
		((self)->function_flag[WRMT_FUNCTION_MOTION] == 1)); \
	assert( ((self)->function_flag[WRMT_FUNCTION_IR] == 0) || \
		((self)->function_flag[WRMT_FUNCTION_IR] == 1)); \
	assert( ((self)->function_flag[WRMT_FUNCTION_SPEAKER] == 0) || \
		((self)->function_flag[WRMT_FUNCTION_SPEAKER] == 1)); \
} 

#define WRMT_WiiRemote_ValidateOutputReport(self) \
{ \
	assert( ((self)->output_buffer[0] >= WRMT_OUTPUT_REPORT_ID_FIRST) && \
		((self)->output_buffer[0] <= WRMT_OUTPUT_REPORT_ID_LAST)); \
} 


/************************************************************
#private variables
************************************************************/
static
const
unsigned char
IR_SENSITIVITY_MIDRANGE_DATA_1[] = 
	{0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64};

static
const
unsigned char
IR_SENSITIVITY_MIDRANGE_DATA_2[] =
	{0x63, 0x03};

static
WRMT_WiiRemote
wiiRemoteList[WRMT_MAX_DEVICES];

static
const 
char *errorMessage = NULL;


/************************************************************
#private functions
************************************************************/

static
void
WRMT_WiiRemote_InitWithDeviceIndex(WRMT_WiiRemote *self,
	int device_index)
{
	int i;
	WRMT_WiiRemoteImpl *wiiRemoteImpl;
	assert(self != NULL);
	assert(device_index >= 0 && device_index <= WRMT_MAX_DEVICES);
	DebugLog("Hello\n");

	wiiRemoteImpl = WRMT_Impl_GetWiiRemoteAt(device_index);
	self->impl = wiiRemoteImpl;
	self->device_index = device_index;
	self->output_buffer = WRMT_WiiRemoteImpl_GetOutputBuffer(wiiRemoteImpl);
	self->input_buffer = WRMT_WiiRemoteImpl_GetInputBuffer(wiiRemoteImpl);

	for (i = 0;i < WRMT_NUMBER_OF_FUNCTIONS;i++)
	{
		self->function_flag[i] = 0;
	}
	for (i = 0;i < WRMT_NUMBER_OF_DATA_TYPE;i++)
	{
		self->device_state[i] = 0;
	}
	self->device_state[WRMT_DATA_SPEAKER_VOLUME] = DEFAULT_SPEAKER_VOLUME;
	self->device_state[WRMT_DATA_SPEAKER_SAMPLE_RATE] = DEFAULT_SPEAKER_SAMPLE_RATE;

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
void
WRMT_WiiRemote_ParseBatteryLevel(WRMT_WiiRemote *self)
{
	assert(self->input_buffer[0] == 0x20);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	self->device_state[WRMT_DATA_BATTERY_LEVEL] = self->input_buffer[6];

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
void
WRMT_WiiRemote_ParseButtonState(WRMT_WiiRemote *self)
{
	int button_state;
	assert(self->input_buffer[0] >= 0x30 && self->input_buffer[0] <= 0x3f);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	button_state = (self->input_buffer[1] << 8) & 0xff00;
	button_state |= self->input_buffer[2] & 0x00ff;
	self->device_state[WRMT_DATA_BUTTONS] = button_state;

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
void
WRMT_WiiRemote_ParseMotionState(WRMT_WiiRemote *self)
{
	assert(self->input_buffer[0] & 0x01);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	self->device_state[WRMT_DATA_MOTION_X] = self->input_buffer[3] & 0xff;
	self->device_state[WRMT_DATA_MOTION_Y] = self->input_buffer[4] & 0xff;
	self->device_state[WRMT_DATA_MOTION_Z] = self->input_buffer[5] & 0xff;

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
void
WRMT_WiiRemote_ParseIRState(WRMT_WiiRemote *self)
{
	assert(self->input_buffer[0] & 0x02);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	if (self->input_buffer[6] == 0xff &&
		self->input_buffer[7] == 0xff &&
		self->input_buffer[8] == 0xff)
	{
		self->device_state[WRMT_DATA_IR1_FOUND] = 0;
		self->device_state[WRMT_DATA_IR1_SIZE] = 0;
		self->device_state[WRMT_DATA_IR1_X] = 0;
		self->device_state[WRMT_DATA_IR1_Y] = 0;
	}
	else
	{
		self->device_state[WRMT_DATA_IR1_FOUND] = 1;
		self->device_state[WRMT_DATA_IR1_SIZE] = self->input_buffer[ 8] & 0x0f;
		self->device_state[WRMT_DATA_IR1_X] = self->input_buffer[ 6];
		self->device_state[WRMT_DATA_IR1_Y] = self->input_buffer[ 7];
		self->device_state[WRMT_DATA_IR1_X] |= ((int)self->input_buffer[ 8] & 0x30) << 4;
		self->device_state[WRMT_DATA_IR1_Y] |= ((int)self->input_buffer[ 8] & 0xc0) << 2;
	}

	if (self->input_buffer[9] == 0xff &&
		self->input_buffer[10] == 0xff &&
		self->input_buffer[11] == 0xff)
	{
		self->device_state[WRMT_DATA_IR2_FOUND] = 0;
		self->device_state[WRMT_DATA_IR2_SIZE] = 0;
		self->device_state[WRMT_DATA_IR2_X] = 0;
		self->device_state[WRMT_DATA_IR2_Y] = 0;
	}
	else
	{
		self->device_state[WRMT_DATA_IR2_FOUND] = 1;
		self->device_state[WRMT_DATA_IR2_SIZE] = self->input_buffer[11] & 0x0f;
		self->device_state[WRMT_DATA_IR2_X] = self->input_buffer[ 9];
		self->device_state[WRMT_DATA_IR2_Y] = self->input_buffer[10];
		self->device_state[WRMT_DATA_IR2_X] |= ((int)self->input_buffer[11] & 0x30) << 4;
		self->device_state[WRMT_DATA_IR2_Y] |= ((int)self->input_buffer[11] & 0xc0) << 2;
	}

	self->device_state[WRMT_DATA_IR_FOUND] = 0;
	self->device_state[WRMT_DATA_IR_SIZE] = 0;
	self->device_state[WRMT_DATA_IR_X] = 0;
	self->device_state[WRMT_DATA_IR_Y] = 0;
	if (self->device_state[WRMT_DATA_IR1_FOUND] ||
		self->device_state[WRMT_DATA_IR2_FOUND])
	{
		int found_count = 0;

		self->device_state[WRMT_DATA_IR_FOUND] = 1;
		if (self->device_state[WRMT_DATA_IR1_FOUND])
		{
			self->device_state[WRMT_DATA_IR_SIZE] += self->device_state[WRMT_DATA_IR1_SIZE];
			self->device_state[WRMT_DATA_IR_X] += self->device_state[WRMT_DATA_IR1_X];
			self->device_state[WRMT_DATA_IR_Y] += self->device_state[WRMT_DATA_IR1_Y];
			found_count++;
		}
		if (self->device_state[WRMT_DATA_IR2_FOUND])
		{
			self->device_state[WRMT_DATA_IR_SIZE] += self->device_state[WRMT_DATA_IR2_SIZE];
			self->device_state[WRMT_DATA_IR_X] += self->device_state[WRMT_DATA_IR2_X];
			self->device_state[WRMT_DATA_IR_Y] += self->device_state[WRMT_DATA_IR2_Y];
			found_count++;
		}

		if (found_count > 0)
		{
			self->device_state[WRMT_DATA_IR_SIZE] /= found_count;
			self->device_state[WRMT_DATA_IR_X] /= found_count;
			self->device_state[WRMT_DATA_IR_Y] /= found_count;
		}
	}

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
void
WRMT_WiiRemote_ParseReport(WRMT_WiiRemote *self)
{
	unsigned char report_id;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

#ifdef DUMP_INPUT_BUFFER
	{
		int i;
		for (i = 0;i < WRMT_BUFFER_SIZE;i++)
			fprintf(stderr, "%02x ", self->input_buffer[i]);
		fprintf(stderr, "\n");
	}
#endif

	report_id = self->input_buffer[0];
	DebugLog("report_id : 0x%02x\n", report_id);
	if ((report_id & 0xf0) == 0x30)
	{
		WRMT_WiiRemote_ParseButtonState(self);
		if (report_id & 0x01)
		{
			WRMT_WiiRemote_ParseMotionState(self);
		}

		if ((report_id & 0x02) &&
			self->function_flag[WRMT_FUNCTION_IR])
		{
			WRMT_WiiRemote_ParseIRState(self);
		}
	}
	else if (report_id == 0x20)
	{ /* Expansion port and controler battery status */
		WRMT_WiiRemote_ParseBatteryLevel(self);
	}

	/* clear report ID */
	self->input_buffer[0] = 0;

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
void
WRMT_WiiRemote_ClearOutputBuffer(WRMT_WiiRemote *self)
{
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	memset(self->output_buffer, 0, WRMT_BUFFER_SIZE);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

static
WRMT_IOReturn
WRMT_WiiRemote_OutputToDevice(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	WRMT_WiiRemote_Invaliant(self);
	WRMT_WiiRemote_ValidateOutputReport(self);
	DebugLog("Hello\n");

	result = WRMT_WiiRemoteImpl_OutputToDevice(self->impl);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

static
WRMT_IOReturn
WRMT_WiiRemote_SendControllerStatusRequest(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_CONTROLLER_STATUS;
	self->output_buffer[1] = 0x00;
	result = WRMT_WiiRemote_OutputToDevice(self);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

/**
* update report type. This function refer following attributes.
* - self->function_flag[WRMT_FUNCTION_CONTINUOUS]
* - self->function_flag[WRMT_FUNCTION_MOTION]
* - self->function_flag[WRMT_FUNCTION_IR]
* - self->device_state[WRMT_DATA_FORCE_FEEDBACK]
**/
static
WRMT_IOReturn
WRMT_WiiRemote_SendReportTypeRequest(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	int channel, continuous, force_feedback;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	continuous = 0x00;
	if (self->function_flag[WRMT_FUNCTION_CONTINUOUS] ||
		self->function_flag[WRMT_FUNCTION_IR])
	{
		continuous = 0x04;
	}
	force_feedback = self->device_state[WRMT_DATA_FORCE_FEEDBACK];

	channel = 0x30;
	if (self->function_flag[WRMT_FUNCTION_MOTION])
		channel |= 0x01;
	if (self->function_flag[WRMT_FUNCTION_IR])
		channel |= 0x03;

	DebugLog("channel : 0x%02x\n", channel);
	WRMT_WiiRemote_ClearOutputBuffer(self);
	self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_REQUEST_REPORT_TYPE;
	self->output_buffer[1] = continuous | force_feedback;
	self->output_buffer[2] = channel;
	result = WRMT_WiiRemote_OutputToDevice(self);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}


/**
* update report type. This function refer following attributes.
* - self->device_state[WRMT_DATA_FORCE_FEEDBACK]
* - self->device_state[WRMT_DATA_LEDS]
**/
static
WRMT_IOReturn
WRMT_WiiRemote_SendDeviceState(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	WRMT_WiiRemote_Invaliant(self);

	WRMT_WiiRemote_ClearOutputBuffer(self);
	self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_LED_AND_FORCE_FEEDBACK;
	self->output_buffer[1] = 0;
	self->output_buffer[1] |= self->device_state[WRMT_DATA_FORCE_FEEDBACK];
	self->output_buffer[1] |= (self->device_state[WRMT_DATA_LEDS] << 4);
	result = WRMT_WiiRemote_OutputToDevice(self);

	WRMT_WiiRemote_Invaliant(self);
	return result;
}

/**
* Update IR Parameters. This function refer following attributes.
* - self->function_flag[WRMT_FUNCTION_IR]
* - self->device_state[WRMT_DATA_FORCE_FEEDBACK]
**/
static
WRMT_IOReturn
WRMT_WiiRemote_SendIRParameters(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	int ir_flag, force_feedback_flag;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	ir_flag = (self->function_flag[WRMT_FUNCTION_IR] == 0) ? 0x00 : 0x04;
	force_feedback_flag = self->device_state[WRMT_DATA_FORCE_FEEDBACK];

	/* IR Sensor Enable */
	WRMT_WiiRemote_ClearOutputBuffer(self);
	self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_IR_SENSOR_ENABLE;
	self->output_buffer[1] = ir_flag | force_feedback_flag;
	result = WRMT_WiiRemote_OutputToDevice(self);
	if (result != WRMT_IO_SUCCESS) return result;
	WRMT_Impl_Sleep(10); /* ?? */

	/* IR Sensor Enable 2 */
	WRMT_WiiRemote_ClearOutputBuffer(self);
	self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_IR_SENSOR_ENABLE2;
	self->output_buffer[1] = ir_flag | force_feedback_flag;
	result = WRMT_WiiRemote_OutputToDevice(self);
	if (result != WRMT_IO_SUCCESS) return result;
	WRMT_Impl_Sleep(10); /* ?? */

	if (self->function_flag[WRMT_FUNCTION_IR])
	{
		unsigned char disable_ir = 0x01, enable_ir = 0x08;
		unsigned char ir_mode = 0x33;

		/* stop ir camera */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04b00030, &disable_ir, 1);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10); /* ?? */

		/* set ir sensitivity */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04b00000, IR_SENSITIVITY_MIDRANGE_DATA_1, 9);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10); /* ?? */

		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04b0001a, IR_SENSITIVITY_MIDRANGE_DATA_2, 2);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10); /* ?? */

		/* set ir mode */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04b00033, &ir_mode, 1);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10); /* ?? */

		/* start ir camera */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04b00030, &enable_ir, 1);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10); /* ?? */
	}

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

/**
* Update IR Parameters. This function refer following attributes.
* - self->function_flag[WRMT_FUNCTION_SPEAKER]
* - self->device_state[WRMT_DATA_SPEAKER_VOLUME]
**/
static
WRMT_IOReturn
WRMT_WiiRemote_SendSpeakerParameters(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	/* enable/disable speaker */
	WRMT_WiiRemote_ClearOutputBuffer(self);
	self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_SPEAKER_ENABLE;
	self->output_buffer[1] = self->function_flag[WRMT_FUNCTION_SPEAKER] ? 0x04 : 0x00;
	result = WRMT_WiiRemote_OutputToDevice(self);
	if (result != WRMT_IO_SUCCESS) return result;
	WRMT_Impl_Sleep(10);

	if (self->function_flag[WRMT_FUNCTION_SPEAKER])
	{
		const unsigned char data1 = 0x01, data8 = 0x08;
		unsigned char speaker_config[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

		/* mute speaker */
		WRMT_WiiRemote_ClearOutputBuffer(self);
		self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_SPEAKER_MUTE;
		self->output_buffer[1] = 0x04;
		result = WRMT_WiiRemote_OutputToDevice(self);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10);

		/* setup speaker */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04a20009, &data1, 1);
		if (result != WRMT_IO_SUCCESS) return result;
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04a20001, &data8, 1);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10);

		/* format (??) */
		speaker_config[1] = 0x00;

		/* sample rate */
		speaker_config[3] = self->device_state[WRMT_DATA_SPEAKER_SAMPLE_RATE] & 0xff;

		/* volume (0-255) */
		speaker_config[4] = self->device_state[WRMT_DATA_SPEAKER_VOLUME] & 0xff;

		/* write speaker_config */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04a20001 , speaker_config, 7);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10);

		/* setup speaker */
		result = WRMT_WiiRemote_WriteDataToMemory(self, 
			0x04a20008, &data1, 1);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10);

		/* unmute speaker */
		WRMT_WiiRemote_ClearOutputBuffer(self);
		self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_SPEAKER_MUTE;
		self->output_buffer[1] = 0x00;
		result = WRMT_WiiRemote_OutputToDevice(self);
		if (result != WRMT_IO_SUCCESS) return result;
		WRMT_Impl_Sleep(10);
	}

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

/************************************************************
#public functions
************************************************************/

/**
* FIXME
**/
void WRMT_SetError(const char *message)
{
	errorMessage = message;
}

/**
* FIXME
**/
char *
WRMT_GetError()
{
	return (char *)errorMessage;
}

int
WRMT_Init()
{
	int result;
	DebugLog("Hello\n");

	result = WRMT_Impl_Init(3);
	if (result == 0)
	{
		int number, device_index;

		number = WRMT_Impl_GetNumWiiRemote();
		for (device_index = 0;device_index < number;device_index++)
		{
			WRMT_WiiRemote *wiiRemote = &(wiiRemoteList[device_index]);
			WRMT_WiiRemote_InitWithDeviceIndex(wiiRemote, device_index);
		}
	}

	DebugLog("Bye\n");
	assert(result == 0 || result == -1);
	return result;
}

void
WRMT_Quit()
{
	DebugLog("Hello\n");

	WRMT_Impl_Quit();

	DebugLog("Bye\n");
}

void
WRMT_Sleep(int ms)
{
	DebugLog("Hello\n");

	WRMT_Impl_Sleep(ms);

	DebugLog("Bye\n");
}

int
WRMT_Update()
{
	WRMT_IOReturn result;
	WRMT_IOReturn rc;
	DebugLog("Hello\n");

	do
	{
		rc = WRMT_Poll();
	}
	while (rc >= 0);

	result = (rc == WRMT_IO_TIMEOUT) ? WRMT_IO_SUCCESS : WRMT_IO_ERROR;
	
	DebugLog("Bye\n");
	assert(result == WRMT_IO_SUCCESS || result == WRMT_IO_ERROR);
	return result;
}

int
WRMT_Poll()
{
	int result;
	WRMT_IOReturn rc;
	WRMT_WiiRemote *wiiRemote;
	int updated_device_index;
	DebugLog("Hello\n");

	/* Polling devices*/
	rc = WRMT_Impl_Poll(&updated_device_index);

	/* Update device status*/
	if(rc == WRMT_IO_SUCCESS)
	{
		wiiRemote = &(wiiRemoteList[updated_device_index]);
		WRMT_WiiRemote_ParseReport(wiiRemote);

		result = updated_device_index;
	}
	else
	{
		result = rc;
	}

	DebugLog("Bye\n");
	assert(result == WRMT_IO_ERROR || result == WRMT_IO_TIMEOUT || result >= 0);
	return result;
}

int
WRMT_GetNumWiiRemote()
{
	return WRMT_Impl_GetNumWiiRemote();
}

WRMT_WiiRemote *
WRMT_GetWiiRemoteAt(int device_index)
{
	WRMT_WiiRemote *result = NULL;
	assert(device_index >= 0 &&
		device_index < WRMT_Impl_GetNumWiiRemote());
	DebugLog("Hello\n");

	result = &(wiiRemoteList[device_index]);

	DebugLog("Bye\n");
	assert(result != NULL);
	return result;
}

WRMT_IOReturn
WRMT_WiiRemote_Open(WRMT_WiiRemote *self)
{
	WRMT_IOReturn result;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	result = WRMT_WiiRemoteImpl_Open(self->impl);
	if (result == WRMT_IO_SUCCESS)
	{
		WRMT_WiiRemote_SendReportTypeRequest(self);
		WRMT_Sleep(10);
		WRMT_WiiRemote_SendDeviceState(self);
		WRMT_Sleep(10);
		WRMT_WiiRemote_SendControllerStatusRequest(self);
	}

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

int
WRMT_WiiRemote_IsOpened(WRMT_WiiRemote *self)
{
	int result = 0;
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	result = WRMT_WiiRemoteImpl_IsOpened(self->impl);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

void
WRMT_WiiRemote_Close(WRMT_WiiRemote *self)
{
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	WRMT_WiiRemoteImpl_Close(self->impl);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
}

int 
WRMT_WiiRemote_IsEnabled(WRMT_WiiRemote *self, WRMT_FunctionType function_type)
{
	int result;
	assert(function_type >= 0 && function_type < WRMT_NUMBER_OF_FUNCTIONS);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello function_type == %d\n", function_type);

	result = self->function_flag[function_type];

	DebugLog("Bye result == %d\n", result);
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

WRMT_IOReturn
WRMT_WiiRemote_SetEnabled(WRMT_WiiRemote *self,
	WRMT_FunctionType function_type, int value)
{
	WRMT_IOReturn result = WRMT_IO_SUCCESS;
	assert(function_type >= 0 && function_type < WRMT_NUMBER_OF_FUNCTIONS);
	assert(value == 0 || value == 1);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello: function_type == %d, value == %d\n", function_type, value);

	if (self->function_flag[function_type] != value)
	{
		self->function_flag[function_type] = value;
		result = WRMT_WiiRemote_SendReportTypeRequest(self);
		if (result != WRMT_IO_SUCCESS) return result;

		switch (function_type)
		{
		case WRMT_FUNCTION_CONTINUOUS :
			break;
		case WRMT_FUNCTION_MOTION :
			break;
		case WRMT_FUNCTION_SPEAKER :
			result = WRMT_WiiRemote_SendSpeakerParameters(self);
			break;
		case WRMT_FUNCTION_IR :
			result = WRMT_WiiRemote_SendIRParameters(self);
			break;
		default:
			break;
		}
		if (result != WRMT_IO_SUCCESS) return result;
	}
	WRMT_Impl_Sleep(10);

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	return result;
}

int
WRMT_WiiRemote_GetState(WRMT_WiiRemote *self, WRMT_DataType data_type)
{
	assert(data_type >= 0 && data_type < WRMT_NUMBER_OF_DATA_TYPE);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello\n");

	return self->device_state[data_type];
}

WRMT_IOReturn
WRMT_WiiRemote_SetState(WRMT_WiiRemote *self, WRMT_DataType data_type, int value)
{
	WRMT_IOReturn result = WRMT_IO_SUCCESS;
	assert(data_type == WRMT_DATA_FORCE_FEEDBACK ||
		data_type == WRMT_DATA_LEDS ||
		data_type == WRMT_DATA_SPEAKER_VOLUME ||
		data_type == WRMT_DATA_SPEAKER_SAMPLE_RATE);
	WRMT_WiiRemote_Invaliant(self);
	DebugLog("Hello data_type == %d, value == %d\n", data_type, value);

	if (self->device_state[data_type] != value)
	{
		self->device_state[data_type] = value;
		result = WRMT_WiiRemote_SendDeviceState(self);
	}

	DebugLog("result : %d\n", result);
	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	assert(result == WRMT_IO_SUCCESS || result == WRMT_IO_ERROR);
	return result;
}

WRMT_IOReturn
WRMT_WiiRemote_WriteDataToMemory(WRMT_WiiRemote *self,
	int address, const unsigned char* data_ptr, size_t data_size)
{
	WRMT_IOReturn result;
	WRMT_WiiRemote_Invaliant(self);
	assert(data_ptr != NULL);
	assert(data_size >=1 && data_size <= 16);
	DebugLog("Hello\n");

	if (data_size >=1 && data_size <= 16)
	{
		WRMT_WiiRemote_ClearOutputBuffer(self);
		self->output_buffer[0] = WRMT_OUTPUT_REPORT_ID_WRITE_DATA;
		self->output_buffer[1] = (address >> 24 & 0xFF);
		self->output_buffer[2] = (address >> 16 & 0xFF);
		self->output_buffer[3] = (address >> 8  & 0xFF);
		self->output_buffer[4] = (address & 0xFF);
		self->output_buffer[5] = (unsigned char)data_size;
		memcpy(self->output_buffer + 6, data_ptr, data_size);
		result = WRMT_WiiRemote_OutputToDevice(self);
	}
	else
	{
		WRMT_SetError("WRMT_WiiRemote_WriteDataToMemory() Illegal data_size.");
		result = WRMT_IO_ERROR;
	}

	DebugLog("Bye\n");
	WRMT_WiiRemote_Invaliant(self);
	assert(result == WRMT_IO_ERROR || result == WRMT_IO_SUCCESS);
	return result;
}

