#import "Tune.h"
#import "TuneParser.h"
#import "NSString+HTML.h"

@implementation TuneParser

@synthesize delegate;

- (id)init {
  self = [super init];
  if ( self ) {
    tune = NULL;
    dots = NULL;
    bodyStarted = NO;
    lastWasBR = NO;
    isHTML = NO;
    firstCall = YES;
    finished = NO;
  }
  return self;
}

- (void) dealloc
{
  [dots release];
  [super dealloc];
}

- (void) parseString:(NSString *)data
{
  [self parseData:[data dataUsingEncoding:NSUTF8StringEncoding]];
}

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

  // Convert RTF data to plain text
  if ( strncmp( b, "{\\rtf", 5 ) == 0 ) {
    NSAttributedString* as = [[NSAttributedString alloc]initWithRTF:data documentAttributes:nil];
    NSString* s = [as string];
    [self parseString:s];
    [as release];
    return;
  }

  for ( int i = 0; i < length; i++ ) {
    if ( b[i] == '\r' || b[i] == '\n' || i == length-1 ) {
      if ( i == length-1 )
        i++;
      NSString *line = [[NSString alloc] initWithBytes:b+start length:i-start encoding:NSISOLatin1StringEncoding];
      [self parseLine:line];
      if ( finished )
        break;

      [line release];
      if ( b[i] == '\r' && i < length-1 && b[i+1] == '\n' )
        i++;
      start = i+1;
    }
  }
  [self parseLine:@""];
}

- (void) parseLine:(NSString *)line
{
  if ( finished )
    return;
//  printf("line: '%s'\n", [line UTF8String]);

  // All this stuff is to allow parsing of pages from www.thesession.org which has ABC embedded in HTML with spurious blank lines.
  if ( firstCall ) {
    firstCall = NO;
    if ( [line length] > 0 && [line characterAtIndex:0] == '<' )
      isHTML = YES;
  }
  if ( isHTML )
    line = [line stringByDecodingHTMLEntities];
  int length = [line length];
  if ( isHTML ) {
    line = [line stringByReplacingOccurrencesOfString:@"<br />" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [line length])];
    line = [line stringByReplacingOccurrencesOfString:@"<br>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [line length])];
    if ( [line compare:@"<div" options:NSCaseInsensitiveSearch range:NSMakeRange(0, 4)] == 0 )
      return;
    if ( bodyStarted && [line compare:@"</div>" options:0 range:NSMakeRange(0, 6)] == 0 ) {
      finished = YES;
      tune.dots = dots;
      if ( tune.title && dots )
        [delegate parsedTune:self tune:tune];
      [dots release];
      dots = NULL;
      tune = NULL;
      return;
    }
  }

  if ( !finished && [line compare:@"X:" options:0 range:NSMakeRange(0, 2)] == 0 ) {
    // Started a tune
    tune = [[Tune alloc] init];
    tune.title = NULL;
    tune.key = @"";
    tune.dots = NULL;
    dots = [[NSMutableString alloc] init];
    [dots appendString:@"X:1\n"];
    bodyStarted = NO;
    lastWasBR = NO;
  } else if ( dots ) {
    if ( [line compare:@"T:" options:0 range:NSMakeRange(0, 2)] == 0 ) {
      if ( !tune.title )
        tune.title = [Tune fixAccents:[[line substringFromIndex:2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
      [dots appendString:line];
      [dots appendString:@"\n"];
#if KEYWORDS
    } else if ( [line compare:@"r:" options:0 range:NSMakeRange(0, 2)] == 0 ) {
      if ( !tune.keyWords )
        tune.keyWords = [[line substringFromIndex:2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
      [dots appendString:line];
      [dots appendString:@"\n"];
#endif
    } else if ( [line compare:@"K:" options:0 range:NSMakeRange(0, 2)] == 0 ) {
      if ( !tune.key || [tune.key length] == 0 )
        tune.key = [[line substringFromIndex:2]
          stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]
        ];
      [dots appendString:line];
      [dots appendString:@"\n"];
    } else if ( [line compare:@"M:" options:0 range:NSMakeRange(0, 2)] == 0 ) {
      NSString *s = [[line substringFromIndex:2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
      const char *p = [s UTF8String];
      int n, d;
      if ( sscanf( p, "%d/%d", &n, &d ) == 2 ) {
        tune.timeSigNum = n;
        tune.timeSigDen = d;
      } else if ( *p == 'C' ) {
        if ( p[1] == '|' )
          tune.timeSigNum = tune.timeSigDen = 2;
        else
          tune.timeSigNum = tune.timeSigDen = 4;
      }
      [dots appendString:line];
      [dots appendString:@"\n"];
    } else if ( [line length] == 0 && bodyStarted ) {
//printf("%d: %s\n", numTunes, [tune.title UTF8String] );
      if ( !lastWasBR ) {
        tune.dots = dots;
        if ( tune.title && dots )
          [delegate parsedTune:self tune:tune];
        [dots release];
        dots = NULL;
        tune = NULL;
      }
      lastWasBR = NO;
    } else {
      if ( !([line length] > 1 && [[NSCharacterSet letterCharacterSet] characterIsMember:[line characterAtIndex:0]] && [line characterAtIndex:1] == ':') )
        bodyStarted = YES;
      [dots appendString:line];
      [dots appendString:@"\n"];
    }
  }
  lastWasBR = isHTML && [line length] != length;
}


@end

