//
//  ICFGameCenterManager.m
//  WhackACac
//
//  Created by Kyle Richter on 7/3/12.
//  Copyright (c) 2012 Dragon Forged Software. All rights reserved.
//

#import "ICFGameCenterManager.h"

@implementation ICFGameCenterManager

@synthesize delegate;

static ICFGameCenterManager *sharedManager = nil;

#pragma mark -
#pragma mark Overhead

+ (ICFGameCenterManager *)sharedManager
{
    @synchronized(self)
    {
        if (sharedManager == nil)
        {
            sharedManager = [[self alloc] init];
        }
    }
    
    return sharedManager;
}

- (void)callDelegateOnMainThread:(SEL)selector withArg:(id)arg error:(NSError*)error
{
	dispatch_async(dispatch_get_main_queue(), ^(void)
    {
        [self callDelegate: selector withArg: arg error: error];
    });
}

- (void)callDelegate: (SEL)selector withArg: (id)arg error:(NSError*)error
{
	assert([NSThread isMainThread]);
    
    if(delegate == nil)
    {
        NSLog(@"Game Center Manager Delegate has not been set");
        return;
    }
    
	if([delegate respondsToSelector: selector])
	{
		if(arg != NULL)
        {
			[delegate performSelector: selector withObject: arg withObject: error];
        }
		
		else
        {
			[delegate performSelector: selector withObject: error];
        }
	}
	
	else
    {
		NSLog(@"Unable to find delegate method '%s' in class %@", sel_getName(selector), [delegate class]);
    }
}

-(void)dealloc
{
    if(achievementDictionary != nil)
    {
        achievementDictionary = nil;
    }
    
}

- (void)callDelegate: (SEL)selector withArg: (id)arg error:(NSError*)error
{
	assert([NSThread isMainThread]);
    
    if(delegate == nil)
    {
        NSLog(@"Delegacja menedżera Game Center nie została ustawiona");
        return;
    }
    
	if([delegate respondsToSelector: selector])
	{
		if(arg != NULL)
        {
			[delegate performSelector: selector withObject: arg withObject: error];
        }
		
		else
        {
			[delegate performSelector: selector withObject: error];
        }
	}
	
	else
    {
		NSLog(@"Nie można znaleźć metody delegacji '%s' w klasie %@", sel_getName(selector), [delegate class]);
    }
}


#pragma mark -
#pragma mark Authentication

- (void) authenticateLocalUser
{
	if([GKLocalPlayer localPlayer].authenticated == NO)
	{
		[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)
		 {
             if(error != nil)
             {
                 if([error code] == GKErrorNotSupported)
                 {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd" message:@"To urządzenie nie obsługuje Game Center" delegate:nil cancelButtonTitle:@"Anuluj" otherButtonTitles:nil];
                     [alert show];
                 }
                 
                 else if([error code] == GKErrorCancelled)
                 {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd" message:@"To urządzenie wykonało zbyt wiele prób logowania, musisz zalogować się z poziomu Game Center" delegate:nil cancelButtonTitle:@"Anuluj" otherButtonTitles:nil];
                     [alert show];
                 }
                 
                 else
                 {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"Anuluj" otherButtonTitles:nil];
                     [alert show];
                 }
                 
                 
                 return;
             }
             
			 [self callDelegateOnMainThread: @selector(gameCenterLoggedIn:) withArg: NULL error: error];
             [self submitAllSavedScores];
		 }];
	}
}

-(void)authenticateLocalUseriOSSix
{
    if([GKLocalPlayer localPlayer].authenticateHandler == nil)
	{
        [[GKLocalPlayer localPlayer] setAuthenticateHandler:^(UIViewController *viewController, NSError *error)
         {
             if(error != nil)
             {
                 if([error code] == GKErrorNotSupported)
                 {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd" message:@"To urządzenie nie obsługuje Game Center" delegate:nil cancelButtonTitle:@"Anuluj" otherButtonTitles:nil];
                     [alert show];
                 }
                 
                 else if([error code] == GKErrorCancelled)
                 {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd" message:@"To urządzenie wykonało zbyt wiele prób logowania, musisz zalogować się z poziomu Game Center" delegate:nil cancelButtonTitle:@"Anuluj" otherButtonTitles:nil];
                     [alert show];
                 }
                 
                 else
                 {
                     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Błąd" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"Anuluj" otherButtonTitles:nil];
                     [alert show];
                 }
             }
             
             else
             {
                 if(viewController != nil)
                 {
                     [(UIViewController *)delegate presentModalViewController:viewController animated:YES];
                 }
                 
                 [self submitAllSavedScores];
             }
         }];
    }
    
}

#pragma mark -
#pragma mark Scores

