/* Copyright (c) 2004, Noah Sorscher
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 	¥ 	Redistributions of source code must retain the above copyright
 * 	notice, this list of conditions and the following disclaimer.
 * 	¥ 	Redistributions in binary form must reproduce the above copyright
 * 	notice, this list of conditions and the following disclaimer in the
 * 	documentation and/or other materials provided with the distribution.
 * 	¥ 	Neither the name of the Noah Sorscher nor the names of its
 * 	contributors may be used to endorse or promote products derived from
 * 	this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
#import "tPlaylist.h"
#include "Movies.h"
#include "random.h"
#include "defaults.h"
#include "tController.h"
#include "tChapters.h"
#include "tInit.h"
#import "SortingDelegate.h"
#import "imageFileView.h"
#import "ImageCompare.h"
#import "PlaylistController.h"


@interface NSTableView (animated)
- (NSRect)unanimatedRectOfRow:(int)rowIndex;
- (void)setSorting:(BOOL)flag;
- (void)stopAnimating;
@end

@interface NSString (contains)
- (BOOL) containsString:(NSString *)searchString;
@end

@implementation NSString (contains)
- (BOOL) containsString:(NSString *)searchString
{
	NSRange r = [self rangeOfString:searchString options:NSCaseInsensitiveSearch];
    if (r.location == NSNotFound)
		return NO;
	return YES;
}
@end

@interface NSArray (extras)
- (BOOL) isEqualToString:(NSString *)string;
- (BOOL) containsString:(NSString *)searchString;
- (BOOL) hasPrefix:(NSString *)searchString;
- (BOOL) hasSuffix:(NSString *)searchString;
@end

@implementation NSArray (extras)
- (BOOL) isEqualToString:(NSString *)string
{
    return NO;
}
- (BOOL) containsString:(NSString *)searchString
{
    if (!searchString) return NO;
    int i, n = [self count];
    for (i=0;i<n;i++) {
        if ([[[self objectAtIndex:i] description] containsString:searchString])
            return YES;
    }
    return NO;
}
- (BOOL) hasPrefix:(NSString *)searchString
{
    if (!searchString) return NO;
    int i, n = [self count];
    for (i=0;i<n;i++) {
        if ([[[[self objectAtIndex:i] description] lowercaseString] hasPrefix:[searchString lowercaseString]])
            return YES;
    }
    return NO;
}
- (BOOL) hasSuffix:(NSString *)searchString
{
    if (!searchString) return NO;
    int i, n = [self count];
    for (i=0;i<n;i++) {
        if ([[[[self objectAtIndex:i] description] lowercaseString] hasSuffix:[searchString lowercaseString]])
            return YES;
    }
    return NO;
}
@end

@interface tPlaylist (private)

- (NSSet *) saveSelectionFromTable:(NSTableView *)inTableView;
- (void) restoreSelection:(NSSet *)inSelectedItemNums toTable:(NSTableView *)inTableView refresh:(BOOL)inRefresh;
- (void)tableView:(NSTableView *)inTableView animateSortFromArray:(NSArray *)fromArray toArray:(NSArray *)toArray;
- (BOOL)word:(NSString *)word forMovie:(MHMovie *)movie;
@end

@implementation tPlaylist


int compareUD(id movieT1, id movieT2, void *theString);


static NSString *specialCategories = @"Audio Bitrate,Audio Channels,Audio Format,Audio Sample Rate,File Creation Date,File Modification Date,File Path,File Size,Movie Length,Video Bitrate,Video Format,Video Height,Video Width,Correct Width,Correct Height,FPS,Source Name,Timecode,Video FourCC,Video Vendor";

NSArray *theNonCategories;
NSArray *theSpecialCategories;

//BOOL recursion = NO;
/*BOOL didDelete = NO;

+ (void)backSpace
{
    didDelete = YES;
}
*/
+ (NSArray *)supportedData
{
    return [specialCategories componentsSeparatedByString:@","];
}

- (NSArray *)supportedData
{
    return [[self class] supportedData];
}

- (void)textDidChange:(NSNotification *)aNotification
{
    //NSLog(@"textDidChange");
    if (recursion) return;
    NSTextView *box = [aNotification object];
    /*
    if (didDelete) {
        didDelete = NO;
        return;
    }
    */
    if (![tInit boolForKey:@"autoComplete"]) return;
    NSString *item, *item2, *string = [NSString stringWithString:[box string]];
    NSRange selection = [box selectedRange];
    int initialLength = [string length];
    if ([string isEqualToString:@""] || [string hasSuffix:@", "] || selection.location != initialLength) return;
    NSRange aRange = [string rangeOfString:@", " options:NSBackwardsSearch];
    if (aRange.length != 0)
        string = [string substringFromIndex:aRange.location+2];
    NSArray *list = [[[NSUserDefaults standardUserDefaults] objectForKey:@"learned"] objectForKey:editingType];
    if (!list) return;
    int i;
    recursion = YES;
    for (i=[list count]-1;i>=0;i--) {
        item = [list objectAtIndex:i];
        item2 = [item stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
        if ([item2 hasPrefix:string])
            item = item2;
        else if (![item hasPrefix:string])
            item = nil;
        if (item) {
            item = [item substringFromIndex:[string length]];
            [box insertText:item];
            selection.length = [item length];
            [box setSelectedRange:selection];
            break;
        }
    }
    recursion = NO;
}

- (tPlaylist *)initWithController:(id)aController
{
    //NSLog(@"tPlaylist initWithController");
    self = [super init];
    recursion = NO;
    theMovies = [[NSMutableArray alloc] init];
    theShuffledMovies = theSortedMovies = nil;
    sortedString = nil;
    theSpecialCategories = [specialCategories componentsSeparatedByString:@","];
    [theSpecialCategories retain];
    
    controller = aController;
    totalLength = totalSize = NumberOfFiles = currentPlayingIndex = lastSelectedRow = shouldEditVariable = lastClickedColumn = 0;
    name = @"";
    
    wontChange = NO;
    editingType = uneditedString = nil;
    sortingDelegate = nil;
    myOptions = nil;
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshImage) name:@"movieLanguageChangedNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(performLiveUpdate:) name:@"liveUpdateNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(multiEdit:) name:@"movieEditNotification" object:nil];
    
    return self;
}

