#import "AppDelegate.h"
#import "TuneDatabase.h"
#import "MainViewController.h"
#import "ManageTunesController.h"
#import "PlaylistViewController.h"
#import "SettingsController.h"
#import "ImportProgressController.h"
#if TARGET_IPAD
#import "TopLevelViewController.h"
#import "TuneViewController.h"
#endif

@implementation AppDelegate

@synthesize database, settings, reachability, playerVolume, playerSpeed, playerVoice, navigationController, topViewController, initializedDatabase, guitarChords, loopPlayback, currentTune, transitionType;
@synthesize preventSleep;
@synthesize tuneScaling;
#if TARGET_IPAD
@synthesize tuneViewController;
#endif

- (void)dealloc
{
  [settings release];
  [database release];
	[navigationController release];
  [window release];
  [super dealloc];
}

static NSString *kSelectedTabKey = @"selectedTabKey";
static NSString *kPlayerVolumeKey = @"playerVolumeKey";
static NSString *kPlayerSpeedKey = @"playerSpeedKey";
static NSString *kPlayerVoiceKey = @"playerVoiceKey";
static NSString *kTuneSortOrderKey = @"tuneSortOrderKey";
static NSString *kGuitarChordsKey = @"guitarChordsKey";
static NSString *kLoopPlaybackKey = @"loopPlaybackKey";
static NSString *kPreventSleepKey = @"preventSleepKey";
static NSString *kCurrentTuneKey = @"currentTuneKey";
static NSString *kTransitionTypeKey = @"transitionType";
static NSString *kTuneScalingKey = @"tuneScaling";

void uncaughtExceptionHandler(NSException *exception)
{
  // If we had a crash while renedering a tune, we won't be able to start up again. Try not to display the offending tune next time we start up
  [[NSUserDefaults standardUserDefaults] setInteger:-1 forKey:kCurrentTuneKey];
  [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
//  NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
  selectedTab = 0;
  settings = [[NSMutableDictionary alloc] init];

#if TARGET_IPAD
#if 0//FIXME_NEWUI
  TopLevelViewController *topLevelViewController = [[TopLevelViewController alloc] initWithNibName:@"TopLevel" bundle:nil];
	[window addSubview: topLevelViewController.view];
  [window setRootViewController:topLevelViewController];//FIXME
  tuneViewController = topLevelViewController.tuneViewController;

  static PlaylistViewController *controller;
  static UINavigationController *navigationController;
  if ( !controller ) {
    controller = [[PlaylistViewController alloc] initWithNibName:@"PlaylistView" bundle:nil];
    [controller databaseChanged:self];
    navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
  }
  CGRect bounds = topLevelViewController.view.bounds;
  bounds.size.width = 320;
	navigationController.view.frame = bounds;
	navigationController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
	[topLevelViewController.view addSubview: navigationController.view];
  
#else
  tuneViewController = [[TuneViewController alloc] initWithTune:nil];
	[window addSubview: tuneViewController.view];
  [window setRootViewController:tuneViewController];//FIXME
#endif
#else
  [navigationController.navigationBar setBarStyle:UIBarStyleDefault];
	[window addSubview: navigationController.view];

	[tabView addSubview: tunesViewController.view];
  tunesViewController.view.frame = tabView.bounds;

	[tabView addSubview: playlistViewController.view];
  playlistViewController.view.frame = tabView.bounds;
  playlistViewController.view.hidden = YES;

	[tabView addSubview: searchViewController.view];
  searchViewController.view.frame = tabView.bounds;
  searchViewController.view.hidden = YES;

	[tabView addSubview: settingsController.view];
  settingsController.view.frame = tabView.bounds;
  settingsController.view.hidden = YES;

	[tabView addSubview: manageTunesController.view];
  manageTunesController.view.frame = tabView.bounds;
  manageTunesController.view.hidden = YES;

  currentViewController = tunesViewController;
#endif

  [rootView addSubview:loadingView];
  [window makeKeyAndVisible];

  reachability = [[Reachability reachabilityForInternetConnection] retain];
  [reachability startNotifer];

  // Initialize preferences
	NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kPlayerVolumeKey];
	if ( testValue == nil ) {
		NSDictionary *appDefaults =  [NSDictionary dictionaryWithObjectsAndKeys:
      [NSNumber numberWithInteger:kSortTunesByOrder], kTuneSortOrderKey,
      [NSNumber numberWithFloat:1], kPlayerVolumeKey,
      [NSNumber numberWithFloat:0], kPlayerVoiceKey,
      [NSNumber numberWithFloat:1], kPlayerSpeedKey,
      [NSNumber numberWithBool:1], kGuitarChordsKey,
      [NSNumber numberWithBool:1], kLoopPlaybackKey,
      [NSNumber numberWithBool:0], kPreventSleepKey,
      [NSNumber numberWithInteger:0], kSelectedTabKey,
      [NSNumber numberWithInteger:-1], kCurrentTuneKey,
      [NSNumber numberWithInteger:0], kTransitionTypeKey,
      [NSNumber numberWithFloat:1], kTuneScalingKey,
      nil];
		
		[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
		[[NSUserDefaults standardUserDefaults] synchronize];
	}
	
#if !TARGET_IPAD
  NSArray *items = tabBar.items;
  selectedTab = [[NSUserDefaults standardUserDefaults] integerForKey:kSelectedTabKey];
  if ( selectedTab >= 0 && selectedTab < [items count] ) {
    UITabBarItem *item = (UITabBarItem*)[items objectAtIndex:selectedTab];
    tabBar.selectedItem = item;
    [self tabBar:tabBar didSelectItem:item];
  }
#endif
	self.tuneSortOrder = [[NSUserDefaults standardUserDefaults] integerForKey:kTuneSortOrderKey];
	guitarChords = [[NSUserDefaults standardUserDefaults] boolForKey:kGuitarChordsKey];
	loopPlayback = [[NSUserDefaults standardUserDefaults] boolForKey:kLoopPlaybackKey];
	preventSleep = [[NSUserDefaults standardUserDefaults] boolForKey:kPreventSleepKey];
	playerVolume = [[NSUserDefaults standardUserDefaults] floatForKey:kPlayerVolumeKey];
	playerVoice = [[NSUserDefaults standardUserDefaults] integerForKey:kPlayerVoiceKey];
	playerSpeed = [[NSUserDefaults standardUserDefaults] floatForKey:kPlayerSpeedKey];
  if ( playerSpeed < -1 )
    playerSpeed = -1;
  if ( playerSpeed > 1 )
    playerSpeed = 1;
	currentTune = [[NSUserDefaults standardUserDefaults] integerForKey:kCurrentTuneKey];
	transitionType = [[NSUserDefaults standardUserDefaults] integerForKey:kTransitionTypeKey];
	tuneScaling = [[NSUserDefaults standardUserDefaults] floatForKey:kTuneScalingKey];
  if ( tuneScaling < 1.0f )
    tuneScaling = 1.0f;
  if ( tuneScaling > 2.0f )
    tuneScaling = 2.0f;

  [UIApplication sharedApplication].idleTimerDisabled = preventSleep;

//  [NSThread detachNewThreadSelector:@selector(threadRun:) toTarget:self withObject:nil];
[self threadRun:self];
}

- (void)showTuneController:(TuneViewController *)controller
{
#if TARGET_IPAD
  [tuneViewController showTune:controller.tune];
#endif
}

- (void)threadRun:(id)sender
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  [self initializeDatabase];
  [self performSelectorOnMainThread:@selector(databaseLoaded:) withObject:self waitUntilDone:NO];
  [pool release];
}

