//
//  RunnerViewController.m
//  iMove3Dv4
//
//  Created by Luis Ballesteros on 5/6/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import <CoreMotion/CoreMotion.h>
#import "GCDAsyncUdpSocket.h"
#import "RunnerViewController.h"
#import "iMove3DAppDelegate.h"

@interface RunnerViewController () {

    //Delegate Class (where we can obtain values from the main viewController
    iMove3DAppDelegate *_iMove3DAppDelegate;

    //State variable to know if the the user is dragging or pointing an obeject
    BOOL isDragging;
    //State variable to know if the touch pad is being used to Object Rotation (or translation)    
    BOOL isRotating;
    //State variable to know if the Gyro Mode is active
    BOOL isGyroMode;

    //Motion manager
    CMMotionManager *motionManager;
    //Timer
    NSTimer *timer;
    //sample frecuency
    float sampleFrecuency;
    //transmision Speed
    float transSpeed;
    //Sensitivity
    float sensitivity;
    
    //yaw
    float xRotValue;
    short int xRotValueInt;
    //pitch
    float yRotValue;
    short int yRotValueInt;
    //roll
    float zRotValue;
    short int zRotValueInt;
    
    //Current Delta X
    short int delta_X;
    //Current Delta Y
    short int delta_Y;
    //Current Delta Z
    short int delta_Z;

    //Accum X
    short int xTransValueInt;
    //Accum Y
    short int yTransValueInt;
    //Accum Z
    short int zTransValueInt;
    
    //Number of touches (fingers) on the screen
    NSInteger numberOfTouches;
    //Current Number of taps
    NSInteger currentNumberOfTaps;
    //Previous Number of taps
    NSInteger previousNumberOfTaps;
    //Is a long pressed on the screen?
    BOOL isLongPressed;
    //Starting Point
    CGPoint startingPoint;
    //Current Point
    CGPoint currentPoint;
    
    //Packet tag
    long tag;
    //UDP Async Socket
    GCDAsyncUdpSocket *udpSocket;
    //Host
    NSString *host;
    //Port
    int port;
    //Data to send
    NSData *data;
    //UDP Packet size
    int size;


    //Buttons
    Byte buttons;
    
    
}

@end


@implementation RunnerViewController
@synthesize xRotValueLabel;
@synthesize yRotValueLabel;
@synthesize zRotValueLabel;
@synthesize xTransValueLabel;
@synthesize yTransValueLabel;
@synthesize zTransValueLabel;
//@synthesize _iMove3DAppDelegate;



- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view.
    [self setupDelegate];
    [self setupTouch];
    [self setupGyro];
    [self setupSocket];
    [self setupButtons];
    [self runDevice];
}

-(void) setupDelegate{
    _iMove3DAppDelegate = (iMove3DAppDelegate *)[[UIApplication sharedApplication] delegate];
    _iMove3DAppDelegate.rvc = self;
    NSLog(@"Delegate Ready");
}

-(void) setupTouch{
    delta_X = 0;
    delta_Y = 0;
    delta_Z = 0;
    
    xTransValueInt=0;
    yTransValueInt=0;
    zTransValueInt=0;
    
    numberOfTouches=0;
    previousNumberOfTaps=0;
    currentNumberOfTaps=0;
    isLongPressed=FALSE;
    
    
    startingPoint.x = 0;
    startingPoint.y = 0;
    
    currentPoint.x = 0;
    currentPoint.y = 0; 
    
    //Adjust the sensitivity 
    sensitivity = [_iMove3DAppDelegate.sensitivity floatValue];
    sensitivity = 5 / (10.1 - sensitivity);     
    
    NSLog(@"Sensitivity: %f",sensitivity);    
    NSLog(@"Touch Ready");    
}


-(void) setupGyro{
    sampleFrecuency = [_iMove3DAppDelegate.sampFrecuency floatValue];
    motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 1.0 / sampleFrecuency;
    [motionManager startDeviceMotionUpdates];
    NSLog(@"Sample Frecuency: %f",sampleFrecuency);
    NSLog(@"Gyro Ready");
}