- (NSString *)stringValue
{
    return name;
}

- (NSString *)name
{
    return name;
}

- (NSString *)description
{
    return name;
}

- (NSString *)sortedString
{
	return sortedString;
}

- (int)count
{
    return [theMovies count];
}

- (int)currentPlayingIndex
{
    return currentPlayingIndex;
}

- (void)setCurrentPlayingIndex:(int)index
{
    if (index >=0 && index < [self count]) {
        currentPlayingIndex = index;
        [[[[controller mainTable] tableColumnWithIdentifier:@"Order"] dataCell] setImageRow:index];
    } else
        currentPlayingIndex = 0;
}

- (MHMovie *)currentPlayingMovie
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (!array || ![array count]) return nil;
    
    if (currentPlayingIndex < 0 || currentPlayingIndex >= [array count]) currentPlayingIndex = 0;
    MHMovie *movie = [array objectAtIndex:currentPlayingIndex];
    return movie;
}

- (void)setCurrentPlayingMovie:(MHMovie *)movie
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (!array || ![array count]) return;
    
    [self setCurrentPlayingIndex:[array indexOfObject:movie]];
}

- (void)setName:(NSString *)aName
{
    name = [aName copy];
}

- (NSDictionary *)defsEntry
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    NSMutableArray *movies = [NSMutableArray array];
    [dict setObject:movies forKey:@"movieData"];
    [dict setObject:name forKey:@"name"];
    if (sortedString) [dict setObject:sortedString forKey:@"sortedString"];
    int i, n = [theMovies count];
    for (i=0;i<n;i++) {
        [movies addObject:[(MHMovie *)[theMovies objectAtIndex:i] defsEntry]];
    }
    if (myOptions)
        [dict setObject:myOptions forKey:@"options"];
    return dict;
}

- (NSArray *)addFromDefsEntry:(NSArray *)entries
{
    MHMovie *aMovie;
    int i, n = [entries count];
    NSMutableArray *array = [NSMutableArray array];
    for (i=0;i<n;i++) {
        aMovie = [[[MHMovie alloc] initWithDefaultsEntry:[entries objectAtIndex:i]] autorelease];
        if (nil != aMovie) {
            [self addMovie:aMovie];
            [array addObject:aMovie];
        }
    }
    return array;
}

- (void)replaceMovie:(MHMovie *)oldMovie withMovie:(MHMovie *)newMovie
{
    if (!newMovie) return;
    int index = [theMovies indexOfObject:oldMovie];
    if (index == NSNotFound) index = [theMovies count];
    else {
        [theMovies removeObjectAtIndex:index];
    }
    [theMovies insertObject:newMovie atIndex:index];
    [controller setCurrentMovie:newMovie];
}

- (NSComparisonResult)compareThis:(id)this toThat:(NSString *)that
{
    if ([this isKindOfClass:[NSString class]])
        return [this caseInsensitiveCompare:that];
    if ([this isKindOfClass:[NSNumber class]])
        return [(NSNumber *)this compare:[NSNumber numberWithDouble:[that doubleValue]]];
    if ([this isKindOfClass:[NSDate class]])
        return [(NSDate *)this compare:[NSDate dateWithNaturalLanguageString:that]];
    return NSOrderedSame;
}

- (BOOL)fitCondition:(NSString *)condition withMovie:(MHMovie *)movie
{
	if ([condition hasPrefix:@"All Edited Movies"])
		return [movie isEdited];
    NSArray *comps = [condition componentsSeparatedByString:@"|"];
    if ([comps count] != 3) return NO;
    NSString *cat = [comps objectAtIndex:0];
    NSString *con = [comps objectAtIndex:1];
    NSString *val = [comps lastObject];
    NSString *value = [movie objectForKey:cat];
    NSString *desc = [value description];
    if ([cat isEqualToString:@"Chapters"])
        desc = [[movie chapters] description];
    else if ([cat isEqualToString:@"Text Tracks"])
        desc = (NSString *)[movie tracksOfType:@"Text"];  // so be careful!  this is an array not a string, so only call things we cheated in up there --^
	if ([con isEqualToString:@"Contains"]) {
        if (desc && [desc containsString:val])
            return YES;
    } else if ([con isEqualToString:@"Does Not Contain"]) {
        if (!desc || ![desc containsString:val])
            return YES;
    } else if ([con isEqualToString:@"Is"]) {
        if (desc && [desc isEqualToString:val])
            return YES;
    } else if ([con isEqualToString:@"Is Not"]) {
        if (!desc || ![desc isEqualToString:val])
            return YES;
    } else if ([con isEqualToString:@"Starts With"]) {
        if (desc && [desc hasPrefix:val])
            return YES;
    } else if ([con isEqualToString:@"Ends With"]) {
        if (desc && [desc hasSuffix:val])
            return YES;
    } else if ([con isEqualToString:@"Is Higher Than"]) {
        if (value && [self compareThis:value toThat:val] == NSOrderedDescending)
            return YES;
    } else if ([con isEqualToString:@"Is Lower Than"]) {
        if (value && [self compareThis:value toThat:val] == NSOrderedAscending)
            return YES;
    }
    return NO;
}

- (NSArray *)moviesFromFolder:(NSString *)dirPath orArray:(NSMutableArray *)oldMovies
{
    BOOL isDir = NO;
    NSArray *files = [[NSFileManager defaultManager] directoryContentsAtPath:dirPath];
    NSMutableArray *newMovies = [NSMutableArray array];
    int i, n = [files count];
    for (i=0;i<n;i++) {
        NSString *path = [dirPath stringByAppendingPathComponent:[files objectAtIndex:i]];
        if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && !isDir) {
            int j, m = [oldMovies count];
            for (j=0;j<m;j++) {
                MHMovie *movie = [oldMovies objectAtIndex:j];
                if ([[movie objectForKey:@"File Path"] isEqualToString:path]) {
                    NSDate *oldDate = [movie objectForKey:@"File Modification Date"];
                    NSDate *newDate = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] objectForKey:NSFileModificationDate];
                    if ([oldDate compare:newDate] == NSOrderedAscending) { // new file found in array
                        NSMovie *newMovie = [[[NSMovie alloc] initWithURL:[NSURL fileURLWithPath:path] byReference:NO] autorelease];
                        if (newMovie) [movie setMovie:newMovie];
                        else movie = nil;
                    }
                    if (movie) {
                        [newMovies addObject:movie];
                        [oldMovies removeObjectAtIndex:j];
                        j--; m--;
                    }
                    break;
                }
            }
            if (j == m) { // didn't find it in the array, add it
                MHMovie *movie = [[[MHMovie alloc] initWithPath:path] autorelease];
                if (movie) {
                    [newMovies addObject:movie];
                    tPlaylist *lib = [[controller playlists] objectAtIndex:0];
                    [lib addMovie:movie];
                }
            }
        }
    }
    return newMovies;
}