- (void)databaseLoaded:(id)sender
{
  [loadingView removeFromSuperview];
  tunesViewController.playlist = nil;
  [[NSNotificationCenter defaultCenter] postNotificationName:@"databaseLoaded" object:self];

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(importFiles:) name:@"importedFile" object:nil]; 
  // See if there are any ABC files to be synced
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentsDirectory = [paths objectAtIndex:0];
  NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
  for ( NSString *file in files ) {
    if ( [file hasSuffix:@".abc"] || [file hasSuffix:@".ABC"] ) {
      if ( !filesToImport )
        filesToImport = [[NSMutableArray alloc] init];
      NSString *path = [documentsDirectory stringByAppendingPathComponent:file];
      [filesToImport addObject:path];
    }
  }
  if ( [filesToImport count] > 0 ) {
    [self importFiles:self];
  }

#if TARGET_IPAD
	if ( currentTune >= 0 ) {
    // Unset the current tune preference. That way, if we get a crash due to a bad ABC file, we won't try to
    // load the file again next time we start up.
    [[NSUserDefaults standardUserDefaults] setInteger:-1 forKey:kCurrentTuneKey];
    [[NSUserDefaults standardUserDefaults] synchronize];

    Tune *tune = [Tune tuneWithPrimaryKey:currentTune database:database.database];
    [tune hydrate];
    [tuneViewController showTune:tune];
    [tune release];
  }
#endif
}

- (void)importFiles:(id)sender {
  // Import the next file on our list of files to import
  if ( [filesToImport count] > 0 ) {
    NSString *path = [filesToImport objectAtIndex:0];
    [path retain];
    [filesToImport removeObject:path];
    ImportProgressController *controller = [[ImportProgressController alloc] initWithNibName:@"ImportProgress" bundle:nil];
#if TARGET_IPAD
    [tuneViewController presentModalViewController:controller animated:YES];
#else
    [navigationController presentModalViewController:controller animated:YES];
#endif
    [controller import:[NSURL fileURLWithPath:path isDirectory:NO] animateDismiss:NO];
    [controller release];
    [path autorelease];
  }
}

- (void)initializeDatabase {
  database = [[TuneDatabase alloc] init];
  [database initializeDatabase];
  [Tune sortTunes:tunes by:self.tuneSortOrder];
  initializedDatabase = YES;
}

- (void)startTransaction
{
  [database startTransaction];
}

- (void)commitTransaction
{
  [database commitTransaction];
}

