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

#import "WiiRemoteImplement.h"
#import "wiiremote_impl.h"
#import "DebugLog.h"

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

#import <unistd.h>

/************************************************************
* class declaration
************************************************************/
@interface ChannelHandler : NSObject 
{
	WiiRemoteImplement *wiiRemoteImplement;
}
- initWithWiiRemote:(WiiRemoteImplement *)aWiiRemoteImplement;
@end

@interface ControlChannelHandler : ChannelHandler <IOBluetoothL2CAPChannelDelegate>
@end

@interface InterruptChannelHandler : ChannelHandler <IOBluetoothL2CAPChannelDelegate>
@end

/************************************************************
* class implementation
************************************************************/

@implementation WiiRemoteImplement
- initWithDevice:(IOBluetoothDevice *)aDevice
{
	DebugLog("Hello\n");

	self = [super init];
	device = [aDevice retain];
	controlChannel = nil;
	interruptChannel = nil;
	controlChannelHandler = [[ControlChannelHandler alloc] initWithWiiRemote:self];
	interruptChannelHandler = [[InterruptChannelHandler alloc] initWithWiiRemote:self];
	controlChannelState = NO;
	interruptChannelState = NO;

	memset(self->outputBuffer, 0, (sizeof(outputBuffer) / sizeof(unsigned char)));
	memset(self->inputBuffer, 0, (sizeof(inputBuffer) / sizeof(unsigned char)));

	DebugLog("Bye\n");
	return self;
}
- (void)dealloc
{
	[self close];
	[device autorelease];
	[controlChannelHandler release];
	[interruptChannelHandler release];
	return [super dealloc];
}

- (void)open
{
	DebugLog("Hello\n");

	[device openConnection:self];
#if 0
	[self openInterruptChannel];
	[self openControlChannel];
#endif

	DebugLog("Bye\n");
}
- (void)close
{
	DebugLog("Hello\n");
	if (interruptChannel)
	{
		[interruptChannel closeChannel];
		[interruptChannel autorelease];
		interruptChannel = nil;
	}
	if (controlChannel)
	{
		[controlChannel closeChannel];
		[controlChannel autorelease];
		controlChannel = nil;
	}
	if ([device isConnected])
	{
		[device closeConnection];
	}
	DebugLog("Bye\n");
}
- (BOOL)isOpened
{
	BOOL result = NO;
	DebugLog("Hello\n");

	if (controlChannel != nil && controlChannelState == YES &&
		interruptChannel != nil && interruptChannelState == YES)
	{
		result = YES;
	}

	DebugLog("Bye: result == %d\n", result);
	return result;
}
- (void)openControlChannel
{
	IOReturn ioReturn;
	IOBluetoothL2CAPChannel *newChannel;
	int retry_count = 10;
	DebugLog("Hello\n");

	do
	{
		ioReturn = [device openL2CAPChannelSync:&newChannel
			withPSM:(BluetoothL2CAPPSM)WRMT_CONTROL_CHANNEL_PSM
			delegate:controlChannelHandler];
		if (ioReturn == kIOReturnSuccess) break;
		retry_count--;
		usleep(10*1000);
	}
	while (retry_count > 0);

	if (ioReturn == kIOReturnSuccess)
	{
		controlChannel = [newChannel retain];
	}

	DebugLog("Bye\n");
}
- (void)openInterruptChannel
{
	IOReturn ioReturn;
	IOBluetoothL2CAPChannel *newChannel;
	int retry_count;
	DebugLog("Hello\n");

	retry_count = 10;
	do
	{
		ioReturn = [device openL2CAPChannelSync:&newChannel
			withPSM:(BluetoothL2CAPPSM)WRMT_INTERRUPT_CHANNEL_PSM
			delegate:interruptChannelHandler];
		if (ioReturn == kIOReturnSuccess) break;
		retry_count--;
		usleep(10*1000);
	}
	while (retry_count > 0);

	if (ioReturn == kIOReturnSuccess)
	{
		interruptChannel = [newChannel retain];
	}

	DebugLog("Bye\n");
}

