//
//  MHWebInput.m
//  Hootenanny
//
//  Created by Noah Sorscher on 9/29/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "MHWebInput.h"


@implementation MHWebInput

MHWebInput *myself = nil;

- (void) init
{
	myself = self;
	[super init];
	//[[NSNotificationCenter defaultCenter]  addObserver:self selector:@selector(dragged:) name:@"mhDragNotification" object:nil];
}

+ (MHWebInput *)myself
{
	return myself;
}

- (void) notFound:(NSString *)s
{
	s = [NSString stringWithFormat:@"Sorry, I don't know the website: %@", s];
	NSString *alt = @"edit xml plist of known sites";
	NSAlert *alert = [NSAlert alertWithMessageText:@"Not Yet Supported" defaultButton:@"OK" alternateButton:alt otherButton:nil informativeTextWithFormat:s];
	int r = [alert runModal];
	if (r == NSAlertAlternateReturn) {
		s = [[NSBundle mainBundle] pathForResource:@"ikeys" ofType:@"xml"];
		[[NSWorkspace sharedWorkspace] openFile:s];
	}
}

- (void) movieStatus:(NSString *)s
{
	//NSLog(s);
	if ([[NSUserDefaults standardUserDefaults] objectForKey:@"noWebFeedback"]) return;
	MHMovie *movie = [controller currentMovie];
	[movie setStatus:s];
	[[controller mainTable] reloadData];
	[[controller summaryTable] reloadData];
	if ([s length] > 1) s = [[s substringFromIndex:1] retain];
	else s = nil;
	[self performSelector:@selector(movieStatus:) withObject:s afterDelay:0.1];
	[s performSelector:@selector(release) withObject:nil afterDelay:0.2];
}

- (void) cancelStatus
{
	[NSObject cancelPreviousPerformRequestsWithTarget:self];
}

- (BOOL) parse: (NSString *)s
{
	[self movieStatus:@"  Loading..."];
	[NSThread detachNewThreadSelector:@selector(parseT:) toTarget:self withObject:s];
	return YES;
}

