/*
iPhly: Radio Control on the iPhone

Copyright (C) 2010-2011 Ari Krupnik & Associates

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License V2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

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

NSString* CONFIGURE_MODEL = @"Configure this Model ⇒";
NSString* CHOOSE_MODEL = @"⇐ Choose Another Model";
NSString* WATCH_VIDEO = @"Watch iPhly Video";
NSString* ORDER_HARDWARE = @"Order iPhly Hardware";
NSString* ABOUT = @"About iPhly";

@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;
@synthesize configureSlider;
@synthesize configureSliderLabel;


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 retain];
		[processor startTransmission];
		
		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];
	[self setTitle:[self gerund]];
	
	[modelNameLabel setText:[NSString stringWithFormat:@"Now %@: %@", [self gerund], [processor name]]];

	// I set bacground color in IB to see where the (otherwise transparent) button is.
	[swipePad setBackgroundColor: nil];
	
	[[self navigationItem] setRightBarButtonItem: configureBarButton];
	
	UIImageView *sliderFrame = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"configure-slider-frame.png"]];
	[sliderFrame setFrame: CGRectMake(0,
									  [[self view] frame].size.height-[sliderFrame frame].size.height,
									  [sliderFrame frame].size.width,
									  [sliderFrame frame].size.height)];
	[[self view] addSubview:sliderFrame];
	[sliderFrame release];
	
	
	CGRect f = [sliderFrame frame];
	int verticalOffset = 2;
	f.origin.y+=verticalOffset;
	int sliderFrameHPadding = 9;
	f.origin.x+=sliderFrameHPadding;
	f.size.width-=2*sliderFrameHPadding;
	
	configureSlider = [[UISlider alloc] initWithFrame:f];
	[configureSlider setThumbImage:[UIImage imageNamed:@"configure-slider-thumb.png"] forState:UIControlStateNormal];
    [configureSlider setMaximumTrackImage:[UIImage imageNamed:@"empty.png"] forState:UIControlStateNormal];
    [configureSlider setMinimumTrackImage:[UIImage imageNamed:@"empty.png"] forState:UIControlStateNormal];
	[configureSlider addTarget:self action:@selector(sliderTouchUp) forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside];
	[configureSlider addTarget:self action:@selector(sliderValueChange) forControlEvents:UIControlEventValueChanged];
	[[self view] addSubview:configureSlider];
	[configureSlider release];
	
	configureSliderLabel = [[UILabel alloc] initWithFrame:f];
	[configureSliderLabel setTextAlignment:UITextAlignmentRight];
	[configureSliderLabel setTextColor:[UIColor darkGrayColor]];
	[configureSliderLabel setFont:[[configureSliderLabel font] fontWithSize:18]];
	[configureSliderLabel setBackgroundColor:[UIColor clearColor]];
	[configureSliderLabel setText:@"Slide to Configure   "];
	[[self view] addSubview:configureSliderLabel];
	[configureSliderLabel release];
	
	swipesFloatToCenterTimer = [NSTimer scheduledTimerWithTimeInterval: SWIPES_CENTER_INTERVAL_SECONDS
																target: self
															  selector: @selector(swipesFloatToCenterMaybe:)
															  userInfo: nil
															   repeats: YES];
	
	[self setupOnLoad];
}

- (void) setupOnLoad {
}

- (void) viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];
	[[self navigationController] setNavigationBarHidden:YES];
}

- (void) viewDidAppear: (BOOL) animated {
	[super viewDidAppear:animated];
	[[UIAccelerometer sharedAccelerometer] setDelegate:self];
	[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(0.01)];
	
	[[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
}

- (NSString *) gerund {
	// override in subclass
	return nil;
}

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

- (IBAction) showConfigurationAS {
	[[[[UIActionSheet alloc] initWithTitle:nil
								  delegate:self
						 cancelButtonTitle:[NSString stringWithFormat:@"Back to %@", [self gerund]]
					destructiveButtonTitle:nil
						 otherButtonTitles:CONFIGURE_MODEL,
	                                       CHOOSE_MODEL,
                                           WATCH_VIDEO,
                                           ORDER_HARDWARE,
										   ABOUT, nil]
	  autorelease] showInView:[self view]];
}

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
	if ([actionSheet buttonTitleAtIndex:buttonIndex]==CONFIGURE_MODEL) {
		[[self navigationController] setNavigationBarHidden:NO];
		[self showConfigurationView];
	} else if ([actionSheet buttonTitleAtIndex:buttonIndex]==CHOOSE_MODEL) {
		[[self navigationController] setNavigationBarHidden:NO];
		[[self navigationController] popViewControllerAnimated:YES];
	} else if ([actionSheet buttonTitleAtIndex:buttonIndex]==WATCH_VIDEO) {
		NSURL *URL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"iPhly-intro" ofType:@"m4v"]];
        MPMoviePlayerController* mpc = [[MPMoviePlayerController alloc] initWithContentURL: URL];
        [[NSNotificationCenter defaultCenter] addObserver: self
                                                 selector: @selector(mpcFinish:)         
                                                     name: MPMoviePlayerPlaybackDidFinishNotification         
                                                   object: mpc];
		[processor stopTransmission];
        [mpc play];
	} else if ([actionSheet buttonTitleAtIndex:buttonIndex]==ORDER_HARDWARE) {
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString: @"http://www.iphly.org/ks"]];
	} else if ([actionSheet buttonTitleAtIndex:buttonIndex]==ABOUT) {
		[[self navigationController] setNavigationBarHidden:NO];
		NSURL *URL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"about-iphly" ofType:@"html"]];
		[[self navigationController] pushViewController:[[[WebViewController alloc]initWithAddress:URL andTitle:@"About iPhly"] autorelease] animated:YES];
	}
}

- (void) mpcFinish: (NSNotification*) n {
    MPMoviePlayerController* mpc = [n object];
    [[NSNotificationCenter defaultCenter] removeObserver: self
                                                    name: MPMoviePlayerPlaybackDidFinishNotification
                                                  object: mpc];
    [mpc release];
    [processor startTransmission];
}

- (void) sliderTouchUp {
	UISlider *s = configureSlider;
	if ([s value] == [s maximumValue]) {
		[self showConfigurationAS];
	}
	[s setValue:[s minimumValue]];
}

- (void) sliderValueChange {
	[configureSliderLabel setAlpha:1-3*[configureSlider value]];
}


@end
