//
//  FlyByTouchViewController.m
//  iPhly
//
//  Created by Ari Krupnik on 5/4/10.
//  Copyright 2010 lib.aero. All rights reserved.
//

#import <SystemConfiguration/SCNetworkReachability.h>
#import "TiltAndSwipeViewController.h"
#import "ModelConfigController.h"
#import "FlyByTouchViewController.h"
#import "DriveByTouchViewController.h"
#import "util.h"

@implementation TiltAndSwipeViewController

#define UI_REDRAW_INTERVAL_SECONDS 0.05
#define SWIPES_CENTER_INTERVAL_SECONDS 0.05

BOOL swipeInProgress = NO;  // swipers spring to center only when the user lifts his finger off the pad

NSTimer *swipesFloatToCenterTimer;

@synthesize configureBarButton;
@synthesize modelNameLabel;
@synthesize swipePad;
@synthesize airplaneModeWarning;

int cellularReachability(void) {
	// This test catches only the cases when cellular reception is available
	// but WiFi is not. If WiFi is available, kSCNetworkReachabilityFlagsIsWWAN
	// is false regardless of cellular connectivity
	SCNetworkReachabilityRef target = SCNetworkReachabilityCreateWithName (NULL, "google.com");
	SCNetworkReachabilityFlags flags;
	SCNetworkReachabilityGetFlags (target, &flags);
	CFRelease (target);
	return flags & kSCNetworkReachabilityFlagsIsWWAN;
}

- (TiltAndSwipeViewController *) initWithProcessor:(ModelProcessor *)p {
	if (!self) {
		return self;
	}
	
	[self release];
	self = [p isCar] ? [DriveByTouchViewController alloc] : [FlyByTouchViewController alloc];
	
	if (self = [super initWithNibName:@"TiltAndSwipeViewController" bundle:nil]) {
		processor = p;
		[processor retain];
		
		swipeXSpring = 0.015;
		swipeYSpring = 0.015;
	}
	return self;
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
	[super viewDidLoad];
	[modelNameLabel setText: [processor name]];

	// I set bacground color in IB to see where the (otherwise transparent) button is.
	[swipePad setBackgroundColor: nil];
	
	// icon from phodder.com/blog/
	[[self navigationItem] setRightBarButtonItem: configureBarButton];
	
	
	swipesFloatToCenterTimer = [NSTimer scheduledTimerWithTimeInterval: SWIPES_CENTER_INTERVAL_SECONDS
																target: self
															  selector: @selector(swipesFloatToCenterMaybe:)
															  userInfo: nil
															   repeats: YES];
	
	[self setupOnLoad];
}

- (void) setupOnLoad {
}

- (void) viewDidAppear: (BOOL) animated {
	[super viewDidAppear:animated];
	[[UIAccelerometer sharedAccelerometer] setDelegate:self];
	[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(0.01)];
	
	[modelNameLabel setText: [processor name]];
	[[self airplaneModeWarning] setHidden: !cellularReachability()];
	
	swipeInProgress = NO;
	[[UIApplication sharedApplication] setIdleTimerDisabled: YES];
}

- (void) viewDidDisappear: (BOOL) animated {
	if (![[self.navigationController viewControllers] containsObject:self]) {
		[swipesFloatToCenterTimer invalidate];
		[[UIAccelerometer sharedAccelerometer] setDelegate:nil];
	}
	[[UIApplication sharedApplication] setIdleTimerDisabled: NO];
	[super viewDidDisappear:animated];
}

- (void)dealloc {
	for(UIView * v in [swipePad subviews]) {
		[v removeFromSuperview];
	}
	
	[swipePad release];
	[modelNameLabel release];
	[configureBarButton release];
	[airplaneModeWarning release];
	
	[processor release];
    [super dealloc];
}


// accelerometer input
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {	
	float as = [processor accelerometerSensitivity];
	[tiltXSink setValue: [tiltXSink value] * (1.0-as) + asin(clip(acceleration.x, -1.0, 1.0))/M_PI_2 * as];
	[tiltYSink setValue: [tiltYSink value] * (1.0-as) + asin(clip(acceleration.y, -1.0, 1.0))/M_PI_2 * as];
}

// touch screen input
- (IBAction) swipePadTouchDown {
	swipeInProgress = YES;
}
- (IBAction) swipePadDrag:(id) sender withEvent:(UIEvent *) event {
	// I expect that it's already YES on account of a TouchDown before the
	// Drag, but set it just in case
	swipeInProgress = YES;
	
	UITouch *touch = [[event allTouches] anyObject];
	UIView *container = [touch view];
	
	float containerHeight = container.bounds.size.height;
	float offsetInContainerY = [touch locationInView: container].y;
	float previousOffsetInContainerY = [touch previousLocationInView: container].y;
	float deltaY = (previousOffsetInContainerY - offsetInContainerY) / containerHeight;
	//[self setThrottle: [[processor throttle] value] + 1.2 * deltaY];
	[swipeYSink setValue: [swipeYSink value] + 1.2 * deltaY];
	
	float containerWidth = container.bounds.size.width;
	float offsetInContainerX = [touch locationInView: container].x;
	float previousOffsetInContainerX = [touch previousLocationInView: container].x;
	float deltaX = (previousOffsetInContainerX - offsetInContainerX) / containerWidth;
	//[self setRudder: [[processor rudder] value] - 1.5 * deltaX];
	[swipeXSink setValue: [swipeXSink value] - 1.5 * deltaX];
}
- (IBAction) swipePadTouchUp {
	swipeInProgress = NO;
}

// autocentering
- (void) swipesFloatToCenterMaybe: (NSTimer *) timer {
	[self doDisplayThing];  // move to drawRect?
	if (swipeInProgress) {
		// swipes float toward center only when user is not dragging finger across them
		return;
	}
	float x = [swipeXSink value];
	float xTrim = 0; //[swipeXSink trim];
	if(x!=xTrim) {
		if(fabs(x - xTrim) < swipeXSpring) {
			[swipeXSink setValue: xTrim];
		} else {
			[swipeXSink setValue: x - copysign(swipeXSpring, x - xTrim)];
		}
	}
	float y = [swipeYSink value];
	float yTrim = 0; //[swipeYSink trim];
	if (y!=yTrim) {
		if(fabs(y - yTrim) < swipeYSpring) {
			[swipeYSink setValue: yTrim];
		} else {
			[swipeYSink setValue: y - copysign(swipeYSpring, y - yTrim)];
		}
	}	
}

// visual feedback
- (void) doDisplayThing {
	// override in subclass
}

// drill down
- (IBAction) showConfigurationView {
	ModelConfigController *modelConfigController = [(ModelConfigController *)[ModelConfigController alloc] initWithProcessor:processor];
	[self.navigationController pushViewController:modelConfigController animated:YES];
	[modelConfigController release];	
}


@end