- (void) parseT: (NSString *)s
{
	NSDictionary *dict = nil;
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	//NSString *htmlString = nil;
	if ([s hasPrefix:@"http://video.barnesandnoble.com"]) {
		NSArray *chList = [self getChaptersFromURL:s];
		if (chList && [chList count]) {
			[tChap setChapters:chList];
		}
	} else {
		dict = [self parseIMDB:s];
	}
	[self performSelectorOnMainThread:@selector(cancelStatus) withObject:nil waitUntilDone:NO];
	[[controller currentMovie] setStatus:nil];
	//NSLog(@"cancel");
	if (dict) {
		MHMovie *movie = [controller currentMovie];
		[self insertMetadata:dict intoMovie:movie];
		[[controller mainTable] performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
		[controller setCurrentMovie:movie];
		//[controller performSelectorOnMainThread:@selector(setCurrentMovie:) withObject:movie waitUntilDone:NO];
	}
	[pool release];
}

+ (NSString *)deHTML:(NSString *)input
{
    if (!input || ![input length]) return @"";
    NSScanner *scan = [NSScanner scannerWithString:input];
    NSMutableString *result = [NSMutableString string];
    [result setString:@""];
    NSString *buffer = nil;
    while (![scan isAtEnd]) {
        buffer = nil;
        [scan scanUpToString:@"<" intoString:&buffer];
        if (buffer)
            [result appendString:buffer];
        buffer = nil;
        [scan scanUpToString:@">" intoString:&buffer];
        [scan scanString:@">" intoString:nil];
        buffer = [buffer lowercaseString];
        if ([buffer isEqualToString:@"<br"] || [buffer isEqualToString:@"<p"])
            [result appendString:@"\n"];
        else
            [result appendString:@" "];
    }
    scan = [NSScanner scannerWithString:result];
    result = [NSMutableString string];
    while (![scan isAtEnd]) {
        buffer = nil;
        [scan scanUpToString:@"&" intoString:&buffer];
        if (buffer) {
            if ([buffer hasPrefix:@";"])
                buffer = [buffer substringFromIndex:1];
            [result appendString:buffer];
        }
        buffer = nil;
        [scan scanUpToString:@";" intoString:&buffer];
        buffer = [MHUtil getEscapeChar:buffer];
        if (buffer)
            [result appendString:buffer];
    }
    scan = [NSScanner scannerWithString:result];
    result = [NSMutableString string];
    [result setString:@""];
    NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet];
    while (![scan isAtEnd]) {
        buffer = nil;
        [scan scanUpToCharactersFromSet:set intoString:&buffer];
        if (buffer) {
            [result appendString:buffer];
            [result appendString:@" "];
        }
        if ([scan isAtEnd]) break;
        [scan setScanLocation:[scan scanLocation]+1];
    }
    [result deleteCharactersInRange:NSMakeRange([result length]-1, 1)];
    
    if ([result hasPrefix:@"\""] && [result hasSuffix:@"\""]) {
        [result deleteCharactersInRange:NSMakeRange(0, 1)];
        [result deleteCharactersInRange:NSMakeRange([result length]-1, 1)];
    }
    if ([result characterAtIndex:[result length]-2] == ' ')
        [result deleteCharactersInRange:NSMakeRange([result length]-2, 2)];
    if ([result hasSuffix:@" pc"])
        [result deleteCharactersInRange:NSMakeRange([result length]-3, 3)];
    int length = [result length];
    if (length <= 0)
        return @"";
    return [result whitespaceTrimmed];
}
/*
- (NSDictionary *)processEpisode:(NSString *)myAddress
{
	NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"EPGkeys"];
    if (!path)
        path = [[NSBundle mainBundle] pathForResource:@"EPGkeys" ofType:@"xml"];
    NSDictionary *keys = [NSDictionary dictionaryWithContentsOfFile:path];
    if (!keys) {
        NSLog(@"EPGkeys file mis-formed!");
        return;
    }
    keys = [[keys objectForKey:@"processEpisode"] objectForKey:@"ifURLContains"];
    NSMutableArray *allKeys = [NSMutableArray arrayWithArray:[keys allKeys]];
    if ([allKeys containsObject:@"*"]) {
        [allKeys removeObject:@"*"];
        [allKeys addObject:@"*"];
    }
    int i, n;
    for (i=0;i<[allKeys count];i++) {
        NSString *aKey = [allKeys objectAtIndex:i];
        if ([myAddress rangeOfString:aKey].length || [aKey isEqualToString:@"*"]) {
            keys = [keys objectForKey:aKey];
            break;
        }
    }
	/*
    NSString *regs = [self processRegulars:[keys objectForKey:@"regulars"]];
    if (regs) {
        NSString *perfs = [metadata objectForKey:@"Performers"];
        if (perfs && ![perfs isEqualToString:regs])
            regs = [NSString stringWithFormat:@"%@, %@", perfs, regs];
        [metadata setObject:regs forKey:@"Performers"];
    }* /
    NSString *buffer = nil;
    //NSString *htmlString = [MHEPGTVT cacheString:myAddress];
	NSString *htmlString = [NSString stringWithContentsOfURL:[NSURL URLWithString:myAddress]];
	if (!htmlString || ![[htmlString whitespaceTrimmed] hasPrefix:@"<"])
		htmlString = [NSString stringWithContentsOfCURL:[NSURL URLWithString:myAddress]];
    if (!htmlString) return;
    NSScanner *scan = [NSScanner scannerWithString:htmlString];
    [scan setCaseSensitive:NO];
    /*
	 NSDictionary *link = [keys objectForKey:@"link"];
	 if (link) {
	 buffer = nil;
	 NSArray *skip = [link objectForKey:@"skip"];
	 NSString *end = [link objectForKey:@"end"];
	 n = [skip count];
	 for (i=0;i<n;i++)
	 [scan scanPastString:[skip objectAtIndex:i]];
	 if (end)
	 [scan scanUpToString:end intoString:&buffer];
	 if (buffer) {
	 NSString *newAddress = [link objectForKey:@"address"];
	 if (newAddress)
	 buffer = [NSString stringWithFormat:newAddress, buffer];
	 myAddress = buffer;
	 htmlString = [MHEPGTVT cacheString:myAddress];
	 }
	 }
	 * /
    NSArray *pieces = [myAddress componentsSeparatedByString:@"#"];
    NSRange r;
    if ([pieces count] == 2) {
        scan = [NSScanner scannerWithString:htmlString];
        [scan setCaseSensitive:NO];
        while (![scan isAtEnd]) {
            [scan scanPastString:@"<a"];
            [scan scanUpToString:@">" intoString:&buffer];
            r = [buffer rangeOfString:@"name" options:NSCaseInsensitiveSearch];
            if (r.length) {
                r = [buffer rangeOfString:[pieces objectAtIndex:1]];
                if (r.length) {
                    htmlString = [htmlString substringFromIndex:[scan scanLocation]];
                    break;
                }
            }
        }/*
        if ([scan isAtEnd]) { // didn't find our # link!  might be a typo in the <a name=> link.  look for the name
            NSString *name = [metadata objectForKey:@"Full Name"];
            if (name) {
                [scan setScanLocation:0];
                [scan scanUpToString:name intoString:nil];
                if (![scan isAtEnd]) {
                    int location = [scan scanLocation];
                    if (location > 5)
                        location -= 4; // go back before the last >
                    htmlString = [htmlString substringFromIndex:location];
                }
            }
        }* /
        if (![scan isAtEnd] && [[keys objectForKey:@"name2name"] boolValue]) {
            scan = [NSScanner scannerWithString:htmlString];
            [scan setCaseSensitive:NO];
            while (![scan isAtEnd]) {
                [scan scanUpToString:@"<a" intoString:nil];
                unsigned loc = [scan scanLocation];
                [scan scanUpToString:@">" intoString:&buffer];
                r = [buffer rangeOfString:@"name" options:NSCaseInsensitiveSearch];
                if (r.length) {
                    int letter = r.location + r.length;
                    char ch = [buffer characterAtIndex:letter];
                    while ((' ' == ch || '\t' == ch) && letter < [buffer length] - 1)
                        ch = [buffer characterAtIndex:++letter];
                    if ('=' == ch) {
                        ch = [buffer characterAtIndex:r.location - 1];
                        if ([[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:ch]) {
                            htmlString = [htmlString substringToIndex:loc];
                            break;
                        }
                    }
                }
            }
        }
    }
    if ([keys objectForKey:@"trimAfter"]) {
        r = [htmlString rangeOfString:[keys objectForKey:@"trimAfter"] options:NSBackwardsSearch];
        if (r.length)
            htmlString = [htmlString substringToIndex:r.location];
    }
    scan = [NSScanner scannerWithString:htmlString];
    [scan setCaseSensitive:NO];
    NSArray *sequence = [keys objectForKey:@"sequence"];
    n = [sequence count];
	NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    for (i=0;i<n;i++) {
        NSString *test = [[scan string] substringFromIndex:[scan scanLocation]];
        NSString *item = [sequence objectAtIndex:i];
        if ([item isEqualToString:@"skip"])
            [scan scanPastString:[sequence objectAtIndex:++i]];
        else if ([item hasPrefix:@"scanTo:"]) {
            item = [item substringFromIndex:7];
            NSString *buffer = nil;
            test = [sequence objectAtIndex:i+1];
            [scan scanUpToString:[sequence objectAtIndex:++i] intoString:&buffer];
            buffer = [MHWebInput deHTML:buffer];
            if (buffer && [buffer length]) {
                if ([item isEqualToString:@"Performers"])
                    buffer = [self fixPerfs:buffer];
                if ([item isEqualToString:@"Product"] && [buffer hasPrefix:@"____"])
                    buffer = nil;
                if ([buffer length])
                    [dict setObject:buffer forKey:item];
            }
        } else if ([item isEqualToString:@"return"])
            [scan setScanLocation:0];
        else if ([item isEqualToString:@"newCap"]) {
            NSString *string = [scan string];
            NSString *newCap = [sequence objectAtIndex:++i];
            NSRange r = [string rangeOfString:newCap];
            unsigned loc = [scan scanLocation];
            if (r.location != NSNotFound) {
                string = [string substringToIndex:r.location];
                if (loc >= [string length])
                    loc = [string length] - 1;
                scan = [NSScanner scannerWithString:string];
                [scan setCaseSensitive:NO];
                [scan setScanLocation:loc];
            }
        }
    }
	return dict;
}
*/
- (NSDictionary *)parseChapter:(NSString *)input
{
    NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"BBkeys"];
    if (!path)
        path = [[NSBundle mainBundle] pathForResource:@"BBkeys" ofType:@"xml"];
    NSDictionary *keys = [[[NSDictionary dictionaryWithContentsOfFile:path] objectForKey:@"chapters"] objectForKey:@"chaps"];
    if (!keys) {
        NSLog(@"BBKeys file mis-formed!");
        return nil;
    }
    //NSLog(@"tWWW parseChapter:");
    if (input == nil || ![input isKindOfClass:[NSString class]]) return nil;
    NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:3];
    // Time Length
    const char *cString = [input cString];
    char ch, timeStart = [[keys objectForKey:@"time start"] characterAtIndex:0], timeStop = [[keys objectForKey:@"time stop"] characterAtIndex:0], trim = [[keys objectForKey:@"trim"] characterAtIndex:0];
    int total, colTal, dig, i, n = [input length];
    total = colTal = dig = 0;
    BOOL timeOn = NO;
    for (i=n-1; i>=0; i--) {
        ch = cString[i];
        if (timeOn && ch >= '0' && ch <= '9')
            total += (ch - '0') * [MHUtil expon:10 toThe:dig++] * [MHUtil expon:60 toThe:colTal];
        else if (timeOn && ch == ':') {
            dig = 0;
            colTal++;
        } else if (ch == timeStop)
            timeOn = YES;
        else if (ch == timeStart)
            break;
    }
    //[result setObject:[NSNumber numberWithLong:samples] forKey:@"Start"];
    [result setObject:[NSNumber numberWithInt:total] forKey:@"nSeconds"];
    // Text
    if (i<=0) i=n;
    for (i--; i>=0; i--) {
        if (cString[i] != trim) break;
    }
    NSString *s = [NSString stringWithCString:cString length:i+1];
    NSRange aRange = [s rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\r\n"]];
    if (aRange.location != NSNotFound)
        s = [s substringToIndex:aRange.location];
    s = [MHUtil fixIMDB:s];
    [result setObject:s forKey:@"Content"];
    return result;
}