- (void)setupSocket
{
    if (udpSocket == nil)
	{
        //UDP Packet size
        size = 13;

        transSpeed = [_iMove3DAppDelegate.transSpeed floatValue];
        NSLog(@"Trans Speed %f",transSpeed);
        udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        NSError *error = nil;
        
        if (![udpSocket bindToPort:8888 error:&error])
        {
            NSLog(@"Error binding: %@", error);
            return;
        }
        if (![udpSocket beginReceiving:&error])
        {
            NSLog(@"Error receiving: %@", error);
            return;
        }
        host = _iMove3DAppDelegate.url;
        port = [_iMove3DAppDelegate.port intValue];
        
        NSLog(@"Socket Ready");
    }        
}


- (void) setupButtons
{
    [self setPointingMode];

    NSLog(@"Buttons Ready");
    
}

-(void) runDevice{
    
    NSLog(@"Running Device");    
    timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/transSpeed)
                                             target:self 
                                           selector:@selector(doUpdate)
                                           userInfo:nil 
                                            repeats:YES];
}

-(void)doUpdate 
{
    startingPoint = _iMove3DAppDelegate.startPoint;
    currentPoint = _iMove3DAppDelegate.currentPoint;
    numberOfTouches = _iMove3DAppDelegate.numberOfTouches;
    isLongPressed = _iMove3DAppDelegate.isLongPressed;

    
    //NSLog(@"Number of taps: %d",numberOfTaps);
    if(previousNumberOfTaps!=currentNumberOfTaps)
    {
        //[self processStateByNumberOfTaps];
        previousNumberOfTaps=currentNumberOfTaps;
        currentNumberOfTaps=0;
    }
    
    //Is Gyro Mode
    if(isGyroMode)
    {
        xRotValue = motionManager.deviceMotion.attitude.yaw*500/M_PI;
        yRotValue = motionManager.deviceMotion.attitude.pitch*500/M_PI;
        zRotValue = motionManager.deviceMotion.attitude.roll*500/M_PI;
	
        xRotValueInt = (short int) xRotValue;
        yRotValueInt = (short int) yRotValue;
        zRotValueInt = (short int) zRotValue;
        
        xRotValueLabel.text = [NSString stringWithFormat:@"%2.1f",(float)xRotValueInt/2.77];
        yRotValueLabel.text = [NSString stringWithFormat:@"%2.1f",(float)yRotValueInt/2.77];
        zRotValueLabel.text = [NSString stringWithFormat:@"%2.1f",(float)zRotValueInt/2.77];
                
        if(numberOfTouches == 1)
        //if(!isLongPressed)
        {
            if (startingPoint.x != currentPoint.x) {
                delta_X = (currentPoint.x - startingPoint.x)*sensitivity;
                xTransValueInt = xTransValueInt + delta_X;
            }
            if (startingPoint.y != currentPoint.y) {
                delta_Y = (currentPoint.y - startingPoint.y)*sensitivity;
                yTransValueInt = yTransValueInt + delta_Y;
            }
            
        }
        else if (numberOfTouches == 2) 
        //else
        {
            if (startingPoint.y != currentPoint.y) {
                delta_Z = (currentPoint.y - startingPoint.y)*sensitivity;
                zTransValueInt = zTransValueInt + delta_Z;
            }
        }
        
        xTransValueLabel.text = [NSString stringWithFormat:@"%d",xTransValueInt];
        yTransValueLabel.text = [NSString stringWithFormat:@"%d",yTransValueInt];
        zTransValueLabel.text = [NSString stringWithFormat:@"%d",zTransValueInt];
    }
    //Is touching?
    else 
    {
        //Is Dragging?
        if(isDragging)
        {   
            //Is Rotating?
            if(isRotating)
            {
                if(numberOfTouches == 1)
                //if(!isLongPressed)
                {
                    if (startingPoint.x != currentPoint.x) {
                        delta_X = (currentPoint.x - startingPoint.x)*sensitivity;
                        xRotValueInt = xRotValueInt + delta_X;
                    }
                    if (startingPoint.y != currentPoint.y) {
                        delta_Y = (currentPoint.y - startingPoint.y)*sensitivity;
                        yRotValueInt = yRotValueInt + delta_Y;
                    }
                    
                }
                else if (numberOfTouches == 2) 
                //else
                {
                    if (startingPoint.y != currentPoint.y) {
                        delta_Z = (currentPoint.y - startingPoint.y)*sensitivity;
                        zRotValueInt = zRotValueInt + delta_Z;
                    }
                }
                
                xRotValueLabel.text = [NSString stringWithFormat:@"%2.1f",(float)xRotValueInt];
                yRotValueLabel.text = [NSString stringWithFormat:@"%2.1f",(float)yRotValueInt];
                zRotValueLabel.text = [NSString stringWithFormat:@"%2.1f",(float)zRotValueInt];
            }
            //Is Translating?
            else 
            {
                if(numberOfTouches == 1)
                //if(!isLongPressed)
                {
                    if (startingPoint.x != currentPoint.x) 
                    {
                        delta_X = (currentPoint.x - startingPoint.x)*sensitivity;
                        xTransValueInt = xTransValueInt + delta_X;
                    }
                    if (startingPoint.y != currentPoint.y) 
                    {
                        delta_Y = (currentPoint.y - startingPoint.y)*sensitivity;
                        yTransValueInt = yTransValueInt + delta_Y;
                    }                
                }
                else if (numberOfTouches == 2) 
                //else
                {
                    if (startingPoint.y != currentPoint.y) 
                    {
                        delta_Z = (currentPoint.y - startingPoint.y)*sensitivity;
                        zTransValueInt = zTransValueInt + delta_Z;
                    }
                }
                
                xTransValueLabel.text = [NSString stringWithFormat:@"%d",xTransValueInt];
                yTransValueLabel.text = [NSString stringWithFormat:@"%d",yTransValueInt];
                zTransValueLabel.text = [NSString stringWithFormat:@"%d",zTransValueInt];
                
            }
        }
        //Is Pointing?
        else 
        {
            //Calculate the translation of the pointer in X
            if (startingPoint.x != currentPoint.x) 
            {
                delta_X = (currentPoint.x - startingPoint.x)*sensitivity;
                xTransValueInt = xTransValueInt + delta_X;
            }
            //Calculate the translation of the pointer in Y
            if (startingPoint.y != currentPoint.y) 
            {
                delta_Y = (currentPoint.y - startingPoint.y)*sensitivity;
                yTransValueInt = yTransValueInt + delta_Y;
            }
            //xTransValueInt=delta_X;
            //yTransValueInt=delta_Y;
            xTransValueLabel.text = [NSString stringWithFormat:@"%d",xTransValueInt];
            yTransValueLabel.text = [NSString stringWithFormat:@"%d",yTransValueInt];
            zTransValueLabel.text = [NSString stringWithFormat:@"%d",0];
        }
    }


    //Buttons:
    buttons = (YES == YES) ? buttons | 0x80 : buttons & 0x7F;//PRESS=1000-0000, RELEASE=0111-1111
    buttons = (isDragging == YES) ? buttons | 0x40 : buttons & 0xBF;//PRESS=0100-0000, RELEASE=1011-1111
    buttons = (isRotating == YES) ? buttons | 0x20 : buttons & 0xDF;//PRESS=0010-0000, RELEASE=1101-1111
    buttons = (isGyroMode == YES) ? buttons | 0x10 : buttons & 0xEF;//PRESS=0001-0000, RELEASE=1110-1111
    buttons = (NO == YES) ? buttons | 0x08 : buttons & 0xF7;//PRESS=0000-1000, RELEASE=1111-0111
    buttons = (NO == YES) ? buttons | 0x04 : buttons & 0xFB;//PRESS=0000-0100, RELEASE=1111-1011
    buttons = (NO == YES) ? buttons | 0x02 : buttons & 0xFD;//PRESS=0000-0010, RELEASE=1111-1101
    buttons = (NO == YES) ? buttons | 0x01 : buttons & 0xFE;//PRESS=0000-0001, RELEASE=1111-1110
    

    //NSLog(@"BUT: %d MOV: %d, %d %d / ROT: %d, %d, %d",buttons,xTransValueInt,yTransValueInt,zTransValueInt,xRotValueInt,yRotValueInt,zRotValueInt);	
    
    
    unsigned char aBuffer[size];
    //Buttons
    aBuffer[0]=buttons;
    //Tranlation in  X
    aBuffer[1]=(Byte)((xTransValueInt&0xFF00)>>8);
    aBuffer[2]=(Byte)(xTransValueInt&0x00FF);
    //Tranlation in  Y
    aBuffer[3]=(Byte)((yTransValueInt&0xFF00)>>8);
    aBuffer[4]=(Byte)(yTransValueInt&0x00FF);
    //Tranlation in  Z
    aBuffer[5]=(Byte)((zTransValueInt&0xFF00)>>8);
    aBuffer[6]=(Byte)(zTransValueInt&0x00FF);
    //Rotation in X
    aBuffer[7]=(Byte)((xRotValueInt&0xFF00)>>8);
    aBuffer[8]=(Byte)(xRotValueInt&0x00FF);
    //Rotation in Y
    aBuffer[9]=(Byte)((yRotValueInt&0xFF00)>>8);
    aBuffer[10]=(Byte)(yRotValueInt&0x00FF);
    //Rotation in Z
    aBuffer[11]=(Byte)((zRotValueInt&0xFF00)>>8);
    aBuffer[12]=(Byte)(zRotValueInt&0x00FF);    

    //Send the information to the socket
    data = [NSData dataWithBytes:aBuffer length:size];	
    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:tag];
    //NSString *msg = [NSString stringWithFormat:@"%d %d %d\n",yawAsInt,pitchAsInt,rollAsInt];
    //NSLog(@"Sent (%ld) Sent: %@", tag ,msg);
    tag++;
}

