//
//  PaddlesViewController.m
//  Paddles
//
//  Created by Górczyński Robert on 12/01/2012.
//

#import "PaddlesViewController.h"

#define MAX_SCORE 3
#define SOUND_WALL   0
#define SOUND_PADDLE 1
#define SOUND_SCORE  2


@implementation PaddlesViewController
@synthesize viewPaddle1;
@synthesize viewPaddle2;
@synthesize viewPuck;
@synthesize viewScore1;
@synthesize viewScore2;

// Wczytanie efektu dźwiękowego do tablicy dźwięków.
- (void)loadSound:(NSString*)name Slot:(int)slot
{
    if (sounds[slot] != 0) return;
    
    // Utworzenie ścieżki dostępu do pliku dźwięku.
    NSString *sndPath = [[NSBundle mainBundle] pathForResource:name 
                                                        ofType:@"wav" 
                                                   inDirectory:@"/"];
    
    // Utworzenie identyfikatora dla dźwięku znajdującego się w slocie.
    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: sndPath], &sounds[slot]);
}

- (void)initSounds
{
    [self loadSound:@"wall" Slot:SOUND_WALL];
    [self loadSound:@"paddle" Slot:SOUND_PADDLE];
    [self loadSound:@"score" Slot:SOUND_SCORE];
}

- (void)playSound:(int)slot
{
    AudioServicesPlaySystemSound(sounds[slot]);
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Usunięcie wszelkich buforowanych danych, obrazów itd., które nie są obecnie używane.
}

#pragma mark - View lifecycle
- (BOOL)canBecomeFirstResponder
{ 
    return YES; 
}