- (void) addTimes:(NSArray *)chaps
{
	int i, total = 0, n = [chaps count];
	NSMutableDictionary *dic = nil;
	for (i=0;i<n;i++) {
		dic = [chaps objectAtIndex:i];
		[dic setObject:[NSNumber numberWithInt:total] forKey:@"Start"];
		total += [[dic objectForKey:@"nSeconds"] intValue];
	}
	if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"chapScale"] boolValue]) {
		double seconds = [[controller currentMovie] durationSeconds];
		if (!seconds) return;
		double scalar = seconds / (double) total;
		n = [chaps count];
		for (i=0;i<n;i++) {
			dic = [chaps objectAtIndex:i];
			seconds = [[dic objectForKey:@"Start"] doubleValue];
			seconds *= scalar;
			[dic setObject:[NSNumber numberWithDouble:seconds] forKey:@"Start"];
		}
	}
}

- (NSArray *)getChaptersFromURL:(NSString *)address
{
    NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"BBkeys"];
    if (!path)
        path = [[NSBundle mainBundle] pathForResource:@"BBkeys" ofType:@"xml"];
    NSDictionary *keys = [NSDictionary dictionaryWithContentsOfFile:path];
    if (!keys) {
        NSLog(@"BBKeys file mis-formed!");
        return NO;
    }
	
    if (!address) return nil;
    //NSLog(@"tWWW getChaptersFromURL:");
    NSString *buffer, *htmlString = nil;
    //BOOL valid = NO;
    htmlString = [NSString stringWithContentsOfURL:[NSURL URLWithString:address]];
    //if (!htmlString)
    //    htmlString = [NSString stringWithContentsOfCURL:[NSURL URLWithString:address]];
    if (nil == htmlString)
		return nil;
	
    htmlString = [MHUtil newLines:htmlString];
    NSScanner *scan = [NSScanner scannerWithString:htmlString];
    [scan setCaseSensitive:NO];
    NSDictionary *chapters = [keys objectForKey:@"chapters"];
    NSArray *skip = [chapters objectForKey:@"skip"];
    int i, n = [skip count];
    for (i=0;i<n;i++)
        [scan scanPastString:[skip objectAtIndex:i]];
    //[scan scanUpToString:@"<!-- begin dvd features" intoString:nil];
    NSMutableArray *chapterList = [[[NSMutableArray alloc] init] retain];
    int strikes = 0, start = [scan scanLocation];
    NSDictionary *dict = [chapters objectForKey:@"chaps"];
    NSMutableArray *strings = [NSMutableArray array];
    NSArray *sKeys = [NSArray arrayWithObjects:@"cue", @"end", @"time start", @"time stop", @"trim", nil];
    n = [sKeys count];
    for (i=0;i<n;i++) {
        buffer = [dict objectForKey:[sKeys objectAtIndex:i]];
        if (!buffer) {
            NSLog(@"BBkeys.xml -> chapters -> chaps -> %@  not found", [sKeys objectAtIndex:i]);
            return nil;
        }
        [strings addObject:buffer];
    }
	
    i=1;
    while (strikes < 5) {
        buffer = nil;
        [scan setScanLocation:start];
        [scan scanUpToString:[NSString stringWithFormat:[strings objectAtIndex:0], i++] intoString:nil];
        char ch = [[scan string] characterAtIndex:[scan scanLocation]-1];
        if (ch < '1' || ch > '9')
            [scan scanUpToString:[strings objectAtIndex:1] intoString:&buffer];
        if (nil != buffer) {
            NSDictionary *aChapter = [self parseChapter:buffer];
            if (aChapter) {
                [chapterList addObject:aChapter];
            }
        }
        if ([scan isAtEnd])
            strikes++;
        else
            strikes = 0;
    }
	[self addTimes:chapterList];
    return chapterList;
}

