/*
SRHistoryController.m

Author: Makoto Kinoshita

Copyright 2004-2006 The Shiira Project. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

  2. 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.

THIS SOFTWARE IS PROVIDED BY THE SHIIRA PROJECT ``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 SHIIRA PROJECT 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 "SRWebHistory.h"

#import "SRAppController.h"
#import "SRBrowserController.h"
#import "SRHistoryController.h"

#import "SRConstants.h"

#import "SRHistoryContextMenu.h"

#import "SRPrefDefaultKeys.h"

// Frame auto save name
NSString*   SRHistoryPanelFrameAutoSaveName = @"SRHistoryPanelFrameAutoSaveName";

@implementation SRHistoryController

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//

+ (id)sharedInstance
{
    static SRHistoryController* _sharedInstance = nil;
    if (!_sharedInstance) {
        _sharedInstance = [[SRHistoryController alloc] init];
    }
    
    return _sharedInstance;
}

- (id)init
{
    self = [super initWithWindowNibName:@"HistoryPanel"];
    if (!self) {
        return nil;
    }
    
    return self;
}

- (void)awakeFromNib
{
    // Configure window
    NSWindow*   window;
    window = [self window];
    [window setFrameAutosaveName:SRHistoryPanelFrameAutoSaveName];
    
    // Configure history outline
    [_outlineView setTarget:self];
    [_outlineView setDoubleAction:@selector(openHistoryAction:)];
    
    // Set image text cell
    NSTableColumn*          column;
    NSCell*                 oldCell;
    HMImageTextFieldCell*   cell;
    column = [_outlineView tableColumnWithIdentifier:@"history"];
    oldCell = [column dataCell];
    cell = [[HMImageTextFieldCell alloc] init];
    [cell setFont:[oldCell font]];
    [column setDataCell:cell];
    [cell release];
    
    // Configure menu button
    [_menuButton setDelegate:self];
    
    // Register notification
    NSNotificationCenter*   center;
    center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(webHistoryUpdated:) 
            name:SRWebHistoryUpdated object:nil];
}

- (void)dealloc
{
    // Remove observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- History --
//--------------------------------------------------------------//

- (NSArray*)selectedHistoryItems
{
    // Get selected objects
    NSArray*    objects;
    objects = [_historyTreeController selectedObjects];
    if (!objects || [objects count] == 0) {
        return nil;
    }
    
    // Collect history item and calendar date
    NSMutableArray* historyItems;
    NSEnumerator*   enumerator;
    id              object;
    historyItems = [NSMutableArray array];
    enumerator = [objects objectEnumerator];
    while (object = [enumerator nextObject]) {
        // For WebHistoryItem
        if ([object isKindOfClass:[WebHistoryItem class]]) {
            [historyItems addObject:object];
        }
        // For dictionary
        if ([object isKindOfClass:[NSDictionary class]]) {
            // Get caledar
            NSCalendarDate* date;
            date = [object objectForKey:@"date"];
            if (date) {
                [historyItems addObject:date];
            }
        }
    }
    
    return historyItems;
}

- (NSMenu*)_contextMenuForView:(id)view 
        event:(NSEvent*)event 
        from:(id)from
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get modifier key flag
    unsigned int    modifierFlags;
    unsigned int    cmdFlag, optionFlag, shiftFlag;
    modifierFlags = [event modifierFlags];
    cmdFlag = modifierFlags & NSCommandKeyMask;
    optionFlag = modifierFlags & NSAlternateKeyMask;
    shiftFlag = modifierFlags & NSShiftKeyMask;
    
    // Create array for tags
    NSMutableArray* tags;
    tags = [NSMutableArray array];
    
    // For right click on the outline view
    if (from == _outlineView) {
        // Select history item under the cursor
        NSPoint point;
        int     rowUnderPoint;
        point = [view convertPoint:[event locationInWindow] 
                fromView:nil];
        rowUnderPoint = [view rowAtPoint:point];
        if (![[view selectedRowIndexes] containsIndex:rowUnderPoint]) {
            [view selectRowIndexes:[NSIndexSet indexSetWithIndex:rowUnderPoint] 
                    byExtendingSelection:NO];
        }
    }
    
    // Get selected rows
    NSIndexSet* indexSet;
    indexSet = [view selectedRowIndexes];
    
    WebHistoryItem* historyItem = nil;
    NSArray*        historyItems = nil;
    
    // No history is selected
    if ([indexSet count] == 0) {
        // Create tag array
        [tags addObject:[NSNumber numberWithInt:SRShowHistoryShelf]];
    }
    else {
        // Just one history item is selected
        if ([indexSet count] == 1) {
            // Get history item
            historyItem = [[self selectedHistoryItems] objectAtIndex:0];
        }
        else {
            // Get history items
            historyItems = [self selectedHistoryItems];
        }
        
        // Case of one history item
        if (historyItem && [historyItem isKindOfClass:[WebHistoryItem class]]) {
            // Create tag array
            [tags addObject:[NSNumber numberWithInt:SROpenHistoryTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenHistoryInNewWindowTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenHistoryInNewTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenHistoryInNewBackgroundWindowTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenHistoryInNewBackgroundTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenHistoryInNewWindowTag]];
            
            //[tags addObject:[NSNumber numberWithInt:SRShowHistoryInShelf]];
            [tags addObject:[NSNumber numberWithInt:SRShowHistoryShelf]];
        }
        // Case of one folder
        if (historyItem && [historyItem isKindOfClass:[NSCalendarDate class]]) {
            // Create tag array
            //[tags addObject:[NSNumber numberWithInt:SRShowHistoryInShelf]];
            [tags addObject:[NSNumber numberWithInt:SRShowHistoryShelf]];
        }
        // Case of multiple history items
        if (historyItems) {
            // Check existence of history item
            BOOL            isContainedHistoryItem = NO;
            NSEnumerator*   enumerator;
            WebHistoryItem* tmp;
            enumerator = [historyItems objectEnumerator];
            while (tmp = [enumerator nextObject]) {
                if ([tmp isKindOfClass:[WebHistoryItem class]]) {
                    isContainedHistoryItem = YES;
                    break;
                }
            }
            
            // Create tag array
            if (isContainedHistoryItem) {
                [tags addObject:[NSNumber numberWithInt:SROpenHistoryInTabsTag]];
            }
            [tags addObject:[NSNumber numberWithInt:SRShowHistoryShelf]];
        }
    }
    
    if ([tags count] > 0) {
        // Copy menu
        NSMenu* menu;
        menu = HMCopyMenuWithTags([SRHistoryContextMenu contextMenu], tags, self);
        
        // Set represented object
        if (historyItem) {
            [[menu itemArray] makeObjectsPerformSelector:@selector(setRepresentedObject:) 
                    withObject:historyItem];
        }
        if (historyItems) {
            [[menu itemArray] makeObjectsPerformSelector:@selector(setRepresentedObject:) 
                    withObject:historyItems];
        }
        
        // Set alt menu
        NSMenuItem* altMenuItem;
        if ([defaults boolForKey:SRTabSelectNewTabs]) {
            altMenuItem = [menu itemWithTag:SROpenHistoryInNewBackgroundWindowTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
            altMenuItem = [menu itemWithTag:SROpenHistoryInNewBackgroundTabTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
        }
        else {
            altMenuItem = [menu itemWithTag:SROpenHistoryInNewWindowTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
            altMenuItem = [menu itemWithTag:SROpenHistoryInNewTabTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
        }
        
        return menu;
    }
    
    return nil;
}

//--------------------------------------------------------------//
#pragma mark -- Actions --
//--------------------------------------------------------------//

- (void)showWindow:(id)sender
{
    // Check window
    if ([[self window] isVisible]) {
        return;
    }
    
    // Set web history
    [_historyTreeController setContent:[[SRWebHistory sharedInstance] treeWebHistory]];
    
    // Show window
    [super showWindow:sender];
}

- (void)openHistoryAction:(id)sender
{
    // Get selected history
    NSArray*    historyItems;
    historyItems = [self selectedHistoryItems];
    if (!historyItems || [historyItems count] == 0) {
        return;
    }
    
    id  history;
    history = [historyItems objectAtIndex:0];
    
    // For calendar date
    if ([history isKindOfClass:[NSCalendarDate class]]) {
        // Get selected row
        int row;
        row = [_outlineView selectedRow];
        if (row == -1) {
            return;
        }
        
        // Get item
        id  item;
        item = [_outlineView itemAtRow:row];
        
        // Toogle expansion
        if ([_outlineView isItemExpanded:item]) {
            [_outlineView collapseItem:item];
        }
        else {
            [_outlineView expandItem:item];
        }
        
        return;
    }
    // For WebHistory
    if ([history isKindOfClass:[WebHistoryItem class]]) {
        WebView*    webView;
        webView = [[[SRAppController sharedInstance] openHistory:history] webView];
        
        // Make web view window key window
        NSWindow*   window;
        window = [webView window];
        if (window) {
            [window makeKeyWindow];
        }
        
        return;
    }
}

- (void)openHistoryInNewWindowAction:(id)sender
{
    // Get selected history
    NSArray*    historyItems;
    id          historyItem;
    historyItems = [self selectedHistoryItems];
    if (!historyItems || [historyItems count] == 0) {
        return;
    }
    historyItem = [historyItems objectAtIndex:0];
    
    // Check history type
    if (![historyItem isKindOfClass:[WebHistoryItem class]]) {
        return;
    }
    
    // Open history
    [[SRBrowserController mainBrowserController] 
            openInNewWindowHistory:historyItem];
}

- (void)openHistoryInNewBackgroundWindowAction:(id)sender
{
    // Get selected history
    NSArray*    historyItems;
    id          historyItem;
    historyItems = [self selectedHistoryItems];
    if (!historyItems || [historyItems count] == 0) {
        return;
    }
    historyItem = [historyItems objectAtIndex:0];
    
    // Check history type
    if (![historyItem isKindOfClass:[WebHistoryItem class]]) {
        return;
    }
    
    // Open history
    [[SRBrowserController mainBrowserController] 
            openInNewBackgroundWindowHistory:historyItem];
}

- (void)openHistoryInNewTabAction:(id)sender
{
    // Get selected history
    NSArray*    historyItems;
    id          historyItem;
    historyItems = [self selectedHistoryItems];
    if (!historyItems || [historyItems count] == 0) {
        return;
    }
    historyItem = [historyItems objectAtIndex:0];
    
    // Check history type
    if (![historyItem isKindOfClass:[WebHistoryItem class]]) {
        return;
    }
    
    // Open history
    [[SRBrowserController mainBrowserController] 
            openInNewTabHistory:historyItem select:YES];
}

- (void)openHistoryInNewBackgroundTabAction:(id)sender
{
    // Get selected history
    NSArray*    historyItems;
    id          historyItem;
    historyItems = [self selectedHistoryItems];
    if (!historyItems || [historyItems count] == 0) {
        return;
    }
    historyItem = [historyItems objectAtIndex:0];
    
    // Check history type
    if (![historyItem isKindOfClass:[WebHistoryItem class]]) {
        return;
    }
    
    // Open history
    [[SRBrowserController mainBrowserController] 
            openInNewTabHistory:historyItem select:NO];
}

- (void)openHistoryInTabsAction:(id)sender
{
}

- (void)deleteHistoryAction:(id)sender
{
}

- (void)addHistoryToBookmarkAction:(id)sender
{
}

- (void)bookmarkAllHistoryAction:(id)sender
{
}

- (void)showShelfAction:(id)sender
{
    [[SRAppController sharedInstance] openShelf:@"jp.hmdt.shiira.historyshelf"];
}

- (void)showInShelfAction:(id)sender
{
}

//--------------------------------------------------------------//
#pragma mark -- NSOutlineView delegate --
//--------------------------------------------------------------//

- (void)outlineView:(NSOutlineView*)outlineView 
        willDisplayCell:(id)cell 
        forTableColumn:(NSTableColumn*)column 
        item:(id)item
{
    // History outline
    if (outlineView == _outlineView) {
        // Get column identifier
        id  identifier;
        identifier = [column identifier];
        
        // For history column
        if ([identifier isEqualToString:@"history"]) {
            // Set image
            if ([item respondsToSelector:@selector(observedObject)]) {
                id  observedObject;
                observedObject = [item performSelector:@selector(observedObject)];
                if ([observedObject isKindOfClass:[NSDictionary class]]) {
                    [cell setImage:[NSImage imageNamed:@"historyFolder"]];
                }
                else {
                    // Set icon
                    NSString*   URLString;
                    NSImage*    icon;
                    URLString = [observedObject URLString];
                    if ([[WebIconDatabase sharedIconDatabase] iconURLForURL:URLString]) {
                        icon = [[WebIconDatabase sharedIconDatabase] 
                                iconForURL:URLString withSize:NSMakeSize(16, 16)];
                    }
                    else {
                        icon = [NSImage imageNamed:@"historyPage"];
                    }
                    [cell setImage:icon];
                }
            }
            return;
        }
    }
}

//--------------------------------------------------------------//
#pragma mark -- NSOutlineViewEx delegate --
//--------------------------------------------------------------//

- (NSMenu*)outlineView:(NSOutlineView*)outlineView menuForEvent:(NSEvent*)event
{
    return [self _contextMenuForView:outlineView event:event from:outlineView];
}

//--------------------------------------------------------------//
#pragma mark -- HMMenuButton delegate --
//--------------------------------------------------------------//

- (NSMenu*)menuButton:(HMMenuButton*)menuButton menuForEvent:(NSEvent*)event
{
    return [self _contextMenuForView:_outlineView event:event from:menuButton];
}

//--------------------------------------------------------------//
#pragma mark -- SRWebHistory notification --
//--------------------------------------------------------------//

- (void)webHistoryUpdated:(NSNotification*)notification
{
    // Check window
    if (![[self window] isVisible]) {
        return;
    }
    
    // Reset content
    [_historyTreeController setContent:[[SRWebHistory sharedInstance] treeWebHistory]];
}

@end