- (void) updateToOptions
{
    if (!myOptions) return;
    [theSortedMovies release];
    theSortedMovies = nil;
    [theShuffledMovies release];
    theShuffledMovies = nil;
    
    BOOL combine = [myOptions containsObject:@"Match Any"];
    NSMutableArray *srcMovies = nil, *dstMovies = nil;
    srcMovies = [NSMutableArray arrayWithArray:[[[controller playlists] objectAtIndex:0] movieArray]];
    if (combine)
        dstMovies = [NSMutableArray array];
    else
        dstMovies = srcMovies;
    
    [theMovies removeAllObjects];
    int i, n = [myOptions count];
    NSString *key = nil, *value = nil;
    for (i=0;i<n;i++) {
        NSArray *opt = [[myOptions objectAtIndex:i] componentsSeparatedByString:@"|"];
        key = [opt objectAtIndex:0];
        value = [opt lastObject];
        if (![key isEqualToString:@"live"] && ![key hasPrefix:@"Match"]) {
            if ([key hasPrefix:@"Sync With Folder"]) {
                if (combine) {
                    NSArray *folderMovies = [self moviesFromFolder:value orArray:srcMovies];
                    [dstMovies addObjectsFromArray:folderMovies];
                } else {
                    NSArray *folderMovies = [self moviesFromFolder:value orArray:dstMovies];
                    [dstMovies removeAllObjects];
                    [dstMovies addObjectsFromArray:folderMovies];
                }
			} else if ([opt count] == 3 || [key isEqualToString:@"All Edited Movies"]) {
                int j, m = [srcMovies count];
                for (j=m-1;j>=0;j--) {
                    MHMovie *movie = [srcMovies objectAtIndex:j];
                    BOOL winnar = [self fitCondition:[myOptions objectAtIndex:i] withMovie:movie];
                    if (combine) {
                        if (![dstMovies containsObject:movie] && winnar) {
                            [dstMovies addObject:movie];
                            [srcMovies removeObjectAtIndex:j];
                        }
                    } else {
                        if (!winnar)
                            [dstMovies removeObjectAtIndex:j];
                    }
                }
            }
        }
    }
    [theMovies addObjectsFromArray:dstMovies];
    [[controller getTable] reloadData];
}

- (void) performLiveUpdate:(NSNotification *)note
{
    if (!myOptions || ![myOptions containsObject:@"live"]) return;
    NSDictionary *changes = [note userInfo];
    NSArray *keys = [changes allKeys];
    int i, n = [keys count];
    for (i=0;i<n;i++) { // changed keys
        NSString *key = [keys objectAtIndex:i];
        if ([key isEqualToString:@"ALL"] || [myOptions hasPrefix:key]) {
            MHMovie *movie = [changes objectForKey:key];
            if (movie && [movie isKindOfClass:[MHMovie class]]) {
                int j, m = [myOptions count];
                for (j=0; j<m;j++) { // my options
                    NSString *anOption = [myOptions objectAtIndex:j];
                    if (![anOption hasPrefix:@"live"] && ![anOption hasPrefix:@"Match"]) {
                        if ([self fitCondition:anOption withMovie:movie]) {
                            if (![theMovies containsObject:movie]) [self addMovie:movie];
                            if ([myOptions containsObject:@"Match Any"])
                                break;
                        } else {
                            if ([theMovies containsObject:movie]) [self removeMovie:[self indexForMovie:movie]];
                            if ([myOptions containsObject:@"Match All"])
                                break;
                        }
                    }
                }
            }
        }
    }
}

- (NSArray *) options
{
    return myOptions;
}

- (void) setOptions:(NSArray *)options
{
    if (myOptions)
        [myOptions release];
    myOptions = nil;
    int count = [options count];
    if ([options containsObject:@"live"]) count--;
    if ([options containsObject:@"Match Any"] || [options containsObject:@"Match All"]) count--;
    if (count > 0) {
        myOptions = [options retain];
        if ([options hasPrefix:@"Sync With Folder"])
            [self performSelector:@selector(updateToOptions) withObject:nil afterDelay:0];
        else
            [self updateToOptions];
    }
}

- (void) showOptions
{
    PlaylistController *winCon = [[PlaylistController alloc] initWithWindowNibName:@"Playlist"];
    [self addWindowController:winCon];
    [winCon showWindow:self];
    //[NSBundle loadNibNamed:@"Playlist" owner:self];
    //[window makeKeyAndOrderFront:self];
}

- (void)multiEdit:(NSNotification *)note
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
	// check if we're the active playlist
	if (self != [controller getModel]) return;
	// loop through the movies and set the data
	int i, n = [array count];
	for (i=0;i<n;i++) {
		if ([[controller mainTable] isRowSelected:i]) {
			NSString *object = [[note userInfo] objectForKey:@"object"],
					*key = [[note userInfo] objectForKey:@"key"],
					*lang = [[note userInfo] objectForKey:@"lang"];
			[[array objectAtIndex:i] setObject:object forKey:key language:lang];
		}
	}
}

/*
NSTableView data source / delegate
*/

- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    int x = [array count];
    return x;
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
    NSString *idString;
    MHMovie *movie;
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (rowIndex >= [array count] || rowIndex < 0) return @"";
    idString = [aTableColumn identifier];
    movie = [array objectAtIndex:rowIndex];
    if ([idString isEqualToString:@"Order"]) {
        /*
        if ([controller playingMovie] == movie) {
            NSString *path = [[NSBundle mainBundle] pathForImageResource:@"monitors"];
            NSAttributedString *pic = [NSAttributedString attributedStringWithAttachment:[[NSTextAttachment alloc] initWithFileWrapper:[[NSFileWrapper alloc] initWithPath:path]]];
            return [[[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%d", rowIndex+1]] autorelease] appendAttributedString:pic];
        } else
        */
            return [NSString stringWithFormat:@"%d", rowIndex + 1];
    }
    if (idString == nil)
        return @"unknown";
    NSString *value = [movie objectForKey:idString];
    return value;
}

- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
    if (wontChange) return;
    NSMutableArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    NSString *idString = [aTableColumn identifier];
    if (rowIndex >= [array count] || rowIndex < 0) return;
    else [(MHMovie *)[array objectAtIndex:rowIndex] setObject:anObject forKey:idString];
    [controller savePrefs];
    
    NSString *newString = [[array objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]];
    [self learn:newString];
    editingMovie = nil;
    [uneditedString release];
    uneditedString = nil;
}

- (void) tableView: (NSTableView *) tableView didClickTableColumn: (NSTableColumn *) tableColumn
{
    if ([tInit boolForKey:@"dontAnimate"]) [self sortByIdentifier:[tableColumn identifier]];
    else {
        [sortingDelegate stopAnimating];
        [sortingDelegate release];
        sortingDelegate = [[SortingDelegate alloc] initWithTableView:tableView];
        [sortingDelegate tableView:tableView didClickTableColumn:tableColumn];
    }
    [tableView reloadData];
}

- (void) sortByIdentifier:(NSString *)identifier
{
    MHMovie *movie = [self currentPlayingMovie];
    
    [theSortedMovies release];
    if ([identifier isEqualToString:@"Order"]) {
        theSortedMovies = nil;
        sortedString = nil;
    }
    else {
        theSortedMovies = [[NSMutableArray alloc] initWithArray:[theMovies sortedArrayUsingFunction: compareUD context:identifier]];
        sortedString = [identifier copy];
    }
    
    [self setCurrentPlayingMovie:movie];
}

- (NSRange)tableView:(NSTableView *)inTableView rowsInRect:(NSRect)inRect defaultRange:(NSRange)inDefaultRange
{
    if (!sortingDelegate) return inDefaultRange;
    return [sortingDelegate tableView:inTableView rowsInRect:inRect defaultRange:inDefaultRange];
}

- (NSRect) tableView:(NSTableView *)inTableView rectOfRow:(int)inRowIndex defaultRect:(NSRect)inDefaultRect
{
    if (!sortingDelegate) return inDefaultRect;
    return [sortingDelegate tableView:inTableView rectOfRow:inRowIndex defaultRect:inDefaultRect];
}

- (BOOL) tableView: (NSTableView *) aTableView shouldEditTableColumn: (NSTableColumn *) aTableColumn row: (int) rowIndex
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (rowIndex < 0) return NO;
    if (![tInit boolForKey:@"doubleClick"])
        return [self shouldEditTableColumn:aTableColumn row:rowIndex];
    if( shouldEditVariable != 1 )
        return NO;
    NSString *aFilePath = [[array objectAtIndex:rowIndex] objectForKey:@"File Path"];
    if( [[NSFileManager defaultManager] isWritableFileAtPath: aFilePath] == YES || ![tInit boolForKey:@"warn"])
        return [self shouldEditTableColumn:aTableColumn row:rowIndex];
    int choice = NSRunAlertPanel(@"Warning", @"This file is not writable.  To save your changes you must \"Save As\".  Do you wish to edit it anyway?", @"OK", @"Cancel", @"OK And Disable Warning");
    switch (choice) {
        case NSAlertDefaultReturn:
            return [self shouldEditTableColumn:aTableColumn row:rowIndex];
        case NSAlertOtherReturn:
            [tInit setBool:NO forKey:@"warn"];
            return [self shouldEditTableColumn:aTableColumn row:rowIndex];
        case NSAlertAlternateReturn:
            return NO;
    }
    return YES;
}


- (BOOL) shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
    //[self learn];
    //NSTextView *editBox = [controller getEditBox];
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    editingMovie = [array objectAtIndex:rowIndex];
    editingType = [aTableColumn identifier];
	
	[editingMovie setStatus:nil];
	//NSLog(@"should edit %@", editingType);
    if ([editingType isEqualToString:@"Order"]) return NO;
    if ([[specialCategories componentsSeparatedByString:@","] containsObject:editingType]) return NO;
    
    [uneditedString release];
    uneditedString = [editingMovie objectForKey:editingType];
    if (uneditedString)
        uneditedString = [[NSString alloc] initWithString:uneditedString];
    else
        uneditedString = @"";
    //[editBox selectAll:self];
    //[editBox insertText:uneditedString];
    return YES;
}

- (void) tableView:(NSTableView *)tableView didEndEditingTableColumn:(NSTableColumn *)col row:(int)row
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    NSString *newString = [[array objectAtIndex:row] objectForKey:[col identifier]];
    [self learn:newString];
    editingMovie = nil;
    [uneditedString release];
    uneditedString = nil;
}

- (BOOL) tableView: (NSTableView *) tableView shouldSelectRow: (int) rowIndex
{
    return YES;
    /*
    if (wontChange) return YES;
    //NSLog(@"selecting main table row: %d", rowIndex);
    if (tableView != [controller mainTable]) return YES;
    MHMovie *newMovie;
    NSString *data;
    if (rowIndex < 0 || rowIndex >= [theMovies count]) {
        data = @"";
        newMovie = nil;
    } else {
        newMovie = [theMovies objectAtIndex:rowIndex];
        data = [newMovie data];
    }
    [controller setCurrentMovie:newMovie];
    [[controller getInfoText] setStringValue:data];
    return YES;
    */
}

- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if ([[aTableColumn identifier] isEqualToString:@"Order"] && [aCell respondsToSelector:@selector(setImageName:)]) {
        if ([controller playingMovie] == [array objectAtIndex:rowIndex])
            [aCell setImageName:@"monitors"];
        else
            [aCell setImageName:nil];
        [aTableView setNeedsDisplay:YES];
    }
    
    if ([aCell respondsToSelector:@selector(setTextColor:)]) {
        NSColor *theColor = [NSColor blackColor];
        //if ([[aTableColumn identifier] isEqualToString:@"Order"] && [controller playingMovie] == [array objectAtIndex:rowIndex])
                //theColor = [NSColor redColor];
        //else
        if ([[array objectAtIndex:rowIndex] isOffline])
            theColor = [NSColor grayColor];
        [aCell setTextColor:theColor];
    }
    if ([aTableView selectedColumn] == [[aTableView tableColumns] indexOfObject:aTableColumn]) {
        if ([aTableView selectedRow] == rowIndex) {
            [aCell setWraps:YES];
            [aCell setScrollable:NO];
        } else {
//            [aCell setWraps:NO];
//            [aCell setScrollable:YES];
        }
    }
}