- (NSString *)pickName:(NSString *)name fromHTML:(NSString *)htmlString
{
	NSScanner *scan = [NSScanner scannerWithString:htmlString];
	[scan setCaseSensitive:NO];
	[scan setCharactersToBeSkipped:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
	NSString *buffer = nil;
	NSRange foundRange;
	foundRange.location = NSNotFound;
	foundRange.length = 0;
	
	while (![scan isAtEnd]) {
		[scan scanPastString:@"<a"];
		[scan scanUpToString:@">" intoString:&buffer];
		NSRange r = [buffer rangeOfString:@"name" options:NSCaseInsensitiveSearch];
		if (r.location != NSNotFound) {
			r = [buffer rangeOfString:name options:NSCaseInsensitiveSearch];
			if (r.location != NSNotFound) {
				while (![scan isAtEnd]) {
					foundRange.location = [scan scanLocation];
					[scan scanPastString:@"<a"];
					[scan scanUpToString:@">" intoString:&buffer];
					r = [buffer rangeOfString:@"name" options:NSCaseInsensitiveSearch];
					if (r.location != NSNotFound) {
						foundRange.length = [scan scanLocation] - foundRange.location;
						break;
					}
				}
				break;
			}
		}
	}
	if (foundRange.length)
		return [htmlString substringWithRange:foundRange];
	return htmlString;
}

- (NSMutableDictionary *)parseIMDB:(NSString *)link
{
	//NSError *err = nil;
	NSString *input = [NSString stringWithContentsOfURL:[NSURL URLWithString:link]]; //encoding:NSUTF8StringEncoding error:&err];
	//if (err) NSLog(@"%@",err);
    NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"ikeys"];
    if (!path) path = [[NSBundle mainBundle] pathForResource:@"ikeys" ofType:@"xml"];
    NSDictionary *keys = [NSDictionary dictionaryWithContentsOfFile:path];
    if (!keys) NSLog(@"ikeys file mis-formed!\n");
    
    if (input == nil) return nil;
	/*
    NSString *confirm = [keys objectForKey:@"confirm"];
    if (confirm) {
        NSRange aRange = [input rangeOfString:confirm];
        if (aRange.location == NSNotFound) {
            NSLog(@"Confirmation String: \"%@\" Not Found", confirm);
            return nil;
        }
    }
	 */
	NSArray *options = [keys allKeys];
	int i, n = [options count];
	for (i=0;i<n;i++) {
		NSString *anOption = [options objectAtIndex:i];
		if ([link containsString:anOption]) {
			keys = [keys objectForKey:anOption];
			break;
		}
	}
	if (i == n) {
		[self performSelectorOnMainThread:@selector(notFound:) withObject:link waitUntilDone:NO]; 
		return nil;
	}
	if ([[keys objectForKey:@"name2name"] boolValue]) {
		NSRange r = [link rangeOfString:@"#" options:NSBackwardsSearch];
		if (r.location != NSNotFound) {
			NSString *name = [link substringFromIndex:r.location+1];
			input = [self pickName:name fromHTML:input];
		}
	}
	
	NSMutableDictionary *dict = [self parseString:input usingKeys:keys];
	if ([keys objectForKey:@"link"]) {
		keys = [keys objectForKey:@"link"];
		NSString *nLink = [keys objectForKey:@"absolute"];
		if (!nLink) nLink = [keys objectForKey:@"relative"];
		if (nLink) {
			nLink = [[NSURL URLWithString:nLink relativeToURL:[NSURL URLWithString:link]] absoluteString];
			if (nLink) {
				input = [NSString stringWithContentsOfURL:[NSURL URLWithString:nLink]];
				if (input) {
					[dict addEntriesFromDictionary:[self parseString:input usingKeys:keys]];
				}
			}
		}
	}
	[dict setObject:link forKey:@"Website"];
	return dict;
}

