/*
 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 "TiltAndSwipePad.h"
#import "ac_util.h"
#import "util.h"

#define SWIPES_CENTER_INTERVAL_SECONDS 0.05

@implementation TiltAndSwipePad

- (id)initWithFrame:(CGRect)frame andProcessor:(ModelProcessor*) p {
    CGRect f = frame;
    
    self = [super initWithFrame:f];
    if (self) {
        
        processor = [p retain];
        [self reloadSettingsFromProcessor];
        
        [self setBackgroundColor:[UIColor clearColor]];
        
        swipeInProgress=NO;
        
        [[UIAccelerometer sharedAccelerometer] setDelegate:self];
        [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(0.01)];
        
        swipesFloatToCenterTimer = [NSTimer scheduledTimerWithTimeInterval: SWIPES_CENTER_INTERVAL_SECONDS
                                                                    target: self
                                                                  selector: @selector(swipesFloatToCenterMaybe)
                                                                  userInfo: nil
                                                                   repeats: YES];
    }
    return self;
}


- (void)reloadSettingsFromProcessor {
    as = [processor accelerometerSensitivity];
    
    ari=[processor accelerometerRollMin];
    arc=[processor accelerometerRollCenter];
    arx=[processor accelerometerRollMax];
    
    api=[processor accelerometerPitchMin];
    apc=[processor accelerometerPitchCenter];
    apx=[processor accelerometerPitchMax];
    
    swipeXScale = [processor swipeScale];
    swipeYScale = [processor swipeScale];
    
    swipeXSpring = [processor returnSpringTension];
    swipeYSpring = [processor returnSpringTension];
}

- (void)dealloc {
    [processor release];
    
    [super dealloc];
}


// accelerometer input

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {	
    static int invert = 0;
    if (invert==0) {
        invert = device_has_audio_jack_on_bottom() ? -1 : 1;
    }
    float scale_x=asin(clip(scale3(invert*acceleration.x, ari,arc,arx, -1,0,1), -1.0, 1.0))/M_PI_2;
	[tiltXSink setValue: [tiltXSink value] * (1.0-as) + scale_x * as];
    float scale_y=asin(clip(scale3(invert*acceleration.y, api,apc,apx, -1,0,1), -1.0, 1.0))/M_PI_2;
	[tiltYSink setValue: [tiltYSink value] * (1.0-as) + scale_y * as];
    
    // it feels resource-intensive to do this 100 times per second, but seems to work OK
    static int count=0;
    if (!(++count%4)) {
        [self setNeedsDisplay];
        count=0;
    }
}


// touch input

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	swipeInProgress = YES;
}

- (void)touchesMoved:(NSSet *)touches 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 = [touches anyObject];
	UIView *container = [touch view];
	
	float offsetInContainerY = [touch locationInView: container].y;
	float previousOffsetInContainerY = [touch previousLocationInView: container].y;
	float deltaY = (previousOffsetInContainerY - offsetInContainerY) / MAX_DEFLECTION_PIXELS;
	[swipeYSink setValue: [swipeYSink value] + swipeYScale * deltaY];
	
	float offsetInContainerX = [touch locationInView: container].x;
	float previousOffsetInContainerX = [touch previousLocationInView: container].x;
	float deltaX = (previousOffsetInContainerX - offsetInContainerX) / MAX_DEFLECTION_PIXELS;
	[swipeXSink setValue: [swipeXSink value] - swipeXScale * deltaX];
    
    [self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	swipeInProgress = NO;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
	swipeInProgress = NO;
}

- (IBAction) swipePadDrag:(id) sender withEvent:(UIEvent *) event {
}

// autocentering
- (void) swipesFloatToCenterMaybe {
	//[tsvc 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];
    float delta_x = SWIPES_CENTER_INTERVAL_SECONDS*swipeXSpring;
	if(swipeXSpring && x!=xTrim) {
		if(fabs(x - xTrim) < (delta_x)) {
			[swipeXSink setValue: xTrim];
		} else {
			[swipeXSink setValue: x - copysign(delta_x, x - xTrim)];
		}
        [self setNeedsDisplay];
	}
	float y = [swipeYSink value];
	float yTrim = 0; //[swipeYSink trim];
    float delta_y = SWIPES_CENTER_INTERVAL_SECONDS*swipeYSpring;
	if (swipeYSpring && y!=yTrim) {
		if(fabs(y - yTrim) < delta_y) {
			[swipeYSink setValue: yTrim];
		} else {
			[swipeYSink setValue: y - copysign(delta_y, y - yTrim)];
		}
        [self setNeedsDisplay];
	}
}


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

- (TrimmerView*) trimmerForQuadrant:(enum quadrant) q {
    ModelProcessorChannel* c=nil;
	switch (q) {
		case Q_TOP:
            c=tiltXSink;
			break;
		case Q_RIGHT:
            c=tiltYSink;
			break;
		case Q_BOTTOM:
            c=swipeXSink;
			break;
		case Q_LEFT:
			c=swipeYSink;
            break;
	}
    return [[[TrimmerView alloc] initWithSwipePad:self andChannel:c inQuadrant:q] autorelease];
}

@end
