#import "AqContentViewController.h"
#import "AqCoreController.h"
#import "AqDownloadsController.h"
#import "AqDrawerController.h"
#import "AqQueryDataSource.h"
#import "AqQueryDataSource(Table).h"
#import "DWCustomizableTableView.h"
#import "NSTableViewExtensions.h"


@implementation AqQueryDataSource

/* Initialization */

    - (id) initWithQuery: (AqQuery*) theQuery; {
        query = theQuery;
        return [self init];
    }

    - (id) init;
    {
        self = [super init];
    
        /* alloc */
            
            newFiles = [[NSMutableArray alloc] init];
            rootNode = [[AqRootNode alloc] init];
            
            currentNode = [rootNode allTypesNode];
            [objects release];
            objects = [[currentNode files] retain];

        /* table */
        
            [self initTable];

        /* filters */
        
            filters[kAqReliabilityFilter] = [[AqReliabilityFilter alloc] init];
            filters[kAqBitrateFilter]     = [[AqBitrateFilter alloc] init];
            filters[kAqSizeFilter]        = [[AqSizeFilter alloc] init];
            filters[kAqKeywordFilter]     = [[AqKeywordFilter alloc] init];
            filters[kAqSpeedFilter]       = [[AqSpeedFilter alloc] init];
            filters[kAqHostFilter]  	  = [[AqHostFilter alloc] init];
        
        /* timer */

            timer = [NSTimer scheduledTimerWithTimeInterval: 0.15 target: self selector: @selector(periodicUpdate:) userInfo: nil repeats: YES];

        return self;
    }
    
    - (void) dealloc; 
    {
        //NSLog(@"AqQueryDataSource: dealloc");
        
        int i;
        for (i=0; i<kAqTotalFilters; i++) {
            [filters[i] release];
        }
    
        [timer invalidate];
        //[invisibleObjects release];
        [newFiles release];
        [rootNode release];
        [super dealloc];
    }
    
    - (void) setTableView: (id) theView; {
        shouldSaveSortOrder = YES;
        [super setTableView: theView];
    }

    - (id) rootNode; {
        return rootNode;
    }

    - (void) setCurrentNode: (AqMetaNode*) theNode; {

        //NSLog(@"setCurrentNode: %@", theNode);

        //if (currentNode) currentNode->fileView = nil;

        [self saveSelectedObjects];
        [objects release];
        objects = [[theNode files] retain];
        [self sort];
        [self restoreSelectedObjects];
        
        [tableView noteNumberOfRowsChanged];

        currentNode = theNode;
        [self updateCell: nil];
        //if (currentNode) currentNode->fileView = tableView;
    }
        

#pragma mark -
/* Actions */

    - (void) removeAllObjects; {
        [super removeAllObjects];
        [newFiles removeAllObjects];
        [rootNode performSelector: @selector(release) withObject: nil afterDelay: 0];
        rootNode = [[AqRootNode alloc] init];
        [self setCurrentNode: [rootNode allTypesNode]]; 
    }


#pragma mark -
/* Query Replies */

    - (void) updateFile: (AqRemoteFile*) theFile; {
        [newFiles addObject: theFile];
    }
        
    - (void) periodicUpdate: (id) timer; 
    {
        int i, count = [newFiles count];
        if (!count) return;

        BOOL needsDisplay = NO;
        BOOL newFileAdded = NO;
        
        /* handle new files */
            
            int initialCount = [currentNode visibleCount];
            [self saveSelectedObjects];
            
            for (i=0; i<count; i++) 
            {
                id file = [newFiles objectAtIndex: i];
                [self setSequence: file];

                /* add file */

                    BOOL passesFilters = [self objectPassesAllFilters: file];

                    if (passesFilters) {
                        needsDisplay = YES;
                    }

                    [rootNode handleFile: file isVisible: passesFilters];

                /*
                    BOOL passesFilters = [self objectPassesAllFilters: file];

                    if (passesFilters) {
                        if (![objects containsObject: file]) {
                            newFileAdded = YES;
                        }
                        needsDisplay = YES;
                    } else {
                        if (![invisibleObjects containsObject: file]) {
                            [invisibleObjects addObject: file];
                        }
                    }
                */    
            }
        
        /* clear new files array */

            [newFiles removeAllObjects];

        /* sort & display */
        
            if (needsDisplay) {
                [self sort];
                [self restoreSelectedObjects];
                [tableView noteNumberOfRowsChanged];
            }
            
            newFileAdded = [currentNode visibleCount] > initialCount;
            if (newFileAdded)
                hasUnviewedFiles = YES;
            
            [self updateCell: nil];
            
        /* log */

            #if 0
            if (count) NSLog(@"periodicUpdate: adding %i files", count);
            #endif
    }