- (NSMutableDictionary *)parseString:(NSString *)input usingKeys:(NSDictionary *)keys
{
    NSMutableDictionary *theResult = [[NSMutableDictionary alloc] init];
    NSScanner *scan = [[NSScanner alloc] initWithString:input];
    [scan setCaseSensitive:NO];
    NSString *buffer, *name, *skip, *end, *endend, *value;
    NSDictionary *cat;
    NSNumber *repeating;
    NSArray *cats = [keys objectForKey:@"categories"];
    int i, j, k, m, n = [cats count];
    for (i=0;i<n;i++) {
        [scan setScanLocation:0];
        buffer = name = skip = end = endend = value = nil;
        cat = [cats objectAtIndex:i];
        name = [cat objectForKey:@"name"];
        end = [cat objectForKey:@"end"];
		endend = [cat objectForKey:@"endend"];
        repeating = [cat objectForKey:@"repeating"];
        m = [[cat objectForKey:@"skip"] count];
        for (j=0;j<m;j++)
            [scan scanPastString:[[cat objectForKey:@"skip"] objectAtIndex:j]];
		int tooFar = [input length]-2;
		if (endend) {
			int start = [scan scanLocation];
			[scan scanUpToString:endend intoString:nil];
			tooFar = [scan scanLocation];
			[scan setScanLocation:start];
		}
        while (![scan isAtEnd]) {
			buffer = nil;
            [scan scanUpToString:end intoString:&buffer];
			if ([scan scanLocation] > tooFar) break;
            buffer = [MHUtil fixIMDB:buffer];
            if (value && [value length]) {
				if ([buffer length])
					value = [NSString stringWithFormat:@"%@, %@", value, buffer];
            } else {
                value = buffer;
			}
            if (!repeating) break;
            k = [repeating intValue];
            for (j-=k; j<m; j++)
                [scan scanPastString:[[cat objectForKey:@"skip"] objectAtIndex:j]];
        }
		if ([value hasPrefix:@"\""] && [value hasSuffix:@"\""] && [value length] > 1)
			value = [value substringWithRange:NSMakeRange(1, [value length]-2)];
		if ([value hasPrefix:@"Season"]) {
			int se = -1, ep = -1;
			NSScanner *tscan = [[NSScanner alloc] initWithString:value];
			[tscan setCaseSensitive:NO];
			[tscan scanString:@"Season" intoString:nil];
			[tscan scanInt:&se];
			[tscan scanString:@"," intoString:nil];
			[tscan scanString:@"Episode" intoString:nil];
			[tscan scanInt:&ep];
			if (se != -1 && ep != -1)
				value = [NSString stringWithFormat:@"Season %.2d, Episode %.2d", se, ep];
			[tscan release];
		}
        if (value)
            [theResult setObject:value forKey:name];
    }
    [scan release];
    return theResult;
}