- (void)applicationWillTerminate:(UIApplication *)application {
  [tunes makeObjectsPerformSelector:@selector(dehydrate)];
  [Tune finalizeStatements];
  [Playlist finalizeStatements];
  [database close];
  [self savePreferences];
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
  // Save the current settings when enetering background
  [self savePreferences];
}

- (void)savePreferences
{
  [[NSUserDefaults standardUserDefaults] setFloat:selectedTab forKey:kSelectedTabKey];
  [[NSUserDefaults standardUserDefaults] setFloat:playerVolume forKey:kPlayerVolumeKey];
  [[NSUserDefaults standardUserDefaults] setFloat:playerSpeed forKey:kPlayerSpeedKey];
  [[NSUserDefaults standardUserDefaults] setInteger:playerVoice forKey:kPlayerVoiceKey];
  [[NSUserDefaults standardUserDefaults] setInteger:self.tuneSortOrder forKey:kTuneSortOrderKey];
  [[NSUserDefaults standardUserDefaults] setBool:guitarChords forKey:kGuitarChordsKey];
  [[NSUserDefaults standardUserDefaults] setBool:loopPlayback forKey:kLoopPlaybackKey];
  [[NSUserDefaults standardUserDefaults] setBool:preventSleep forKey:kPreventSleepKey];
  [[NSUserDefaults standardUserDefaults] setInteger:currentTune forKey:kCurrentTuneKey];
  [[NSUserDefaults standardUserDefaults] setInteger:transitionType forKey:kTransitionTypeKey];
  [[NSUserDefaults standardUserDefaults] setFloat:tuneScaling forKey:kTuneScalingKey];
  [[NSUserDefaults standardUserDefaults] synchronize];
}

- (id)tuneWithPrimaryKey:(NSInteger)pk
{
  return [Tune tuneWithPrimaryKey:pk database:database.database];
}

- (void)removeTune:(Tune *)tune {
  [database removeTune:tune];
}

- (void)addTune:(Tune *)tune {
  [database addTune:tune];
}

-(void)onImportTunes:(id)sender {
  ManageTunesController *controller = [[ManageTunesController alloc] initWithNibName:@"ManageTunes" bundle:nil];
	[navigationController pushViewController:controller animated:YES];
}

- (void)deleteAllTunes {
  [database deleteAllTunes];
#if TARGET_IPAD
  [self.tuneViewController showTune:nil];
#endif
}

- (void)sortTunes {
  [rootView addSubview:loadingView];
  [database sortTunesBy:self.tuneSortOrder];
  [loadingView removeFromSuperview];
}

- (void)addPlaylist:(Playlist *)playlist {
  [database addPlaylist:playlist];
}

- (void)removePlaylist:(Playlist *)playlist {
  [database removePlaylist:playlist];
}

- (void)searchForTunes:(NSString *)searchText tunes:(NSArray *)tunelist results:(NSMutableArray *)results
{
  [database searchForTunes:searchText tunes:tunelist results:results];
}

- (void)searchForTunesWithTitle:(NSString *)titleText key:(NSString *)keyText meter:(NSString *)meterText tunes:(NSArray *)tunelist results:(NSMutableArray *)results
{
  [database searchForTunesWithTitle:titleText key:keyText meter:meterText tunes:tunelist results:results];
}

- (void)searchForDots:(NSString *)searchText tunes:(NSArray *)tunelist results:(NSMutableArray *)results;
{
  [database searchForDots:searchText tunes:tunelist results:results];
}

- (NSMutableArray *)tunes
{
  return database.tunes;
}

- (NSMutableArray *)playlists
{
  return database.playlists;
}

- (int) tuneSortOrder
{
  return database.tuneSortOrder;
}

- (void) setTuneSortOrder:(int)order
{
  database.tuneSortOrder = (SortOrder)order;
}

- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
  selectedTab = [item tag];
  if ( currentViewController )
    [currentViewController viewWillDisappear:NO];
  currentViewController.view.hidden = YES;
  switch ( [item tag] ) {
  case 0:
    currentViewController = tunesViewController;
    topViewController.navigationItem.rightBarButtonItem = currentViewController.editButtonItem;
    break;
  case 1:
    currentViewController = playlistViewController;
    topViewController.navigationItem.rightBarButtonItem = currentViewController.editButtonItem;
    break;
  case 2:
    currentViewController = searchViewController;
    topViewController.navigationItem.rightBarButtonItem = nil;
    break;
  case 3:
    currentViewController = manageTunesController;
    topViewController.navigationItem.rightBarButtonItem = nil;
    break;
  case 4:
    currentViewController = settingsController;
    topViewController.navigationItem.rightBarButtonItem = nil;
    break;
  }
  if ( currentViewController )
    [currentViewController viewWillAppear:NO];
  currentViewController.view.hidden = NO;
}

- (void)refreshView
{
  //FIXME-This is a hacky workround for viewWillAppear not being called on MainView/PlaylistController when going Back from a tune,
  // which causes the Edit button to disappear.
  [self tabBar:tabBar didSelectItem:[tabBar selectedItem]];
}

@end

@implementation RootViewController

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
  return YES;
}

- (BOOL)shouldAutorotate {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskAll;
}

- (void)viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  [appDelegate refreshView];
}

@end
