#import "ImportProgressController.h"
#import "AppDelegate.h"
#import "Tune.h"
#import "PlaylistViewController.h"

@implementation ImportProgressController

-(void)viewDidLoad {
  animateDismiss = YES;
}

- (void)import:(NSURL *)url animateDismiss:(BOOL)animate
{
  animateDismiss = animate;
  progressView.progress = 0;
  _url = url;
  [_url retain];
  parsedTunes = [[NSMutableArray alloc] init];
  [parsedTunes retain];
  fragment = nil;
  lastWasCR = NO;
  titleLabel.text = [NSString stringWithFormat:@"Importing %@", [[_url path] lastPathComponent]];
  [NSThread detachNewThreadSelector:@selector(threadRun:) toTarget:self withObject:nil];
}

- (void)import:(NSURL *)url
{
  [self import:url animateDismiss:YES];
}

- (void) importRequest:(NSURLRequest *)request
{
  _request = [request retain];
  animateDismiss = YES;
  progressView.progress = 0;
  _url = [request URL];
  parsedTunes = [[NSMutableArray alloc] init];
  [parsedTunes retain];
  fragment = nil;
  lastWasCR = NO;
  titleLabel.text = [NSString stringWithFormat:@"Importing %@", [[_url path] lastPathComponent]];
  [NSThread detachNewThreadSelector:@selector(threadRun:) toTarget:self withObject:nil];
}

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

- (void)didReceiveMemoryWarning
{
	[super didReceiveMemoryWarning];
}

-(void)dealloc
{
  [_url release];
  [_request release];
  [parsedTunes release];
  [fragment release];
	[super dealloc];
}

- (IBAction) onCancel:(id)sender
{
  cancelled = true;
  finished = true;
  if ( urlConnection ) {
    [urlConnection cancel];
    urlConnection = NULL;
  }
  [self connectionDidFinishLoading:NULL];
}

- (void)threadRun:(id)sender
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  

  cancelled = false;
  finished = false;
  statusCode = 0;

  NSURLRequest *theRequest;
  if ( _request )
    theRequest = _request;
  else
    theRequest = [NSURLRequest requestWithURL:_url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];

  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  [appDelegate startTransaction];
  parser = [[TuneParser alloc] init];
  parser.delegate = self;

  numTunes = 0;
  bytesRead = 0;
  bytesProcessed = 0;

  urlConnection = [NSURLConnection connectionWithRequest:theRequest delegate:self];
  if ( urlConnection == nil ) {
    UIAlertView *alert = [[UIAlertView alloc] 
      initWithTitle: @"Unable to initiate request" 
      message:@"NSURLConnection initialization method failed" 
      delegate:self 
      cancelButtonTitle:nil 
      otherButtonTitles:@"OK", nil];
    [alert show];
  }

  BOOL done = NO;
  do {
    SInt32 result = CFRunLoopRunInMode( kCFRunLoopDefaultMode, 1, YES );
    if ( (result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished) ) {
      done = YES;
    }
    if ( cancelled || finished )
      done = YES;
  } while ( !done );

  // If it was a local file, delete it when finished
  if ( [_url isFileURL] ) {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager removeItemAtPath:[_url path] error:nil];
  }

  [pool release];
}

#pragma mark UIViewController delegate methods

- (void)viewWillAppear:(BOOL)animated
{
}

#pragma mark NSURLConnection delegate methods

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
  bytesToRead = (long)[response expectedContentLength];
  if ( [response isKindOfClass:[NSHTTPURLResponse class]] ) {
    statusCode = [(NSHTTPURLResponse *)response statusCode];
    if ( statusCode >= 400 )
      cancelled = true;
  }
}

