/************************************************************
* Copyright (C) 2007 Masahiko SAWAI All Rights Reserved. 
************************************************************/

#import "wiiremote_impl.h"

#import "WiiRemoteManager.h"
#import "WiiRemoteImplement.h"
#import "DebugLog.h"

#import <stdio.h>
#import <stdlib.h>
#import <assert.h>

#import <unistd.h>

/************************************************************
#type definitions
************************************************************/

struct wrmt_wiiremote_impl
{
	WiiRemoteImplement *object;
} ;

#define WRMT_Impl_Invaliant(self) \
{ \
	assert((self) != NULL); \
	assert((self)->object != nil); \
}

/************************************************************
#private constants
************************************************************/
static const
WRMT_IOReturn
RESULT_CODE_MAPPING_TABLE[] =
{
	WRMT_IO_ERROR, 
	WRMT_IO_ERROR, /* kCFRunLoopRunFinished */
	WRMT_IO_ERROR, /* kCFRunLoopRunStopped */
	WRMT_IO_TIMEOUT, /* kCFRunLoopRunTimedOut */
	WRMT_IO_SUCCESS, /* kCFRunLoopRunHandledSource */
};

/************************************************************
#private variables
************************************************************/

static
NSAutoreleasePool *pool = nil;

static
WiiRemoteManager *manager = nil;

static
WRMT_WiiRemoteImpl wiiRemoteImplList[WRMT_MAX_DEVICES];

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

/************************************************************
#public functions
************************************************************/
int
WRMT_Impl_Init(int inquiry_length_in_sec)
{
	int result = 0;
	assert(manager == nil);
	DebugLog("Hello\n");

	pool = [[NSAutoreleasePool alloc] init];
	manager = [[WiiRemoteManager alloc] initWithInquiryLength:inquiry_length_in_sec];

	// Inquiry WiiRemote devices
	[manager startInquiry];
	do
	{
		CFStringRef modeName = kCFRunLoopDefaultMode;
		CFRunLoopRunInMode(modeName, 1.0, false);
		DebugLog("[manager status] = %d\n", [manager status]);
	}
	while([manager status] != WiiRemoteManagerStatusInquiryStoped);

	// Init wiiRemoteImplList
	int i, number;
	number = [manager numberOfWiiRemotes];
	assert(number <= WRMT_MAX_DEVICES);
	for (i = 0;i < number;i++)
	{
		wiiRemoteImplList[i].object = [manager wiiRemoteAt:i];
	}

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

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

	[manager clear];
	[manager autorelease];
	manager = nil;
	[pool release];

	DebugLog("Bye\n");
}

void
WRMT_Impl_Sleep(int ms)
{
	usleep(ms * 1000);
}

WRMT_IOReturn
WRMT_Impl_Poll(int *updated_device_index_pointer)
{
	WRMT_IOReturn result = WRMT_IO_TIMEOUT;
	SInt32 runLoopResult;
	assert(manager != nil);
	DebugLog("Hello\n");

	int number = [manager numberOfWiiRemotes];
	/* run loop */
	BOOL inputDone = NO;
	while (inputDone == NO)
	{
		CFStringRef modeName = kCFRunLoopDefaultMode;
		runLoopResult = CFRunLoopRunInMode(modeName, 0.0, true);
		if (runLoopResult == kCFRunLoopRunHandledSource)
		{
			int i;
			for (i = 0;i < number;i++)
			{
				unsigned char *inputBuffer = [wiiRemoteImplList[i].object inputBuffer];
				if (inputBuffer[0] != 0)
				{
					inputDone = YES;
					if (updated_device_index_pointer != NULL)
					{
						*updated_device_index_pointer = i;
					}
					break;
				}
			}
		}
		else
		{
			break;
		}
	}
	result = RESULT_CODE_MAPPING_TABLE[runLoopResult];

	DebugLog("Bye\n");
	assert(manager != nil);
	assert( result == WRMT_IO_ERROR ||
		result == WRMT_IO_SUCCESS ||
		result == WRMT_IO_TIMEOUT);
	return result;
	return result;
}

int
WRMT_Impl_GetNumWiiRemote()
{
	assert(manager != nil);
	return [manager numberOfWiiRemotes];
}

WRMT_WiiRemoteImpl *
WRMT_Impl_GetWiiRemoteAt(int device_index)
{
	assert(device_index >= 0 &&
		device_index < WRMT_Impl_GetNumWiiRemote());
	return &(wiiRemoteImplList[device_index]);
}

WRMT_IOReturn
WRMT_WiiRemoteImpl_Open(WRMT_WiiRemoteImpl *self)
{
	WRMT_IOReturn result = WRMT_IO_ERROR;
	WiiRemoteImplement *object;
	int i;
	WRMT_Impl_Invaliant(self);
	assert(manager != nil);
	DebugLog("Hello\n");

	object = self->object;
	[object open];
	
	// run loop 0.1 * 100 = 10 (sec)
	for (i = 0;i < 100;i++)
	{
		CFStringRef modeName = kCFRunLoopDefaultMode;
		CFRunLoopRunInMode(modeName, 0.1, false);
		if([object isOpened] == YES)
		{
			result = WRMT_IO_SUCCESS;
			break;
		}
	}

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

int
WRMT_WiiRemoteImpl_IsOpened(WRMT_WiiRemoteImpl *self)
{
	int result = 0;
	WRMT_Impl_Invaliant(self);
	assert(manager != nil);
	DebugLog("Hello\n");

	if ([self->object isOpened]) result = 1;

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

void
WRMT_WiiRemoteImpl_Close(WRMT_WiiRemoteImpl *self)
{
	WRMT_Impl_Invaliant(self);
	assert(manager != nil);
	DebugLog("Hello\n");

	[self->object close];

	DebugLog("Bye\n");
	WRMT_Impl_Invaliant(self);
	return ;
}

unsigned char *
WRMT_WiiRemoteImpl_GetOutputBuffer(WRMT_WiiRemoteImpl *self)
{
	unsigned char *result = NULL;
	WRMT_Impl_Invaliant(self);

	result = [self->object outputBuffer];

	WRMT_Impl_Invaliant(self);
	return result;
}

unsigned char *
WRMT_WiiRemoteImpl_GetInputBuffer(WRMT_WiiRemoteImpl *self)
{
	unsigned char *result = NULL;
	WRMT_Impl_Invaliant(self);

	result = [self->object inputBuffer];

	WRMT_Impl_Invaliant(self);
	return result;
}

WRMT_IOReturn
WRMT_WiiRemoteImpl_OutputToDevice(WRMT_WiiRemoteImpl *self)
{
	WRMT_IOReturn result = WRMT_IO_ERROR;
	WRMT_Impl_Invaliant(self);
	DebugLog("Hello\n");

	result = [self->object writeToDevice];

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