- (IOReturn)writeToDevice
{
	WRMT_IOReturn result = WRMT_IO_ERROR;
	IOReturn ioReturn;
	assert( (outputBuffer[1] >= WRMT_OUTPUT_REPORT_ID_FIRST) &&
		(outputBuffer[1] <= WRMT_OUTPUT_REPORT_ID_LAST) );
	DebugLog("Hello\n");

	/* check connection status*/
	if (![device isConnected] || controlChannel == nil)
	{
		WRMT_SetError("Device is not connected.");
		return WRMT_IO_ERROR;
	}

	/* send request */
	outputBuffer[0] = 0x52;
	int report_id = outputBuffer[1]; 
	UInt16 report_size = WRMT_Impl_GetOutputReportSize(report_id);
	int retry_count = 10;
	do
	{
		ioReturn = [controlChannel writeSync:outputBuffer
			length:report_size+1];
		if (ioReturn == kIOReturnSuccess) break;
		retry_count--;
		usleep(10*1000);
	}
	while (retry_count > 0);

	if (ioReturn == kIOReturnSuccess)
	{
		result = WRMT_IO_SUCCESS;
	}
	else
	{
		WRMT_SetError("Send Request Failed.");
		result = WRMT_IO_ERROR;
	}

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

- (unsigned char *)outputBuffer
{
	return outputBuffer+1;
}
- (unsigned char *)inputBuffer
{
	return inputBuffer+1;
}
- (void)setInputData:(void *)dataPointer length:(size_t)dataLength
{
	assert(dataPointer != NULL);
	assert(dataLength <= INPUT_BUFFER_SIZE);
	DebugLog("Hello\n");

	memcpy(inputBuffer, dataPointer, dataLength);

	DebugLog("Bye\n");
}
- setControlChannelState:(BOOL)newValue
{
	DebugLog("Hello: newValue == %d\n", newValue);

	controlChannelState = newValue;

	DebugLog("Bye\n");
	return self;
}
- setInterruptChannelState:(BOOL)newValue
{
	DebugLog("Hello: newValue == %d\n", newValue);

	interruptChannelState = newValue;

	DebugLog("Bye\n");
	return self;
}
/**
* callbacks
**/
- (void)connectionComplete:(IOBluetoothDevice *)aDevice
	status:(IOReturn)status
{
	DebugLog("status == 0x%x\n", status);
	[device performSDPQuery:self];
#if 0
	[self openControlChannel];
	[self openInterruptChannel];
#endif
}
- (void)sdpQueryComplete:(IOBluetoothDevice *)aDevice
	status:(IOReturn)status
{
	DebugLog("status == 0x%x\n", status);
#if 1
	[self openControlChannel];
	[self openInterruptChannel];
#endif
}
#if 0
- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
	data:(void *)dataPointer
	length:(size_t)dataLength
{
	DebugLog("Hello\n");
	if (l2capChannel == controlChannel)
	{
		DebugLog("controlChannel\n");
	}
	else if (l2capChannel == interruptChannel)
	{
		DebugLog("interruptChannel\n");
		memcpy(inputBuffer, dataPointer, dataLength);
	}
	else
	{
		DebugLog("Unknown channel\n");
	}
	DebugLog("Bye\n");
}
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel status:(IOReturn)error
{
	if (l2capChannel == controlChannel) DebugLog("controlChannel\n");
	else if (l2capChannel == interruptChannel) DebugLog("interruptChannel\n");
	else DebugLog("Unknown Channel\n");
}
- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel
{
	if (l2capChannel == controlChannel) DebugLog("controlChannel\n");
	else if (l2capChannel == interruptChannel) DebugLog("interruptChannel\n");
	else DebugLog("Unknown Channel\n");
}
- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel
{
	if (l2capChannel == controlChannel) DebugLog("controlChannel\n");
	else if (l2capChannel == interruptChannel) DebugLog("interruptChannel\n");
	else DebugLog("Unknown Channel\n");
}
- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel refcon:(void*)refcon status:(IOReturn)error
{
	if (l2capChannel == controlChannel) DebugLog("controlChannel\n");
	else if (l2capChannel == interruptChannel) DebugLog("interruptChannel\n");
	else DebugLog("Unknown Channel");
}
- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel
{
	if (l2capChannel == controlChannel) DebugLog("controlChannel\n");
	else if (l2capChannel == interruptChannel) DebugLog("interruptChannel\n");
	else DebugLog("Unknown Channel");
}
#endif
@end


@implementation ChannelHandler
- initWithWiiRemote:(WiiRemoteImplement *)aWiiRemoteImplement
{
	self = [super init];
	wiiRemoteImplement = aWiiRemoteImplement;

	return self;
}
@end


@implementation ControlChannelHandler
- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
	data:(void *)dataPointer
	length:(size_t)dataLength
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel status:(IOReturn)error
{
	DebugLog("Hello\n");

	[wiiRemoteImplement setControlChannelState:YES];

	DebugLog("Bye\n");
}
- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel
{
	DebugLog("Hello\n");

	[wiiRemoteImplement setControlChannelState:NO];

	DebugLog("Bye\n");
}
- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel refcon:(void*)refcon status:(IOReturn)error
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
@end


@implementation InterruptChannelHandler
- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
	data:(void *)dataPointer
	length:(size_t)dataLength
{
	DebugLog("Hello\n");

	[wiiRemoteImplement setInputData:dataPointer length:dataLength];

	DebugLog("Bye\n");
}
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)l2capChannel status:(IOReturn)error
{
	DebugLog("Hello\n");

	fprintf(stderr, "l2capChannelOpenComplete: %s\n", __func__);
	[wiiRemoteImplement setInterruptChannelState:YES];

	DebugLog("Bye\n");
}
- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel
{
	DebugLog("Hello\n");
	fprintf(stderr, "l2capChannel: %s\n", __func__);

	[wiiRemoteImplement setInterruptChannelState:NO];

	DebugLog("Bye\n");
}
- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel refcon:(void*)refcon status:(IOReturn)error
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel
{
	DebugLog("Hello\n");
	DebugLog("Bye\n");
}
@end