- (BOOL)keyIsGood:(NSString *) key
{
    //NSLog(@"tWWW keyIsGood");
    NSArray *bad = [NSArray arrayWithObjects:@"title", @"code", @"dl", @"address", nil];
    NSArray *good = [NSArray arrayWithObjects:@"Album", @"Author", @"Copyright", @"Creation Date", @"Full Name", @"Description", @"Director", @"Information", @"Performers", @"Product", @"Writer", @"Genre", @"Website", @"Cover Image", @"Rating", nil];
    NSArray *preferences = [NSArray arrayWithObjects:t_album, t_author, t_copy, t_credate, t_fname, t_desc, t_dir, t_info, t_perf, t_prod, t_writ, @"optGenre", @"optWebsite", @"optIcon", @"optRating", nil];
	//NSArray *preferences = [NSArray arrayWithObjects:optAlbum, optAuthor, optCopy, optCreDate, optFName, optDesc, optDir, optInfo, optPerf, optProd, optWrit, optGenre, optWebsite, optIcon, optRating, optIcon, nil];
    int i, n = [bad count];
    if (key == nil) return NO;
    for (i=0;i<n;i++) {
        if ([key isEqualToString:[bad objectAtIndex:i]]) return NO;
    }
    n = [good count];
    for (i=0;i<n;i++) {
        if ([key isEqualToString:[good objectAtIndex:i]])
            return [tInit boolForKey:[preferences objectAtIndex:i]];
    }
    return YES;
}


