#import "BluetoothController.h"
#import "AppDelegate.h"
#import "Tune.h"

@implementation BluetoothController

@synthesize gameState, peerStatus, session, peerId, connectionAlert;

-(void)viewDidLoad {
  [super viewDidLoad];
	
//	peerStatus = kServer;
	session = nil;
	peerId = nil;
		
//	NSString *uid = [[UIDevice currentDevice] uniqueIdentifier];
//  gameUniqueID = [uid hash];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
  return YES;
}

- (void)didReceiveMemoryWarning
{
	[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview.
	// Release anything that's not essential, such as cached data.
}

//
// various states the game can get into
//
typedef enum {
	kStateStartGame,
	kStatePicker,
	kStateMultiplayer,
	kStateMultiplayerCointoss,
	kStateMultiplayerReconnect
} gameStates;

typedef enum {
	kServer,
	kClient
} gameNetwork;

#define kTunebookSessionID @"tunebook"

#define kMaxTankPacketSize 1024

- (void)viewDidUnload {
}

- (void)dealloc { 
	if(self.connectionAlert.visible) {
		[self.connectionAlert dismissWithClickedButtonIndex:-1 animated:NO];
	}
	self.connectionAlert = nil;
	
	[self invalidateSession:self.session];
	self.session = nil;
	self.peerId = nil;
	
	[super dealloc];
}

#pragma mark -
#pragma mark Peer Picker Related Methods

-(void)startPicker {
	GKPeerPickerController*		picker;
	
//	self.gameState = kStatePicker;			// we're going to do Multiplayer!
	
	picker = [[GKPeerPickerController alloc] init]; // note: picker is released in various picker delegate methods when picker use is done.
	picker.delegate = self;
	[picker show]; // show the Peer Picker
}

#pragma mark GKPeerPickerControllerDelegate Methods

- (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker { 
	picker.delegate = nil;
  [picker autorelease]; 
	
	if ( self.session != nil )	{
		[self invalidateSession:self.session];
		self.session = nil;
	}
	
	self.gameState = kStateStartGame;
} 

/*
 *	Note: No need to implement -peerPickerController:didSelectConnectionType: delegate method since this app does not support multiple connection types.
 *		- see reference documentation for this delegate method and the GKPeerPickerController's connectionTypesMask property.
 */

- (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type { 
	GKSession *s = [[GKSession alloc] initWithSessionID:kTunebookSessionID displayName:@"FIXME-displayName" sessionMode:GKSessionModePeer]; 
	return [s autorelease];
}

- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)s { 
	self.peerId = peerID;
	self.session = s;
	self.session.delegate = self; 
	[self.session setDataReceiveHandler:self withContext:NULL];
	
	[picker dismiss];
	picker.delegate = nil;
	[picker autorelease];
	
	self.gameState = kStateMultiplayerCointoss;
} 

#pragma mark -
#pragma mark Session Related Methods

//
// invalidate session
//
- (void)invalidateSession:(GKSession *)s {
	if ( s != nil ) {
		[s disconnectFromAllPeers]; 
		s.available = NO; 
		[s setDataReceiveHandler: nil withContext: NULL]; 
		s.delegate = nil; 
	}
}

#pragma mark Data Send/Receive Methods

- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context { 
//	static int lastPacketTime = -1;
//	unsigned char *incomingPacket = (unsigned char *)[data bytes];
//	int *pIntData = (int *)&incomingPacket[0];
//	//
//	// developer  check the network time and make sure packers are in order
//	//
//	int packetTime = pIntData[0];
//	int packetID = pIntData[1];
//	if(packetTime < lastPacketTime && packetID != NETWORK_COINTOSS) {
//		return;	
//	}
//	
//	lastPacketTime = packetTime;
//	switch( packetID ) {
//		case NETWORK_COINTOSS:
//			{
//				// coin toss to determine roles of the two players
//				int coinToss = pIntData[2];
//				// if other player's coin is higher than ours then that player is the server
//				if(coinToss > gameUniqueID) {
//					self.peerStatus = kClient;
//				}
//			}
//			break;
//		case NETWORK_HEARTBEAT:
//			{
//				// Received heartbeat data with other player's position, destination, and firing status.
//				
//				// update the other player's info from the heartbeat
//				tankInfo *ts = (tankInfo *)&incomingPacket[8];		// tank data as seen on other client
//				int peer = (self.peerStatus == kServer) ? kClient : kServer;
//				tankInfo *ds = &tankStats[peer];					// same tank, as we see it on this client
//				memcpy( ds, ts, sizeof(tankInfo) );
//				
//				// update heartbeat timestamp
//				self.lastHeartbeatDate = [NSDate date];
//				
//				// if we were trying to reconnect, set the state back to multiplayer as the peer is back
//				if(self.gameState == kStateMultiplayerReconnect) {
//					if(self.connectionAlert && self.connectionAlert.visible) {
//						[self.connectionAlert dismissWithClickedButtonIndex:-1 animated:YES];
//					}
//					self.gameState = kStateMultiplayer;
//				}
//			}
//			break;
//		default:
//			// error
//			break;
//	}
}

- (void)sendNetworkPacket:(GKSession *)session packetID:(int)packetID withData:(void *)data ofLength:(int)length reliable:(BOOL)howtosend {
	// the packet we'll send is resued
//	static unsigned char networkPacket[kMaxTankPacketSize];
//	const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our header
//	
//	if(length < (kMaxTankPacketSize - packetHeaderSize)) { // our networkPacket buffer size minus the size of the header info
//		int *pIntData = (int *)&networkPacket[0];
//		// header info
//		pIntData[0] = gamePacketNumber++;
//		pIntData[1] = packetID;
//		// copy data in after the header
//		memcpy( &networkPacket[packetHeaderSize], data, length ); 
//		
//		NSData *packet = [NSData dataWithBytes: networkPacket length: (length+8)];
//		if(howtosend == YES) { 
//			[session sendData:packet toPeers:[NSArray arrayWithObject:peerId] withDataMode:GKSendDataReliable error:nil];
//		} else {
//			[session sendData:packet toPeers:[NSArray arrayWithObject:peerId] withDataMode:GKSendDataUnreliable error:nil];
//		}
//	}
}

#pragma mark GKSessionDelegate Methods

- (void)session:(GKSession *)s peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state { 
	if ( self.gameState == kStatePicker ) {
		return;
	}
	
	if ( state == GKPeerStateDisconnected ) {		
		NSString *message = [NSString stringWithFormat:@"Could not reconnect with %@.", [s displayNameForPeer:peerID]];
		if((self.gameState == kStateMultiplayerReconnect) && self.connectionAlert && self.connectionAlert.visible) {
			self.connectionAlert.message = message;
		} else {
			UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Lost Connection" message:message delegate:self cancelButtonTitle:@"End Game" otherButtonTitles:nil];
			self.connectionAlert = alert;
			[alert show];
			[alert release];
		}
		
		self.gameState = kStateStartGame; 
	} 
} 

#pragma mark -
#pragma mark Event Handling Methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self startPicker];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}

#pragma mark -
#pragma mark UIAlertViewDelegate Methods

// Called when an alert button is tapped.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
	// 0 index is "End Game" button
	if(buttonIndex == 0) {
		self.gameState = kStateStartGame; 
	}
}

@end