-(void)stopDevice {
    [motionManager stopGyroUpdates];
    [timer invalidate];
}

- (void)viewDidUnload
{
    [self setXRotValueLabel:nil];
    [self setYRotValueLabel:nil];
    [self setZRotValueLabel:nil];
    [udpSocket close];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}


-(void) processStateByNumberOfTaps
{
    currentNumberOfTaps = _iMove3DAppDelegate.numberOfTaps;
    if (currentNumberOfTaps==1) 
    {
        [self changeStatePointingDragging];
    }
    else if (currentNumberOfTaps==2) 
    {
        if(isDragging && !isGyroMode)
        {
            [self changeStateTranslatingRotating];
        }
    }
    else if (currentNumberOfTaps==3) 
    {
        if(isDragging)
        {
            [self changeStateGyroTouching];
        }
    }
}


- (IBAction)togglePointingDragging:(id)sender 
{
    [self changeStatePointingDragging];
}

- (IBAction)toggleTranslatingRotating:(id)sender 
{
    [self changeStateTranslatingRotating];
}

- (IBAction)toggleGyroTouching:(id)sender 
{
    [self changeStateGyroTouching];
}

-(void) changeStatePointingDragging
{
    //Is the user dragging an object?
    if(isDragging)
    {
        [self setPointingMode];
    }
    else 
    {
        [self setDraggingMode];
    }
}


