/*
SRSideBarController.m

Author: Makoto Kinoshita

Copyright 2004 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 "SRDefaultsKey.h"

#import "SRMainWindowController.h"
#import "SRSideBarController.h"
#import "SRSBBookmarksController.h"
#import "SRSBHistoryController.h"
#import "SRSBDownloadController.h"
#import "SRSBPageHolderController.h"
#import "SRSBRSSController.h"

#import "SRTabView.h"
#import "HTSRTabBarView.h"

static float    _verticalTabViewHeight = 18.0f;

@interface SRSideBarController (private)
- (void)_prepareTabViewItemWithIdentifier:(id)identifier;
@end

@implementation SRSideBarController

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

- (id)initWithMainWindowController:(SRMainWindowController*)mainWindowController
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    // Initialize instance variables
    _mainWindowController = mainWindowController;
    _isResizedByDrawer = NO;
    
    // Register notification
    NSNotificationCenter*   center;
    center = [NSNotificationCenter defaultCenter];
    [center addObserver:self 
            selector:@selector(applicationWillTerminate:) 
            name:NSApplicationWillTerminateNotification 
            object:nil];
    
    return self;
}

- (void)awakeFromNib
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Configure for drawer
    NSString*   drawerSizeString;
    drawerSizeString = [defaults stringForKey:SRSideBarDrawerSize];
    if (drawerSizeString) {
        _drawerInitialSize = NSSizeFromString(drawerSizeString);
    }
    else {
        _drawerInitialSize = NSZeroSize;
    }
    
    NSWindow*   window;
    window = [_mainWindowController window];
    SR_VERIFY(window);
    [_drawer setParentWindow:window];
    
    [_drawer setDelegate:self];
    
    // Add tab view item
    _drawerTab = [_drawerSRTabView tabView];
    
    NSArray*    identifiers = [NSArray arrayWithObjects:
            @"bookmark", @"history", @"download", @"pageHolder", @"RSS", nil];
    NSArray*    titles = [NSArray arrayWithObjects:
            @"Bookmarks", @"History", @"Download", @"Page holder", @"RSS", nil];
    
    int i;
    for (i = 0; i < [identifiers count]; i++) {
        NSString*   identifier;
        NSString*   title;
        identifier = [identifiers objectAtIndex:i];
        title = [titles objectAtIndex:i];
        
        // Check RSS enable
        if ([identifier isEqualToString:@"RSS"] && ![defaults boolForKey:SRRSSEnable]) {
            continue;
        }
        
        // Add tab view item
        NSTabViewItem*  tabViewItem;
        tabViewItem = [[NSTabViewItem alloc] initWithIdentifier:identifier];
        [tabViewItem setLabel:NSLocalizedString(title, title)];
        [_drawerTab addTabViewItem:tabViewItem];
    }
    
    // Configure tab view
    [_drawerSRTabView setTabViewType:HTSRLeftTabsBezelBorder];
    [_drawerSRTabView setTabViewHeight:_verticalTabViewHeight];
    
    [_drawerTab setTabViewType:NSNoTabsBezelBorder];
    [_drawerTab setDelegate:self];
    
    // Reorder tab view item
    NSArray*    tabViewOrder;
    tabViewOrder = [defaults objectForKey:SRSideBarTabOrder];
    if (tabViewOrder) {
        // Retain all tab view items
        NSArray*    tabViewItems;
        tabViewItems = [[_drawerTab tabViewItems] copy];
        
        // Reorder tab view items
        int i, itemIndex = 0;
        for (i = 0; i < [tabViewOrder count]; i++) {
            NSString*   identifier;
            identifier = [tabViewOrder objectAtIndex:i];
            
            int index;
            index = [_drawerTab indexOfTabViewItemWithIdentifier:identifier];
            if (index == NSNotFound) {
                continue;
            }
            if (index <= i) {
                itemIndex++;
                continue;
            }
            
            NSTabViewItem*  tabViewItem;
            tabViewItem = [_drawerTab tabViewItemAtIndex:index];
            [_drawerTab removeTabViewItem:tabViewItem];
            [_drawerTab insertTabViewItem:tabViewItem atIndex:itemIndex++];
        }
        
        [tabViewItems release];
    }
    
    // Configure tab bar view
    HTSRTabBarView* tabBarView;
    tabBarView = [_drawerSRTabView tabBarView];
    [tabBarView setHasCloseButton:NO];
    [tabBarView setAccordingToLabelWidth:YES];
    [tabBarView setShowNewTabuBtton:NO];
    [tabBarView setHasMenu:NO];
    [tabBarView setFont:[NSFont boldSystemFontOfSize:10.0]];
    
    // Select tab selected previously
    int selectedTab;
    selectedTab = [defaults integerForKey:SRMainWindowSidebarSelectedTab];
    [self showTab:selectedTab];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [_bookmarksController release];
    [_historyController release];
    [_downloadController release];
    [_pageHolderController release];
    [_RSSController release];
    
    // Release outlets
    [_drawer setDelegate:nil];
    [_drawer setParentWindow:nil];
    [_drawer release];
    [_drawerView release];
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- Main window controller --
//--------------------------------------------------------------//

- (SRMainWindowController*)mainWindowController
{
    return _mainWindowController;
}

- (void)setMainWindowController:(SRMainWindowController*)mainWindowController
{
    _mainWindowController = mainWindowController;
    
    [_bookmarksController setMainWindowController:mainWindowController];
    [_historyController setMainWindowController:mainWindowController];
    [_downloadController setMainWindowController:mainWindowController];
}

//--------------------------------------------------------------//
#pragma mark -- Sidebar controller --
//--------------------------------------------------------------//

- (NSString*)identifierOfTab:(SRSidebarTab)tab
{
    switch (tab) {
    case SRSidebarBookmarkTab: return @"bookmark";
    case SRSidebarHistoryTab: return @"history";
    case SRSidebarDownloadTab: return @"download";
    case SRSidebarPageHolderTab: return @"pageHolder";
    case SRSidebarRSSTab: return @"RSS";
    }
    return nil;
}

- (SRSidebarTab)tabOfIdentifier:(NSString*)identifier
{
    if([identifier isEqualToString:@"bookmark"]) {
        return SRSidebarBookmarkTab;
    }
    else if([identifier isEqualToString:@"history"]) {
        return SRSidebarHistoryTab;
    }
    else if([identifier isEqualToString:@"download"]) {
        return SRSidebarDownloadTab;
    }
    else if([identifier isEqualToString:@"pageHolder"]) {
        return SRSidebarPageHolderTab;
    }
    else if([identifier isEqualToString:@"RSS"]) {
        return SRSidebarRSSTab;
    }
    return -1;
}

- (SRSidebarTab)selectedTab
{
    return [self tabOfIdentifier:[[_drawerTab selectedTabViewItem] identifier]];
}

- (SRSBBookmarksController*)bookmarksController
{
    if (!_bookmarksController) {
        // Create bookmarks controller
        _bookmarksController = [[SRSBBookmarksController alloc] 
                initWithMainWindowController:_mainWindowController sideBarController:self];
        
        // Load nib file
        if (![NSBundle loadNibNamed:@"SBBookmarks" owner:_bookmarksController]) {
            // Fatal error
            SR_FATAL(@"Could not load SBBookmarks.nib");
        }
    }
    
    return _bookmarksController;
}

- (SRSBHistoryController*)historyController
{
    if (!_historyController) {
        // Create history controller
        _historyController = [[SRSBHistoryController alloc] 
                initWithMainWindowController:_mainWindowController sideBarController:self];
        
        // Load nib file
        if (![NSBundle loadNibNamed:@"SBHistory" owner:_historyController]) {
            // Fatal error
            SR_FATAL(@"Could not load SBHistory.nib");
        }
    }
    
    return _historyController;
}

- (SRSBDownloadController*)downloadController
{
    if (!_downloadController) {
        // Create download controller
        _downloadController = [[SRSBDownloadController alloc] 
                initWithMainWindowController:_mainWindowController sideBarController:self];
        
        // Load nib file
        if (![NSBundle loadNibNamed:@"SBDownload" owner:_downloadController]) {
            // Fatal error
            SR_FATAL(@"Could not load SBDownload.nib");
        }
    }
    
    return _downloadController;
}

- (SRSBPageHolderController*)pageHolderController
{
    if (!_pageHolderController) {
        // Create page holder controller
        _pageHolderController = [[SRSBPageHolderController alloc] 
                initWithMainWindowController:_mainWindowController sideBarController:self];
        
        // Load nib file
        if (![NSBundle loadNibNamed:@"SBPageHolder" owner:_pageHolderController]) {
            // Fatal error
            SR_FATAL(@"Could not load SBDownload.nib");
        }
    }
    
    return _pageHolderController;
}

- (SRSBRSSController*)RSSController
{
    if (!_RSSController) {
        // Create RSS controller
        _RSSController = [[SRSBRSSController alloc] 
                initWithMainWindowController:_mainWindowController sideBarController:self];
        
        // Load nib file
        if (![NSBundle loadNibNamed:@"SBRSS" owner:_RSSController]) {
            // Fatal error
            SR_FATAL(@"Could not load RSS.nib");
        }
    }
    
    return _RSSController;
}

//--------------------------------------------------------------//
#pragma mark -- Drawer --
//--------------------------------------------------------------//

- (NSDrawer*)drawer
{
    return _drawer;
}

- (void)_prepareTabViewItemWithIdentifier:(id)identifier
{
    // Get tab view item
    NSTabViewItem*  item;
    int             index, subviewCount;
    index = [_drawerTab indexOfTabViewItemWithIdentifier:identifier];
    if (index == NSNotFound) {
        return;
    }
    item = [_drawerTab tabViewItemAtIndex:index];
    subviewCount = [[[item view] subviews] count];
    
    id  controller = nil;
    
    // For bookmark
    if ([identifier isEqualToString:@"bookmark"]) {
        if (!_bookmarksController || subviewCount == 0) {
            // Load bookmarks controller
            controller = [self bookmarksController];
            
            // Put it in tab view
            [item setView:[_bookmarksController view]];
        }
    }
    // For history
    if ([identifier isEqualToString:@"history"]) {
        if (!_historyController || subviewCount == 0) {
            // Load history controller
            controller = [self historyController];
            
            // Put it in tab view
            [item setView:[_historyController view]];
        }
    }
    // For download
    if ([identifier isEqualToString:@"download"]) {
        if (!_downloadController || subviewCount == 0) {
            // Load download controller
            controller = [self downloadController];
            
            // Put it in tab view
            [item setView:[_downloadController view]];
        }
    }
    // For page hodler
    if ([identifier isEqualToString:@"pageHolder"]) {
        if (!_pageHolderController || subviewCount == 0) {
            // Load page holder controller
            controller = [self pageHolderController];
            
            // Put it in tab view
            [item setView:[_pageHolderController view]];
        }
    }
    // For RSS
    if ([identifier isEqualToString:@"RSS"]) {
        if (!_RSSController || subviewCount == 0) {
            // Load RSS controller
            controller = [self RSSController];
            
            // Put it in tab view
            [item setView:[_RSSController view]];
        }
    }
    
    // Notify will open message
    if (controller && [controller respondsToSelector:@selector(sideBarWillShow)]) {
        [controller sideBarWillShow];
    }
}

- (void)showTab:(SRSidebarTab)tab
{
    NSString*   identifier;
    identifier = [self identifierOfTab:tab];
    
    // Select tab
    if ([_drawer state] != NSDrawerClosedState) {
        [self _prepareTabViewItemWithIdentifier:identifier];
    }
    [_drawerSRTabView selectItemWithIdentifier:identifier];
}

- (BOOL)isResizedByDrawer
{
    return _isResizedByDrawer;
}

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

- (void)createNewBookmarkFolderAction:(id)sender
{
    // Open drwaer
    if ([_drawer state] == NSDrawerClosedState || 
        [_drawer state] == NSDrawerClosingState) 
    {
        [_mainWindowController setSidebarVisible:YES];
    }
    
    // Select tab
    [self showTab:SRSidebarBookmarkTab];
    
    // Pass to bookmark controller
    [[self bookmarksController] createNewBookmarkFolderAction:sender];
}

//--------------------------------------------------------------//
#pragma mark -- NSApplication notification --
//--------------------------------------------------------------//

- (void)applicationWillTerminate:(NSNotification*)notification
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Save tab order
    NSMutableArray* identifiers;
    NSEnumerator*   enumerator;
    NSTabViewItem*  tabViewItem;
    identifiers = [NSMutableArray array];
    enumerator = [[_drawerTab tabViewItems] objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        [identifiers addObject:[tabViewItem identifier]];
    }
    [defaults setObject:identifiers forKey:SRSideBarTabOrder];
}

//--------------------------------------------------------------//
#pragma mark -- NSDrawer delegate --
//--------------------------------------------------------------//

- (void)drawerWillOpen:(NSNotification*)notification
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Prepare for tab view item
    [self _prepareTabViewItemWithIdentifier:[[_drawerTab selectedTabViewItem] identifier]];
    
    // Get edge
    NSRectEdge  edge;
    edge = [_drawer edge];
    
    // Set tab view type
    if (edge == NSMaxXEdge) {
        if ([_drawerSRTabView tabViewType] == HTSRLeftTabsBezelBorder) {
            [_drawerSRTabView setTabViewType:HTSRRightTabsBezelBorder];
            [_drawerSRTabView setTabViewHeight:_verticalTabViewHeight];
        }
    }
    if (edge == NSMinXEdge) {
        if ([_drawerSRTabView tabViewType] == HTSRRightTabsBezelBorder) {
            [_drawerSRTabView setTabViewType:HTSRLeftTabsBezelBorder];
            [_drawerSRTabView setTabViewHeight:_verticalTabViewHeight];
        }
    }
    
    // Set initial size for first time
    if (!NSEqualSizes(_drawerInitialSize, NSZeroSize)) {
        [_drawer setContentSize:_drawerInitialSize];
        _drawerInitialSize = NSZeroSize;
    }
    
    // Ignore auto resize
    if (![defaults boolForKey:SRSidebarAutoresize]) {
        return;
    }
    
    // Calulate window and drawer size
    NSSize      contentSize;
    NSRect      windowFrame, withDrawerFrame, visibleFrame;
    static int  _outsideBorder = 12;
    contentSize = [_drawer contentSize];
    windowFrame = [[_drawer parentWindow] frame];
    withDrawerFrame = windowFrame;
    visibleFrame = [[[_drawer parentWindow] screen] visibleFrame];
    if (edge == NSMaxXEdge) {
        withDrawerFrame.size.width += contentSize.width + _outsideBorder;
        if (withDrawerFrame.origin.x + withDrawerFrame.size.width > 
            visibleFrame.origin.x + visibleFrame.size.width)
        {
            // Shrink window
            _isResizedByDrawer = YES;
            _originalFrame = windowFrame;
            
            int delta;
            delta = (withDrawerFrame.origin.x + withDrawerFrame.size.width) - 
                    (visibleFrame.origin.x + visibleFrame.size.width);
            windowFrame.size.width -= delta;
            [[_drawer parentWindow] setFrame:windowFrame display:YES];
            _resizedFrame = windowFrame;
        }
    }
    if (edge == NSMinXEdge) {
        withDrawerFrame.origin.x -= contentSize.width + _outsideBorder;
        withDrawerFrame.size.width += contentSize.width + _outsideBorder;
        if (withDrawerFrame.origin.x < visibleFrame.origin.x) {
            // Shrink window
            _isResizedByDrawer = YES;
            _originalFrame = windowFrame;
            
            int delta;
            delta = visibleFrame.origin.x - withDrawerFrame.origin.x;
            windowFrame.origin.x += delta;
            windowFrame.size.width -= delta;
            [[_drawer parentWindow] setFrame:windowFrame display:YES];
            _resizedFrame = windowFrame;
        }
    }
}

//- drawerShouldOpen:

- (void)drawerDidOpen:(NSNotification*)notification
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Set sidebar visibility to default database
    [defaults setBool:YES forKey:SRMainWindowSidebarVisible];
}

- (NSSize)drawerWillResizeContents:(NSDrawer*)drawer 
        toSize:(NSSize)contentSize
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Store size to user default
    [defaults setObject:NSStringFromSize(contentSize) forKey:SRSideBarDrawerSize];
    
    return contentSize;
}

//- drawerWillClose:
//- drawerShouldClose:

- (void)drawerDidClose:(NSNotification*)notification
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Set sidebar visibility to default database
    [defaults setBool:NO forKey:SRMainWindowSidebarVisible];
    
    // Ignore auto resize
    if (![defaults boolForKey:SRSidebarAutoresize]) {
        return;
    }
    
    // Resize window
    if (_isResizedByDrawer) {
        // Calc delta between orignal and resized frame
        int deltaOriginX;
        deltaOriginX = _originalFrame.origin.x - _resizedFrame.origin.x;
        
        // Get frame size
        NSWindow*   parentWindow;
        NSRect      windowFrame, frame;
        parentWindow = [_drawer parentWindow];
        windowFrame = [parentWindow frame];
        frame = windowFrame;
        
        // Roll back window position
        if (deltaOriginX != 0) {
            frame.origin.x += deltaOriginX;
        }
        
        // Change window size if size is not changed till automatic resize
        if (NSEqualSizes(windowFrame.size, _resizedFrame.size)) {
            frame.size = _originalFrame.size;
        }
        
        if ([defaults boolForKey:SRSidebarAutoresize]) {
            [parentWindow setFrame:frame display:YES];
        }
        _isResizedByDrawer = NO;
    }
}

//--------------------------------------------------------------//
#pragma mark -- NSTabView delegate --
//--------------------------------------------------------------//

- (BOOL)tabView:(NSTabView*)tabView 
        shouldSelectTabViewItem:(NSTabViewItem*)tabViewItem
{
    [self _prepareTabViewItemWithIdentifier:[tabViewItem identifier]];
    
    return YES;
}

- (void)tabView:(NSTabView*)tabView 
        didSelectTabViewItem:(NSTabViewItem*)tabViewItem
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get tab view identifier
    id  identifier;
    identifier = [tabViewItem identifier];
    
    // Set selected tab in default database
    int selectedTab;
    selectedTab = [self tabOfIdentifier:identifier];
    if (selectedTab != -1) {
        [defaults setInteger:selectedTab forKey:SRMainWindowSidebarSelectedTab];
    }
}

@end