- (BOOL)checkString:(NSString *)s
{
    return (nil != s && [s isKindOfClass:[NSString class]] && ![s isEqualToString:@""]);
}

- (NSString *)mergeThis:(NSString *)this that:(NSString *)that
{
    //NSLog(@"tWWW mergeThis:that");
    BOOL trueThis, trueThat;
    trueThis = [self checkString:this];
    trueThat = [self checkString:that];
    if (!trueThis && !trueThat) return @"";
    if (!trueThis) return [that copy];
    if (!trueThat) return [this copy];
    
    if ([this isEqualToString:that]) return [this copy];
    NSRange aRange;
    NSArray *a = [that componentsSeparatedByString:@", "];
    NSString *buffer;
    NSMutableString *output = [NSMutableString stringWithCapacity:[this length] + [that length]];
    [output appendString:this];
    int i, n = [a count];
    for (i=0;i<n;i++) {
        buffer = [a objectAtIndex:i];
        aRange = [this rangeOfString:buffer options:NSCaseInsensitiveSearch];
        if (aRange.length == 0) {
            [output appendString:@", "];
            [output appendString:buffer];
        }
    }
    return output;
}


- (NSString *)uninvert:(NSString *)input
{
    NSArray *sufs = [NSArray arrayWithObjects:@", the", @", a", @", an", nil];
    int i, n = [sufs count];
    for (i=0;i<n;i++) {
	if ([[input lowercaseString] hasSuffix:[sufs objectAtIndex:i]]) {
	    int length = [input length], elength = [(NSString *)[sufs objectAtIndex:i] length];
	    NSString *end = [input substringFromIndex:length - elength + 2];
	    input = [input substringToIndex:length - elength];
	    return [NSString stringWithFormat:@"%@ %@", end, input];
	}
    }
    return input;
}