- (void) changeStateTranslatingRotating
{
    //Is the user rotating an object?
    if(isRotating)
    {
        [self setTranslatingMode];
    }
    else
    {
        [self setRotatingMode];
    }
}

-(void) changeStateGyroTouching
{
    //Is the gyro on?
    if(isGyroMode)
    {
        [self setTouchingMode];
        //Let's enabling the button for setting the touch pad to rotate or translate objects
        [toggleTranslatingRotatingButton setEnabled:TRUE];
        //[toggleTouchPadToRotateTranslate setHidden:FALSE];
        [toggleTranslatingRotatingButton setTitle:@"Rotating" forState:UIControlStateNormal];
        
        UIColor *myColor2 = [UIColor colorWithRed:51.0f/255.0f green:102.0f/255.0f blue:153.0f/255.0f alpha:1.0f];        
        [toggleTranslatingRotatingButton setTitleColor:myColor2 forState:UIControlStateNormal];
        [toggleTranslatingRotatingButton setBackgroundImage:[UIImage imageNamed:@"grey.bmp"] forState:UIControlStateNormal];
        isRotating=YES;
    }
    else 
    {
        [self setGyroMode];
        //Let's disable the button for setting the touch pad to rotate or translate objects
        [toggleTranslatingRotatingButton setEnabled:FALSE];
        [toggleTranslatingRotatingButton setTitle:@"Translating" forState:UIControlStateNormal];
        UIColor *myColor2 = [UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:1.0f];
        [toggleTranslatingRotatingButton setTitleColor:myColor2 forState:UIControlStateNormal];
        [toggleTranslatingRotatingButton setBackgroundImage:[UIImage imageNamed:@"orange.bmp"] forState:UIControlStateNormal];
        isRotating=NO;
    }
   
}