- (void)refreshImage
{
    MHMovie *movie = [controller currentMovie];
    NSImage *image = [movie imageForLanguage:[movie currentLanguage]];
    if (!image) {
        NSString *path = [movie objectForKey:@"File Path"];
        if (path) {
            image = [[IconFamily iconFamilyWithIconOfFile:path] imageWithAllReps];
            NSString *blankPath = [[[NSBundle mainBundle] pathForResource:@"mhSpriteHelper" ofType:@"app"] stringByAppendingPathComponent:@"Contents/Resources/blank.mov"];
            NSImage *image2 = [[IconFamily iconFamilyWithIconOfFile:blankPath] imageWithAllReps];
            NSComparisonResult result = [image compareA:image2];
            if (result == NSOrderedSame) {
                image = nil;
                
            }
        }
    }
    [controller setPicViewPic:image];
}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
    //[self learn];
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    [uneditedString release];
    (NSString *)editingMovie = editingType = uneditedString = nil;
    if (wontChange) return;
    MHMovie *newMovie = nil;
    NSTableView *table = [controller mainTable];
    if ([table numberOfSelectedRows] >= 1)
        newMovie = [array objectAtIndex:[table selectedRow]];
	[controller setCurrentMovie:newMovie];
    NSString *data = [newMovie data];
	if ([table numberOfSelectedRows] > 1) data = @"Multiple selection!  Changes will apply to all selected movies.";
    if (!data) data = @"";
    [[controller getInfoText] setStringValue:data];
    [self refreshImage];
}


- (void)tableViewSelectionWontChange:(NSNotification *)aNotification
{	wontChange = YES;	}

- (void)tableViewSelectionWillChangeAgain:(NSNotification *)aNotification
{	wontChange = NO;	}

- (void)tableView:(NSTableView *)tview rightClickWithEvent:(NSEvent *)event
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
	NSPoint point = [event locationInWindow];
	point = [tview convertPoint:point fromView:nil];
	int row = [tview rowAtPoint:point];
	NSMenu *menu = [[[NSMenu alloc] init] autorelease];
	NSMenuItem *item = nil;
	if (row >= 0 && row < [theMovies count]) {
		item = [[[NSMenuItem alloc] initWithTitle:@"Play Movie" action:@selector(setPlayingMovie:) keyEquivalent:@""] autorelease];
		[item setTarget:controller];
		[item setRepresentedObject:[array objectAtIndex:row]];
		[menu addItem:item];
		item = [[[NSMenuItem alloc] initWithTitle:@"Remove Movie" action:@selector(removeRow:) keyEquivalent:@""] autorelease];
		[item setTarget:controller];
		[menu addItem:item];
	}
	[self tableView:tview shouldSelectRow:row];
	//[tview selectRow:row byExtendingSelection:NO];
	//NSLog(@"point: %g x %g column: %d", point.x, point.y, index);
	[NSMenu popUpContextMenu:menu withEvent:event forView:tview];
}

- (void)tableView:(NSTableView *) tableView headerRightClickWithEvent:(NSEvent *) anEvent
{
    NSTableView *table = [controller getTable];
    if (tableView != table) return;
    NSMenu *menu = [[[NSMenu alloc] init] autorelease];
    NSMutableArray *list = [NSMutableArray arrayWithArray:[[controller getAddColumnBox] objectValues]];
    int i, n = [[tableView tableColumns] count];
    for (i=0;i<n;i++) {
        NSString *idString = [[[tableView tableColumns] objectAtIndex:i] identifier];
        if (![idString isEqualToString:@"Order"] && ![list containsObject:idString]) [list addObject:idString];
    }
    n = [list count];
    for (i=0;i<n;i++) {
        NSMenuItem *item = [[[NSMenuItem alloc] init] autorelease];
        NSString *title = [list objectAtIndex:i];
        [item setTitle:title];
        [item setTarget:controller];
        int x = [table columnWithIdentifier:title];
        if (x==-1) {
            [item setState:NO];
            [item setAction:@selector(addColumnFromMenu:)];
        } else {
            [item setState:YES];
            [item setAction:@selector(removeColumnFromMenu:)];
        }
        [menu addItem:item];
    }
    NSPoint point = [anEvent locationInWindow];
    point = [[tableView headerView] convertPoint:point fromView:nil];
    int index = [[tableView headerView] columnAtPoint:point];
    [controller setRightClickColumn:index];
    //NSLog(@"point: %g x %g column: %d", point.x, point.y, index);
    [NSMenu popUpContextMenu:menu withEvent:anEvent forView:tableView];
}

- (void)doSingleClick:(id)sender
{
    if (![tInit boolForKey:@"doubleClick"]) return;
	NSTableView 	*theTable	= [controller getTable];
	NSTableColumn	*theColumn	= [[theTable tableColumns] objectAtIndex:lastClickedColumn];
	int currentSelectedRow = [theTable selectedRow];
	if (currentSelectedRow != -1 && currentSelectedRow == lastSelectedRow ) {
		shouldEditVariable = 1;
		if( [self tableView:theTable shouldEditTableColumn:theColumn row:currentSelectedRow] == YES )
		{
			[theTable editColumn:lastClickedColumn row:currentSelectedRow withEvent:nil select:YES];
                        shouldEditVariable = 0;
		}
		else return;
		shouldEditVariable = 0;
	}
	else
	{
		lastSelectedRow = currentSelectedRow;
	}
}

- (IBAction)doSingleClickWithDelay:(id)sender 
{	
    if (![tInit boolForKey:@"doubleClick"]) return;
	[self performSelector:@selector(doSingleClick:)
               withObject:sender
               afterDelay:GetDblTime() / 60.0]; //Carbon Call
	lastClickedColumn = [[controller getTable] clickedColumn];
}