- (NSString *)reduce:(NSString *)input
{
    NSArray *names = [input componentsSeparatedByString:@","];
    NSMutableArray *uNames = [NSMutableArray array];
    int i, n = [names count];
    for (i=0;i<n;i++) {
	NSString *aName = [names objectAtIndex:i];
	NSRange aRange = [aName rangeOfString:@"("];
	NSRange bRange = [aName rangeOfString:@")"];
	if (aRange.length && bRange.length && bRange.location > aRange.location) {
	    NSMutableString *mName = [NSMutableString stringWithString:aName];
	    aRange.length = bRange.location - aRange.location + 1;
	    [mName deleteCharactersInRange:aRange];
            [mName replaceOccurrencesOfString:@"  " withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [mName length]-1)];
	    aName = [mName whitespaceTrimmed];
            if ([aName hasSuffix:@" &"]) aName = [aName substringToIndex:[aName length]-2];
            else if ([aName hasSuffix:@" and"]) aName = [aName substringToIndex:[aName length]-4];
	}
	if (![uNames containsObject:aName])
	    [uNames addObject:[aName whitespaceTrimmed]];
    }
    return [uNames componentsJoinedByString:@", "];
}

- (void)insertMetadata:(NSDictionary *)metadata intoMovie:(MHMovie *)aMovie
{
    //int num = [metadata count];
    NSArray *keys = [metadata allKeys];
    NSString *key, *value;
    int i, j, m, n = [keys count];
    NSString *fn = nil;
	BOOL merging = [tInit boolForKey:@"merge"];
    for (i=0;i<n;i++) {
        key = [keys objectAtIndex:i];
        if ([self keyIsGood:key]) {
            value = [[metadata objectForKey:key] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
            if ([tInit boolForKey:@"optReduce"])
                value = [self reduce:value];
            if ([key isEqualToString:@"Performers"]) {
                NSScanner *scan = [NSScanner scannerWithString:value];
                m = [[[NSUserDefaults standardUserDefaults] objectForKey:t_numPerformers] intValue];
				if (!m) m = 5;
                for (j=0;j<m;j++)
                    [scan scanPastString:@", "];
                if (![scan isAtEnd])
                    value = [value substringToIndex:[scan scanLocation]-2];
				// regulars
				NSDictionary *webRegs = [[NSUserDefaults standardUserDefaults] objectForKey:@"webRegs"];
				NSString *regs = [metadata objectForKey:@"Author"];
				if (regs) {
					regs = [webRegs objectForKey:regs];
					if (regs) {
						value = [regs stringByAppendingFormat:@", %@", value];
					}
				}
            } else if ([key isEqualToString:@"Full Name"]) {
				fn = value;
				value = [self uninvert:value];
				if ([tInit boolForKey:@"filename"]) {
					NSString *name = [value stringByAppendingString:@".mov"];
					if ([metadata objectForKey:@"Product"]) name = [NSString stringWithFormat:@"%@ %@", [metadata objectForKey:@"Product"], name];
					[aMovie setObject:name forKey:@"File Name"];
				}
			}
			if ([key isEqualToString:@"Cover Image"]) {
				NSString *path = [MHUtil supportDir];
				path = [path stringByAppendingPathComponent:[aMovie stringValue]];
				path = [path stringByAppendingString:@".jpg"];
				path = [MHUtil uniquePath:path];
				if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
                    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:value]];
                    [data writeToFile:path atomically:NO];
                }
				[aMovie setImageFile:path];
			} else if (merging) {
				NSString *oldValue = [aMovie objectForKey:key];
				value = [self mergeThis:value that:oldValue];
            }
            [aMovie setObject:value forKey:key language:@"English"];
        }
    }
	
    if ([tInit boolForKey:t_comment])
        [aMovie setObject:[tInit stringForKey:t_commentText] forKey:@"Comment" language:@"English"];
}



@end