- (void) updateProgress:(id)sender
{
  progressView.progress = (float)bytesProcessed / bytesToRead;
  statusLabel.text = [NSString stringWithFormat:@"Read %.1fKb, found %d tunes", (float)bytesProcessed/1024, numTunes];
}

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
  const char *b = (const char *)data.bytes;
  int length = data.length;
  int start = 0;

  if ( cancelled )
    return;

  bytesRead += length;
  [self performSelectorOnMainThread:@selector(updateProgress:) withObject:nil waitUntilDone:NO];

  int n = numTunes;
  int i = 0;
  for ( ; i < length && !cancelled; i++ ) {
    bytesProcessed++;
    if ( lastWasCR && b[i] == '\n' ) {
      lastWasCR = NO;
      start = i+1;
    } else if ( b[i] == '\r' || b[i] == '\n' ) {
      NSString *line = [[NSString alloc] initWithBytes:b+start length:i-start encoding:NSISOLatin1StringEncoding];
      if ( line == nil )
        line = [[NSString alloc] initWithBytes:b+start length:i-start encoding:NSUTF8StringEncoding];
      if ( fragment ) {
        [fragment appendString:line];
        [parser parseLine:fragment];
        [fragment release];
        fragment = nil;
      } else
        [parser parseLine:line];
      if ( numTunes >= n+10 ) {
        [self performSelectorOnMainThread:@selector(updateProgress:) withObject:nil waitUntilDone:NO];
        n = numTunes;
      }

      [line release];
      if ( b[i] == '\r' )
        lastWasCR = YES;
      start = i+1;
    }
  }
  if ( start != i ) {
    if ( fragment == nil )
      fragment = [[NSMutableString alloc] init];
    
    NSString *s = [[NSString alloc] initWithBytes:b+start length:i-start encoding:NSISOLatin1StringEncoding];
    if ( s == nil )
      s = [[NSString alloc] initWithBytes:b+start length:i-start encoding:NSUTF8StringEncoding];
    [fragment appendString:s];
    [s release];
  }
}

- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
  UIAlertView *alert = [[UIAlertView alloc] 
    initWithTitle: @"Import Failed"
    message:[error localizedDescription]
    delegate:self
    cancelButtonTitle:nil
    otherButtonTitles:@"OK", nil];
  [alert show];
	[connection release];
  [self dismissModalViewControllerAnimated:YES];
}

- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
  return nil;
}

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
  [parser parseLine:@""]; // Force the last tune to end
  [self performSelectorOnMainThread:@selector(finishedImport:) withObject:nil waitUntilDone:NO];
}

- (void) finishedImport:(id)sender
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  [appDelegate commitTransaction];

  NSString* filename = [[_url path] lastPathComponent];

  if ( statusCode >= 400 ) {
    UIAlertView *alert = [[UIAlertView alloc] 
      initWithTitle: @"Import Failed" 
      message:[NSString stringWithFormat:@"An error (%d) occurred when importing %@: %@", statusCode, filename, [NSHTTPURLResponse localizedStringForStatusCode:statusCode]]
      delegate:self 
      cancelButtonTitle:nil 
      otherButtonTitles:@"OK", nil]; 
    [alert show];
  } else if ( numTunes ) {
    UIAlertView *alert = [[UIAlertView alloc] 
      initWithTitle: cancelled ? @"Import Stopped" : @"Import Succeeded" 
      message:[NSString stringWithFormat:@"Imported %d tunes from %@.\nDo you want to create a tunebook with these tunes?", numTunes, filename]
      delegate:self 
      cancelButtonTitle:@"No"
      otherButtonTitles:@"Create", nil]; 
    [alert show];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"databaseChanged" object:self]; 
  } else {
    UIAlertView *alert = [[UIAlertView alloc] 
      initWithTitle: @"Import Failed" 
      message:[NSString stringWithFormat:@"The file %@ was imported, but appeared to contain no tunes.", filename]
      delegate:self 
      cancelButtonTitle:nil 
      otherButtonTitles:@"OK", nil]; 
    [alert show];
  }

  finished = true;
}

#pragma mark TuneParser delegate methods

-(void) parsedTune:(TuneParser *)parser tune:(Tune *)tune
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  [appDelegate addTune:tune];
  [parsedTunes addObject:tune];
  numTunes++;
}

#pragma mark UIAlertView delegate methods

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
  if ( buttonIndex == 1 && parsedTunes && [parsedTunes count] != 0 ) {
    Playlist *playlist = [[Playlist alloc] init];
    playlist.name = [[_url path] lastPathComponent];
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [appDelegate startTransaction];
    [appDelegate addPlaylist:playlist];
    for ( Tune* tune in parsedTunes )
      [playlist addTune:tune];
    [appDelegate commitTransaction];
    [parsedTunes release];
    parsedTunes = nil;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"playlistsChanged" object:self]; 
  }

  [self dismissModalViewControllerAnimated:animateDismiss];
  [[NSNotificationCenter defaultCenter] postNotificationName:@"importedFile" object:nil]; 
}

@end