- (IBAction)doDoubleClick:(id)sender
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    NSTableView *tview = [controller getTable];
    if ([tview clickedColumn] == 0 && [tview clickedRow] >= 0)
        [controller setPlayingMovie:[array objectAtIndex:[tview clickedRow]]];
    if ([tInit boolForKey:@"doubleClick"]) {
		[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(doSingleClick:) object:sender];
		lastSelectedRow = [tview selectedRow];
                if ([tview clickedRow] >= 0)
                    [controller setPlayingMovie:[array objectAtIndex:[tview clickedRow]]];
	} else {
		if ([tview clickedColumn] >= 0 && [self shouldEditTableColumn:[[tview tableColumns] objectAtIndex:[tview clickedColumn]] row:[tview clickedRow]]) {
			shouldEditVariable = 1;
			[tview editColumn:[tview clickedColumn] row:[tview clickedRow] withEvent:[NSApp currentEvent] select:YES];
			shouldEditVariable = 0;
		}
	}
}

- (BOOL) deleteForTableView:(NSTableView *) tableView
{
    int choice = NSRunAlertPanel(@"Are you sure you want to remove the selected rows or columns?", @"Use Command-Delete to bypass this warning.", @"Remove Selection", @"Cancel", nil);
    switch (choice) {
        case NSAlertDefaultReturn:
            return [self commandDeleteForTableView:tableView];
        default:
            return YES;
    }
}

- (BOOL) commandDeleteForTableView:(NSTableView *) tableView
{
    MHMovie *playingMovie = [controller playingMovie];
    NSArray *cols = [tableView tableColumns];
    int i;
    BOOL found = NO, playNew = NO;
    for (i=[cols count]-1; i>=1; i--) { // the first column is the untouchable Order column
        if ([tableView isColumnSelected:i]) {
            [tableView removeTableColumn:[cols objectAtIndex:i]];
            found = YES;
        }
    }
    if (found) return YES;
    for (i=[tableView numberOfRows]-1; i>=0; i--) {
        playNew = NO;
        if ([tableView isRowSelected:i]) {
	    if ([self movieForIndex:i] == playingMovie) playNew = YES;
            [self removeMovie:i];
            if (playNew && [theMovies count])
                [[controller getPlayer] movieDidChangeTo:[self movieForIndex:0]];
            found = YES;
        }
    }
    [tableView reloadData];
    [self tableViewSelectionDidChange:nil];
    return found;
}

- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
{
    [pboard declareTypes:[NSArray arrayWithObjects:@"moviesFromSelf", @"moviesFromOther", nil] owner:nil];
    [pboard setPropertyList:rows forType:@"moviesFromSelf"];
    [pboard setPropertyList:rows forType:@"moviesFromOther"];
    return YES;
}

- (NSDragOperation)tableView:(NSTableView*)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation
{
    return NSDragOperationPrivate;
}

- (BOOL)tableView:(NSTableView*)tableView acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)operation
{
    NSMutableArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    MHMovie *playingMovie = [self currentPlayingMovie];
    
    NSPasteboard *b = [info draggingPasteboard];
    NSArray *types = [b types];
    if (![types containsObject:@"moviesFromSelf"]) return NO;
    NSArray *rows = [b propertyListForType:@"moviesFromSelf"];
    NSMutableArray *toMove = [NSMutableArray array];
    int i, n = [rows count];
    for (i=0;i<n;i++)
        [toMove addObject:[array objectAtIndex:[[rows objectAtIndex:i] intValue]]];
    int newRow = row;
    for (i=[rows count]-1;i>=0;i--) {
        newRow = row;
        MHMovie *movie = [toMove objectAtIndex:i];
        int oldRow = [array indexOfObject:movie];
        if (oldRow != NSNotFound) [array removeObject:movie];
        else if (oldRow < row && operation == NSTableViewDropAbove) newRow--;
        if (newRow >= [array count]) [array addObject:movie];
        else [array insertObject:movie atIndex:newRow];
    }
    
    [self setCurrentPlayingMovie:playingMovie];
    
    [tableView reloadData];
    [tableView selectRow:newRow byExtendingSelection:NO];
    return YES;
}

- (void)tableViewColumnDidMove:(NSNotification *)note
{
    if (colMoveRecurse) return;
    int old = [[[note userInfo] objectForKey:@"NSOldColumn"] intValue];
    int new = [[[note userInfo] objectForKey:@"NSNewColumn"] intValue];
    NSTableView *tview = [note object];
    if (old == 0 || new == 0) {
        colMoveRecurse = YES;
        [tview moveColumn:new toColumn:old];
        [tview reloadData];
        colMoveRecurse = NO;
    }
    NSString *idstring = sortedString;
    if (!idstring) idstring = @"Order";
    NSTableColumn *sortedCol = [tview tableColumnWithIdentifier:idstring];
    [tview setHighlightedTableColumn:sortedCol];
}

- (void)tableViewColumnDidResize:(NSNotification *)note
{
    NSTableView *tview = [note object];
    NSString *idstring = sortedString;
    if (!idstring) idstring = @"Order";
    NSTableColumn *sortedCol = [tview tableColumnWithIdentifier:idstring];
    [tview setHighlightedTableColumn:sortedCol];
}

- (void)imageViewDidFinishEditing:(imageFileView *)view
{
    int index = [[controller mainTable] selectedRow];
    if (index < 0) return;
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (index >= [array count]) return;
    MHMovie *movie = [array objectAtIndex:index];
    NSString *path = [view filepath];
    [movie setImageFile:path language:[movie currentLanguage]];
}

- (BOOL) isSelectedFileWritable
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    return [[array objectAtIndex:[[controller mainTable] selectedRow]] isFileWritable];
}