-(void) setPointingMode{
    //Let's point the object
    [togglePointingDragButton setTitle:@"Pointing" forState:UIControlStateNormal];
    UIColor *myColor = [UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:1.0f];
    [togglePointingDragButton setTitleColor:myColor forState:UIControlStateNormal];
    [togglePointingDragButton setBackgroundImage:[UIImage imageNamed:@"blue.bmp"] forState:UIControlStateNormal];
    isDragging=NO;
    //Since the user is pointing an object, the Translating/Rotating button should be disabled and gone
    [toggleTranslatingRotatingButton setEnabled:FALSE];
    [toggleTranslatingRotatingButton setHidden:TRUE];
    [self setTranslatingMode];
    //Since the user is pointing an object, the Gyro/Touching button should be disabled and gone
    [toggleGryoTouchingButton setEnabled:FALSE];
    [toggleGryoTouchingButton setHidden:TRUE];    
    [self setTouchingMode];

}

-(void) setDraggingMode{
    [togglePointingDragButton setTitle:@"Dragging" forState:UIControlStateNormal];
    UIColor *myColor = [UIColor colorWithRed:51.0f/255.0f green:102.0f/255.0f blue:153.0f/255.0f alpha:1.0f];
    [togglePointingDragButton setTitleColor:myColor forState:UIControlStateNormal];
    [togglePointingDragButton setBackgroundImage:[UIImage imageNamed:@"yellow.bmp"] forState:UIControlStateNormal];
    isDragging=YES;
    //Since the user is dragging an object, the Translating/Rotating button should be enabled and shown
    [toggleTranslatingRotatingButton setEnabled:TRUE];
    [toggleTranslatingRotatingButton setHidden:FALSE];   
    [self setTranslatingMode];
    //Since the user is dragging an object, the Gyro/Touching button should be enabled and shown
    [toggleGryoTouchingButton setEnabled:TRUE];
    [toggleGryoTouchingButton setHidden:FALSE];    
    [self setTouchingMode];
}

-(void) setTranslatingMode{
    [toggleTranslatingRotatingButton setTitle:@"Translating" forState:UIControlStateNormal];
    UIColor *myColor = [UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:1.0f];
    [toggleTranslatingRotatingButton setTitleColor:myColor forState:UIControlStateNormal];
    [toggleTranslatingRotatingButton setBackgroundImage:[UIImage imageNamed:@"orange.bmp"] forState:UIControlStateNormal];
    isRotating=NO;
}

-(void) setRotatingMode{
    [toggleTranslatingRotatingButton setTitle:@"Rotating" forState:UIControlStateNormal];
    
    UIColor *myColor = [UIColor colorWithRed:51.0f/255.0f green:102.0f/255.0f blue:153.0f/255.0f alpha:1.0f];        
    [toggleTranslatingRotatingButton setTitleColor:myColor forState:UIControlStateNormal];
    [toggleTranslatingRotatingButton setBackgroundImage:[UIImage imageNamed:@"grey.bmp"] forState:UIControlStateNormal];
    isRotating=YES;
}

-(void) setTouchingMode{
    //Turn the touch pad on
    [toggleGryoTouchingButton setTitle:@"Touch" forState:UIControlStateNormal];
    UIColor *myColor = [UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:1.0f];
    [toggleGryoTouchingButton setTitleColor:myColor forState:UIControlStateNormal];
    [toggleGryoTouchingButton setBackgroundImage:[UIImage imageNamed:@"red.bmp"] forState:UIControlStateNormal];
    isGyroMode=NO;
}

-(void) setGyroMode{
    //let's turn on the gyro
    [toggleGryoTouchingButton setTitle:@"Gyro" forState:UIControlStateNormal];
    UIColor *myColor = [UIColor colorWithRed:51.0f/255.0f green:102.0f/255.0f blue:153.0f/255.0f alpha:1.0f];
    [toggleGryoTouchingButton setTitleColor:myColor forState:UIControlStateNormal];
    [toggleGryoTouchingButton setBackgroundImage:[UIImage imageNamed:@"green.bmp"] forState:UIControlStateNormal];
    isGyroMode=YES;
}

- (IBAction)settingsButton:(id)sender 
{    
    //[self viewDidUnload];
    [self stopDevice];
    [udpSocket close];
    [self dismissModalViewControllerAnimated:YES];
}

@end