- (void)viewDidUnload
{
    [self setViewPaddle1:nil];
    [self setViewPaddle2:nil];
    [self setViewPuck:nil];
    [self setViewScore1:nil];
    [self setViewScore2:nil];
    [super viewDidUnload];
    // Usunięcie wszystkich "przytrzymanych" podwidoków widoku głównego,
    // na przykład self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self becomeFirstResponder];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self resignFirstResponder];
	[super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
	[super viewDidDisappear:animated];
}

/*
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Zwrot wartości YES dla obsługiwanych układów.
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
*/

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Iteracja przez elementy dotknięcia.
    for (UITouch *touch in touches)
    {
        // Pobranie miejsca dotknięcia palcem w widoku.
        CGPoint touchPoint = [touch locationInView:self.view];
        
        // Sprawdzenie, która połowa ekranu została dotknięta i przypisanie
        // dotknięcia do określonej paletki, jeśli nie zostało jeszcze przypisane.
        if (touch1 == nil && touchPoint.y < 240) 
        {
            touch1 = touch;
            viewPaddle1.center = CGPointMake(touchPoint.x, viewPaddle1.center.y);
        }
        else if (touch2 == nil && touchPoint.y >= 240)
        {
            touch2 = touch;
            viewPaddle2.center = CGPointMake(touchPoint.x, viewPaddle2.center.y);
        }
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Iteracja przez elementy dotknięcia.
    for (UITouch *touch in touches)
    {
        // Pobranie miejsca dotknięcia palcem w widoku.
        CGPoint touchPoint = [touch locationInView:self.view];
        
        // Jeżeli dotknięcie jest przypisane paletce, zmieniamy położenie paletki.
        if (touch == touch1) 
        {
            viewPaddle1.center = CGPointMake(touchPoint.x, viewPaddle1.center.y);
        }
        else if (touch == touch2)
        {
            viewPaddle2.center = CGPointMake(touchPoint.x, viewPaddle2.center.y);
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Iteracja przez elementy dotknięcia.
    for (UITouch *touch in touches)
    {
        if (touch == touch1) touch1 = nil;
        else if (touch == touch2) touch2 = nil;
    }
}

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

- (void)reset
{
    // Określenie kierunku poruszania się piłeczki: w lewo lub w prawo.
    if ((arc4random() % 2) == 0) dx = -1; else dx = 1;
    
    // Odwrócenie wartości dy jeżeli nie wynosi 0 ponieważ to spowoduje ruch piłeczki 
    // w kierunku gracza, który zdobył punkt. W przeciwnym razie kierunek będzie wybrany losowo.
    if (dy != 0) dy = -dy;
    else if ((arc4random() % 2) == 0) dy = -1; else dy = 1;
    
    // Przejście do losowo wybranego położenia na środku ekranu.
    viewPuck.center = CGPointMake(15 + arc4random() % (320-30), 240);
    
    // Wyzerowanie prędkości.
    speed = 2;
}

- (void)start
{
    if (timer == nil)
    {
        // Utworzenie stopera animacji.
        timer = [[NSTimer scheduledTimerWithTimeInterval:1.0/60.0
                                                  target:self 
                                                selector:@selector(animate) 
                                                userInfo:NULL 
                                                 repeats:YES] retain];
    }
    
    // Wyświetlenie piłeczki.
    viewPuck.hidden = NO;
}

- (void)stop
{
    if (timer != nil)
    {
        [timer invalidate];
        [timer release];
        timer = nil;
    }
    
    // Ukrycie piłeczki.
    viewPuck.hidden = YES;
}

- (void)displayMessage:(NSString*) msg
{
    // Jednocześnie może być wyświetlony tylko jeden komunikat.
    if (alert) return;
    
    // Wstrzymanie animacji.
    [self stop];
    
    // Utworzenie i wyświetlenie okna komunikatu.
    alert = [[UIAlertView alloc] initWithTitle:@"Gra" 
                                       message:msg
                                      delegate:self 
                             cancelButtonTitle:@"OK" 
                             otherButtonTitles:nil];
    [alert show];
    [alert release];
}

- (void)newGame
{
    [self reset];
    
    // Wyzerowanie punktacji.
    viewScore1.text = [NSString stringWithString:@"0"];
    viewScore2.text = [NSString stringWithString:@"0"];
    
    // Wyświetlenie komunikatu pozwalającego na rozpoczęcie gry.
    [self displayMessage:@"Gotowi do gry?"];
}

- (int)gameOver
{
    if ([viewScore1.text intValue] >= MAX_SCORE) return 1;
    if ([viewScore2.text intValue] >= MAX_SCORE) return 2;
    return 0;
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    // Okno zostało zamknięte więc można wyzerować grę i rozpocząć odtwarzanie animacji.
    alert = nil;
    
    // Sprawdzenie czy należy rozpocząć nową grę?
    if ([self gameOver])
    {
        [self newGame];
        return;
    }
    
    // Wyzerowanie rundy.
    [self reset];
    
    // Wyzerowanie animacji.
    [self start];
}

- (BOOL)checkPuckCollision:(CGRect)rect 
                      DirX:(float)x 
                      DirY:(float)y
{
    // Sprawdzenie, czy piłeczka przecina się z podanym prostokątem.
    if (CGRectIntersectsRect(viewPuck.frame, rect))
    {
        // Zmiana kierunku poruszania się piłeczki.
        if (x != 0) dx = x;
        if (y != 0) dy = y;
        return TRUE;
    }
    return FALSE;
}

- (BOOL)checkGoal
{
    // Sprawdzenie, czy piłeczka wykroczyła poza ekran. Jeśli tak, zerujemy rundę.
    if (viewPuck.center.y < 0 || viewPuck.center.y >= 480) 
    {
        // Pobranie wartości liczbowej z etykiet punktacji.
        int s1 = [viewScore1.text intValue];
        int s2 = [viewScore2.text intValue];
        
        // Przydzielenie punktu odpowiedniemu graczowi.
        if (viewPuck.center.y < 0) ++s2; else ++s1;
        
        // Uaktualnienie etykiet punktacji.
        viewScore1.text = [NSString stringWithFormat:@"%u", s1];
        viewScore2.text = [NSString stringWithFormat:@"%u", s2];
        
        // Sprawdzenie zwycięzcy.
        if ([self gameOver] == 1)
        {
            // Ogłoszenie zwycięzcy.
            [self displayMessage:@"Wygrał gracz numer 1!"];
        }
        else if ([self gameOver] == 2)
        {
            // Ogłoszenie zwycięzcy.
            [self displayMessage:@"Wygrał gracz numer 2!"];
        }
        else
        {
            // Wyzerowanie rundy.
            [self reset];
        }
        
        // Zwrócenie wartości TRUE w przypadku zdobycia punktu.
        return TRUE;
    }
    
    // Brak punktu.
    return FALSE;
}

- (void)increaseSpeed
{
    speed += 0.5;
    if (speed > 10) speed = 10;
}

- (void)animate
{
    // Przesunięcie piłeczki do nowego położenia uwzględniając jej kierunek i prędkość.
    viewPuck.center = CGPointMake(viewPuck.center.x + dx*speed,
                                  viewPuck.center.y + dy*speed);
    
    // Sprawdzenie wystąpienia kolizji piłeczki z lewą lub prawą ścianą.
    if ([self checkPuckCollision:CGRectMake(-10,0,20,480) 
                            DirX:fabs(dx) 
                            DirY:0])
    {
        // Odtworzenie dźwięku uderzenia o ścianę.
        [self playSound:SOUND_WALL];
    }
    if ([self checkPuckCollision:CGRectMake(310,0,20,480) 
                            DirX:-fabs(dx) 
                            DirY:0])
    {
        // Odtworzenie dźwięku uderzenia o ścianę.
        [self playSound:SOUND_WALL];
    }
    // Wykrywanie kolizji piłeczki z paletkami graczy.
    if ([self checkPuckCollision:viewPaddle1.frame 
                            DirX:(viewPuck.center.x - viewPaddle1.center.x) / 32.0 
                            DirY:1])
    {
        // Odtworzenie dźwięku uderzenia o paletkę i zwiększenie prędkości piłeczki.
        [self increaseSpeed];
        [self playSound:SOUND_PADDLE];
    }
    
    if ([self checkPuckCollision:viewPaddle2.frame 
                            DirX:(viewPuck.center.x - viewPaddle2.center.x) / 32.0 
                            DirY:-1])
    {
        // Odtworzenie dźwięku uderzenia o paletkę i zwiększenie prędkości piłeczki.
        [self increaseSpeed];
        [self playSound:SOUND_PADDLE];
    }
    
    // Sprawdzenie, czy został zdobyty punkt.
    if ([self checkGoal])
    {
        // Odtworzenie dźwięku podczas dodawania punktu graczowi.
        [self playSound:SOUND_SCORE];
    }
}

- (void)pause
{
    [self stop];
}

- (void)resume
{
    // Wyświetlenie komunikatu z pytaniem o wznowienie gry.
    [self displayMessage:@"Gra jest wstrzymana"];
}

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event 
{
    if (event.type == UIEventSubtypeMotionShake) 
    {
        // Wstrzymanie gry, a następnie jej wznowienie w celu wyświetlenia komunikatu.
        [self pause];
        [self resume];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Wszelka konfiguacja dodatkowa po wczytaniu widoku z pliku nib.
    [self initSounds];
    [self newGame];
}

- (void)dealloc {
    // Usunięcie dźwięków.
    for (int i = 0; i < 3; ++i) 
    {
        AudioServicesDisposeSystemSoundID(sounds[i]);
    }

    [viewPaddle1 release];
    [viewPaddle2 release];
    [viewPuck release];
    [viewScore1 release];
    [viewScore2 release];
    [super dealloc];
}
@end