- (BOOL) learn:(NSString *)newString;
{
    if (!uneditedString)
        uneditedString = @"";
	int col = [[controller getTable] editedColumn];
	if (!editingType && col >= 0)
		editingType = [[[[controller getTable] tableColumns] objectAtIndex:col] identifier];
    if (!editingType) return NO;
    if (!newString || ![newString length]) return YES;
    if ([newString hasPrefix:uneditedString])
        newString = [newString substringFromIndex:[uneditedString length]];
    NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
    NSMutableDictionary *learned = [NSMutableDictionary dictionary];
    [learned addEntriesFromDictionary:[defs objectForKey:@"learned"]];
    NSMutableArray *cat = [NSMutableArray array];
    [cat addObjectsFromArray:[learned objectForKey:editingType]];
    NSArray *values = [newString componentsSeparatedByString:@", "];
    int i, n = [values count];
    for (i=0;i<n;i++) {
        NSString *value = [values objectAtIndex:i];
        if (![value isEqualToString:@""]) {
            if (NSNotFound == [cat indexOfObject:value])
                [cat addObject:value];
            else { // readd the value to the top because it was used again
                [cat removeObject:value];
                [cat addObject:value];
            }
        }
    }
    [learned setObject:cat forKey:editingType];
    [defs setObject:learned forKey:@"learned"];
    [defs synchronize];
    return YES;
}

- (BOOL)addMovie:(MHMovie *)theMovie
{
    if (!theMovie || ![theMovie isKindOfClass:[MHMovie class]]) return NO;
    if ([theMovies containsObject:theMovie]) return NO;
    [theMovies addObject:theMovie];
    if (theShuffledMovies) [theShuffledMovies addObject:theMovie];
    if (theSortedMovies) [theSortedMovies addObject:theMovie];
    NSNumber *num = [theMovie objectForKey:@"Seconds"];
    if (num)
        totalLength += [num intValue];
    num = [theMovie objectForKey:@"File Size"];
    if (num)
        totalSize += [num doubleValue];
    NumberOfFiles += 1;
    return YES;
}

- (NSArray *)search:(NSString *)searchString
{
    //NSLog(@"tPlaylist search");
    NSMutableArray *theChosen = [[NSMutableArray alloc] init];
    NSMutableArray *words = [NSMutableArray array];
    NSScanner *scan = [NSScanner scannerWithString:searchString];
    NSString *aWord;
    NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@" \""];
    int i, j, m, n;
    while (![scan isAtEnd]) {
        aWord = nil;
        [scan scanUpToCharactersFromSet:set intoString:&aWord];
        i = [scan scanLocation];
        if (aWord) {
            [words addObject:aWord];
            if ([scan scanString:@"\"" intoString:nil]) {
                [scan scanUpToString:@"\"" intoString:&aWord];
                [scan scanString:@"\"" intoString:nil];
                if (aWord)
                    [words addObject:aWord];
            }
        }
    }
    BOOL success;
    MHMovie *theMovie;
    n = [theMovies count];
    m = [words count];
    for (i=0;i<n;i++) { // for each movie
        theMovie = [theMovies objectAtIndex:i];
        success = YES;
        for (j=0;j<m;j++) { // for each word
            aWord = [words objectAtIndex:j];
            if (![self word:aWord forMovie:theMovie]) success = NO;
            if (!success) {
                while (j < m - 2 && [[words objectAtIndex:++j] isEqualToString:@"OR"]) {
                    aWord = [words objectAtIndex:++j];
                    if ([self word:aWord forMovie:theMovie]) success = YES;
                }
            }
        }
        if (success)
            [theChosen addObject:theMovie];
    }
    return theChosen;
}

- (BOOL)word:(NSString *)word forMovie:(MHMovie *)movie
{
    if ([word hasPrefix:@"-"]) return ![movie containsString:[word substringFromIndex:1]];
    return [movie containsString:word];
}

- (BOOL)addMovies: (NSArray *)someMovies
{
    //NSLog(@"tPlaylist addMovies");
    int i, n;
    MHMovie *theMovie;
    [theMovies addObjectsFromArray:someMovies];
    if (theShuffledMovies) [theShuffledMovies addObjectsFromArray:someMovies];
    if (theSortedMovies) [theSortedMovies addObjectsFromArray:someMovies];
    n = [someMovies count];
    for (i=0; i<n; i++) {
        theMovie = [someMovies objectAtIndex:i];
        totalLength += [[theMovie objectForKey:@"Seconds"] intValue];
        totalSize += [[theMovie objectForKey:@"File Size"] doubleValue];
        NumberOfFiles += 1;
    }
    
    return YES;
}

- (void)clearTableView:(NSTableView *)tview
{
    int i, n = [theMovies count];
    if (n > [tview numberOfRows]) n = [tview numberOfRows];
    for (i=n-1;i>=0;i--) {
        if ([tview isRowSelected:i])
            [self removeMovie:i];
    }
    n = [tview numberOfColumns];
    for (i=n-1;i>=0;i--) {
        if ([tview isColumnSelected:i])
            [tview removeTableColumn:(NSTableColumn *)[[tview tableColumns] objectAtIndex:i]];
    }
}
/*
- (void)cutTableView:(NSTableView *)tview
{
    [self clearTableView:tview];
}
*/
- (BOOL)removeMovie: (int)index
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    //NSLog(@"tPlaylist removeMovie");
    if (index < 0 || index >= [array count]) return NO;
    MHMovie *theMovie = [array objectAtIndex:index];
    totalLength -= [[theMovie objectForKey:@"Seconds"] intValue];
    totalSize -= [[theMovie objectForKey:@"File Size"] doubleValue];
    NumberOfFiles -= 1;
    [controller willDisposeMovie:theMovie sender:self];
    //[[controller getPlayer] shouldFreeMovie:theMovie];
    //[theMovies removeObjectAtIndex:index];
    [theMovies removeObject:theMovie];
    if (theShuffledMovies) [theShuffledMovies removeObject:theMovie];
    if (theSortedMovies) [theSortedMovies removeObject:theMovie];
    [controller updateTotals];
    
    return YES;
}

- (BOOL)removeAll
{
    [controller willDisposeMovie:nil sender:self];
    
    [theMovies removeAllObjects];
    if (theShuffledMovies) [theShuffledMovies removeAllObjects];
    if (theSortedMovies) [theSortedMovies removeAllObjects];
    totalLength = 0;
    totalSize = 0;
    NumberOfFiles = 0;
    return YES;
}

- (MHMovie *)movieWithPath:(NSString *)path
{
    if (!path) return nil;
    int i, n = [theMovies count];
    for (i=0;i<n;i++)
        if ([[[theMovies objectAtIndex:i] objectForKey:@"File Path"] isEqualToString:path])
            return [theMovies objectAtIndex:i];
    return nil;
}