- (void)reportScore:(int64_t)score forCategory:(NSString*)category
{
	GKScore *scoreReporter = [[GKScore alloc] initWithCategory:category];
	scoreReporter.value = score;
    
	[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)
	 {
		 if (error != nil)
		 {
			 NSData* savedScoreData = [NSKeyedArchiver archivedDataWithRootObject:scoreReporter];
             [self storeScoreForLater: savedScoreData];
		 }
		 
		 [self callDelegateOnMainThread:@selector(gameCenterScoreReported:) withArg:NULL error:error];
	 }];
}

- (void)storeScoreForLater:(NSData *)scoreData;
{
	NSMutableArray *savedScoresArray = [[NSMutableArray alloc] initWithArray: [[NSUserDefaults standardUserDefaults] objectForKey:@"savedScores"]];
	[savedScoresArray addObject: scoreData];
	[[NSUserDefaults standardUserDefaults] setObject:savedScoresArray forKey:@"savedScores"];
}
-(void)submitAllSavedScores
{
	NSMutableArray *savedScoreArray = [[NSMutableArray alloc] initWithArray: [[NSUserDefaults standardUserDefaults] objectForKey:@"savedScores"]];
	[[NSUserDefaults standardUserDefaults] removeObjectForKey: @"savedScores"];
	
	for(NSData *scoreData in savedScoreArray)
	{
		GKScore *scoreReporter = [NSKeyedUnarchiver unarchiveObjectWithData: scoreData];
		
		[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)
		 {
			 if (error != nil)
			 {
				 NSData* savedScoreData = [NSKeyedArchiver archivedDataWithRootObject:scoreReporter];
				 [self storeScoreForLater: savedScoreData];
			 }
			 
			 else
             {
				 NSLog(@"Wysłano wyniki oczekujące na wysłanie");
                 [self callDelegateOnMainThread:@selector(gameCenterScoreReported:) withArg:NULL error:error];
             }
		 }];
	}
}

#pragma mark -
#pragma mark Achievements


- (void)resetAchievements
{
	[achievementDictionary removeAllObjects];
	
	[GKAchievement resetAchievementsWithCompletionHandler: ^(NSError *error)
	 {
		 if(error == nil)
		 {
			 NSLog(@"Osiągnięcia zostały usunięte");
		 }
         
		 else
		 {
			 NSLog(@"Nie można usunąć osiągnięć: %@", [error localizedDescription]);
		 }
	 }];
}

-(void)populateAchievementCache
{
    if(achievementDictionary != nil)
    {
        NSLog(@"Odnowienie pamięci podręcznej osiągnięć: %@", achievementDictionary);
    }
    
    else
    {
        achievementDictionary = [[NSMutableDictionary alloc] init];
    }
    
    [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error)
     {
        
         if(error != nil)
         {
             NSLog(@"Wystąpił błąd w trakcie wypełniania pamięci podręcznej osiągnięć: %@", [error localizedDescription]);
         }
         
         else
         {
             for(GKAchievement *achievement in achievements)
             {
                 [achievementDictionary setObject:achievement forKey:[achievement identifier]];
             }
         }
     }];
}



-(void)reportAchievement:(NSString *)identifier withPercentageComplete:(double)percentComplete
{
    if(achievementDictionary == nil)
    {
        NSLog(@"Przed wysłaniem postępu należy wypełnić pamięć podręczną osiągnięć");
        return;
    }
        
    GKAchievement *achievement = [achievementDictionary objectForKey: identifier];
    
    if(achievement == nil) //no progress has yet been made on this achievement 
    {
        achievement = [[GKAchievement alloc] initWithIdentifier: identifier];
        [achievement setPercentComplete: percentComplete];
        [achievementDictionary setObject: achievement forKey:identifier];
    }
    
    else //this achievement has some progress
    {
        if([achievement percentComplete] >= 100.0 || [achievement percentComplete] >= percentComplete)
        {
            NSLog(@"Próba zaktualizowania osiągnięcia %@, które zostało ukończone lub ma większy stopień osiągnięcia (%f)", identifier, percentComplete);
            return;
        }
        
        [achievement setPercentComplete: percentComplete];
        [achievementDictionary setObject: achievement forKey:identifier];
    }
    
    achievement.showsCompletionBanner = YES;
    
    [achievement reportAchievementWithCompletionHandler:^(NSError *error)
    {
        if(error != nil)
        {
            NSLog(@"Wystąpił błąd w trakcie wysyłania osiągnięcia %@: %@", identifier, [error localizedDescription]);
        }
        
        [self callDelegateOnMainThread:@selector(gameCenterAchievementReported:) withArg:NULL error:error];
    }];
}

-(GKAchievement *)achievementForIdentifier:(NSString *)identifier
{
    GKAchievement *achievement = nil;
    
    achievement = [achievementDictionary objectForKey:identifier];
    
    if(achievement == nil)
    {
        achievement = [[GKAchievement alloc] initWithIdentifier:identifier];
        [achievementDictionary setObject: achievement forKey:identifier];
    }
    
    return achievement;
}

@end