#pragma mark -
/* Filtering */

    - (AqFilter*) filterForIndex: (int) aqFilterIndex; {
        return filters[aqFilterIndex];
    }
    
    - (BOOL) objectPassesAllFilters: (AqRemoteFile*) theFile; {
        int i;
        for (i=0; i<kAqTotalFilters; i++) {
            if (filterIsActive[i])
                if (![filters[i] passesFilter: theFile])
                    return NO;
        }
        return YES;
    }
    
    /* tightenFilter is called (by AqFilterController) when the current filter is become tighter.  This allows us to only inspect the visible objects, since any object that previously failed the filter will still fail it. */
    
    - (void) tightenFilter: (int) aqFilterIndex; 
    {
        [self reevaluateAllFilters: aqFilterIndex];
        /*
        id theFilter = filters[aqFilterIndex];
        filterIsActive[aqFilterIndex] = YES;

        //NSLog(@"tightenFilter: %@", theFilter);
        //[Profile start];
        
        id objectsToRemove = [[NSMutableArray alloc] init];
        int i, count = [objects count];
        
        for (i=0; i<count; i++) 
        {
            id aqRemoteFile = [objects objectAtIndex: i];

            if (![theFilter passesFilter: aqRemoteFile]) {
                [objectsToRemove addObject: aqRemoteFile];
            }
        }
        
        //[Profile end];
        
        if ([objectsToRemove count]) 
        {
            [self saveSelectedObjects];

            [invisibleObjects addObjectsFromArray: objectsToRemove];
            [objects removeObjectsInArray: objectsToRemove];

            [self restoreSelectedObjects];
            [tableView noteNumberOfRowsChanged];
        }
        
        [objectsToRemove release];
        */
    }
    
    /* relaxFilter is similar to tightenFilter, except that all visible objects will continue to remain visible, and only invisible objects need to be checked. */
    
    - (void) relaxFilter: (int) aqFilterIndex; 
    {
        [self reevaluateAllFilters: aqFilterIndex];
        /*
        //id theFilter = filters[aqFilterIndex];
        //NSLog(@"relaxFilter: %@", theFilter);
        
        id objectsToAdd = [[NSMutableArray alloc] init];
        int i, count = [invisibleObjects count];
        
        for (i=0; i<count; i++) 
        {
            id aqRemoteFile = [invisibleObjects objectAtIndex: i];

            if ([self objectPassesAllFilters: aqRemoteFile]) {
                [objectsToAdd addObject: aqRemoteFile];
            }
        }
        
        if ([objectsToAdd count]) 
        {
            [self saveSelectedObjects];
            
            [invisibleObjects removeObjectsInArray: objectsToAdd];
            [objects addObjectsFromArray: objectsToAdd];
            
            [self sort];
            [self restoreSelectedObjects];
            [tableView noteNumberOfRowsChanged];
        }
        
        [objectsToAdd release];
        */
    }
    
    - (void) reevaluateAllFilters: (int) aqFilterIndex; 
    {
        filterIsActive[aqFilterIndex] = YES;
        [self saveSelectedObjects];
        
        unsigned initialCount = [objects count];

        /* reset everything */
            
            id allFiles = [[[NSMutableArray alloc] init] autorelease];
            [allFiles addObjectsFromArray: [[rootNode allTypesNode] files]];
            [allFiles addObjectsFromArray: [[rootNode allTypesNode] hiddenFiles]];
    
        /* apply all filters */

            int i, count = [allFiles count];
            for (i=0; i<count; i++) {
                id aqRemoteFile = [allFiles objectAtIndex: i];
                if ([self objectPassesAllFilters: aqRemoteFile]) {
                    [rootNode handleFile: aqRemoteFile isVisible: YES];
                } else {
                    [rootNode handleFile: aqRemoteFile isVisible: NO];
                }
            }

        if (initialCount != [objects count]) {
            [self sort];
            [self restoreSelectedObjects];
            [tableView noteNumberOfRowsChanged];
        }
    }


#pragma mark -
/* Cell */
    
    - (void) updateCell: (id) sender; 
    {
        hasUnviewedFiles = hasUnviewedFiles && ![tableView window];
        if (![AqDrawerController instance]) return;
        
        id queryView = [AqDrawerController instance]->queryView;
        int v = [currentNode visibleCount];
        int t = [rootNode totalCount];

        id a = (hasUnviewedFiles) ? [AqQueryCell secondaryBlueAttributes] : [AqQueryCell secondaryAttributes];
        
        id theString;
        if (t!=v)   theString = [NSString stringWithFormat: @"%i/%i", v, t];
        else if (v) theString = [NSString stringWithFormat: @"%i", v];
        else        theString = nil;

        if (theString)
            [query->cell setSecondary: [[[DWTableString alloc] initWithString: theString attributes: a] autorelease]];
        else 
            [query->cell setSecondary: nil];

        [queryView setNeedsDisplayInRect: [queryView rectOfRow: [AqQC indexOfQuery: query]]];
    }


#pragma mark -
/* nextKeyView chain */

    - (NSView*) nextValidKeyView; {
        return [[AqContentViewController instance] currentToolbarDelegate]->searchView;
    }

    - (NSView*) previousValidKeyView; {
        id currentView = [[AqContentViewController instance] currentView];
        if ([currentView isKindOfClass: [NSSplitView class]]) {
            return [[[currentView subviews] objectAtIndex: 0] lastView];
        } else {
            return nil;
        }
    }

    - (void) leftKeyPressed; {
        [[tableView window] makeFirstResponder: [self previousValidKeyView]];
    }
    
    - (void) rightKeyPressed; {
        [[tableView window] makeFirstResponder: [self nextValidKeyView]];
    }

@end