- (MHMovie *)movieForIndex: (int)index
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (array == nil || [array count] == 0) return nil;
    if (index >= [array count] || index < 0) index = 0;
    return [array objectAtIndex:index];
}

- (int)indexForMovie:(MHMovie *)movie
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    int i, n = [array count];
    for (i=0;i<n;i++) {
        if ([array objectAtIndex:i] == movie)
            return i;
    }
    return -1;
}

- (NSArray *)movieArray
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    return [NSArray arrayWithArray:array];
}

- (double)getTotalMB
{
   //return totalSize;
    //return [NSObject numberWithDouble:@"%f", totalSize];
    double size = 0;
    int i, n = [theMovies count];
    for (i=0;i<n;i++)
        size += [[[theMovies objectAtIndex:i] objectForKey:@"File Size"] doubleValue];
    return size;
}

- (double)getTotalTime
{
    //return totalLength;
    double time = 0;
    int i, n = [theMovies count];
    for (i=0;i<n;i++)
        time += [[[theMovies objectAtIndex:i] objectForKey:@"Seconds"] doubleValue];
    return time;
}

- (int)getNumberOfFiles
{
   return NumberOfFiles;
}

- (NSString *)summaryForIndex:(int)index
{
    NSArray *array = theSortedMovies;
    if (!array) array = theShuffledMovies;
    if (!array) array = theMovies;
    
    if (index < 0 || index >= [array count])
        return @"";
    MHMovie *theMovie = [array objectAtIndex:index];
    return [theMovie summary];
}

- (BOOL)updateCategoriesForTable: (NSTableView *)tableView upTo: (int)maxColumns
{
    //NSLog(@"tPlaylist updateCategoriesForTable");
    NSTableColumn *aColumn;
    NSString *key;
    NSArray *theColumns, *theKeys;
    int tally;
    int i, j, k, l, m, n;
    
    NSMutableArray *theCategories = [[NSMutableArray alloc] init];
    
    n = [theMovies count];
    for (i=0;i<n;i++) {
        theKeys = [[theMovies objectAtIndex:i] allMetadataKeys];
        m = [theKeys count];
        for (j=0;j<m;j++) {
            key = [theKeys objectAtIndex:j];
            l = [theCategories count];
            for (k=0;k<l;k++) {
                if ([key isEqualToString:[theCategories objectAtIndex:k]])
                    break;
            }
            if (k == l)
                [theCategories addObject:key];
        }
    }
    
    theColumns = [tableView tableColumns];
    tally = [theColumns count];
    
    n = [theCategories count];
    for (i=0; i<n; i++) {
        key = [theCategories objectAtIndex:i];
        if ([tableView tableColumnWithIdentifier:key] == nil) {
            aColumn = [[NSTableColumn alloc] initWithIdentifier:key];
            [[aColumn headerCell] setStringValue:key];
            [tableView addTableColumn:aColumn];
            tally++;
        }
        if (maxColumns != -1 && tally >= maxColumns) break;
    }
    return YES;
}


- (void)shuffle
{
    MHMovie *movie = [self currentPlayingMovie];
    
    [theShuffledMovies release];
    theShuffledMovies = [[NSMutableArray alloc] initWithArray:[theMovies sortedArrayUsingFunction: compareUD context:@"tShuffle"]];
    sortedString = nil;
    
    [self setCurrentPlayingMovie:movie];
}

- (void)unshuffle
{
    MHMovie *movie = [self currentPlayingMovie];
    
    [theShuffledMovies release];
    theShuffledMovies = nil;
    sortedString = nil;
    
    [self setCurrentPlayingMovie:movie];
}

int compareUD(id movieT1, id movieT2, void *theString) {
    id one, two;
    NSString *first, *second, *input;
    double l1, l2;
    if (![movieT1 isKindOfClass:[MHMovie class]]) return NSOrderedSame;
    if (![movieT2 isKindOfClass:[MHMovie class]]) return NSOrderedSame;
    if (![(NSString *)theString isKindOfClass:[NSString class]]) return NSOrderedSame;
    input = [NSString stringWithString:theString];
    if ([input isEqualToString:@"tShuffle"]) {
        if (RandomChance(0.5)) return NSOrderedAscending;
        return NSOrderedDescending;
    }
    if ([input isEqualToString:@"Movie Length"]) input = @"Seconds";
    one = [movieT1 objectForKey:input];
    two = [movieT2 objectForKey:input];
    if ([one isKindOfClass:[NSNumber class]] || [two isKindOfClass:[NSNumber class]]) {
        l1 = [one doubleValue];
        l2 = [two doubleValue];
        if (l1<l2) return NSOrderedAscending;
        if (l1 == l2) return NSOrderedSame;
        if (l1>l2) return NSOrderedDescending;
    }
    first = [movieT1 objectForKey:input];
    second = [movieT2 objectForKey:input];
    if (!first) {
		if (!second)
			return NSOrderedSame;
		return NSOrderedAscending;
	}
	if (!second)
		return NSOrderedDescending;
    if ([first isKindOfClass:[NSDate class]] && [second isKindOfClass:[NSDate class]])
        return [first compare:second];
    if (![first isKindOfClass:[NSString class]])
		first = [first description];
	if (![second isKindOfClass:[NSString class]])
		second = [second description];
	
	NSArray *langs = [tLanguages systemLanguages];
	NSString *lang = @"English";
	if ([langs count]) lang = [langs objectAtIndex:0];
	NSString *aPath = [[NSBundle mainBundle] pathForResource:@"Articles" ofType:@"xml"];
	NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:aPath];
	NSArray *articles = [plist objectForKey:lang];
	if (!articles) articles = [plist objectForKey:@"English"];
	int i, n = [articles count];
	for (i=0;i<n;i++) {
		if ([[first lowercaseString] hasPrefix:[articles objectAtIndex:i]])
			first = [first substringFromIndex:[(NSString *)[articles objectAtIndex:i] length]];
		if ([[second lowercaseString] hasPrefix:[articles objectAtIndex:i]])
			second = [second substringFromIndex:[(NSString *)[articles objectAtIndex:i] length]];
	}
	if (first == nil) return NSOrderedAscending;
	if (second == nil) return NSOrderedDescending;
	return [first compare:second options:NSCaseInsensitiveSearch];
}



@end
