/*
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"

@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;
    
    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];
    
    // Select tab selected previously
    int selectedTab;
    selectedTab = [defaults integerForKey:SRMainWindowSidebarSelectedTab];
    [self showTab:selectedTab];
}

- (void)dealloc
{
    [_bookmarksController release];
    [_historyController release];
    [_downloadController 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 --
//--------------------------------------------------------------//

- (SRSidebarTab)selectedTab
{
    NSTabViewItem *tab = [_drawerTab selectedTabViewItem];
    NSString *identifier = [tab identifier];
    
    if([identifier isEqualToString:@"bookmark"]) {
        return SRSidebarBookmarkTab;
    }
    else if([identifier isEqualToString:@"history"]) {
        return SRSidebarHistoryTab;
    }
    else if([identifier isEqualToString:@"download"]) {
        return SRSidebarDownloadTab;
    }
    else {
        return -1;
    }
}

- (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;
}

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

- (NSDrawer*)drawer
{
    return _drawer;
}

- (void)_prepareTabViewItemWithIdentifier:(id)identifier
{
    // Get tab view item
    NSTabViewItem*  item;
    int             subviewCount;
    item = [_drawerTab tabViewItemAtIndex:
            [_drawerTab indexOfTabViewItemWithIdentifier:identifier]];
    subviewCount = [[[item view] subviews] count];
    
    // For bookmark
    if ([identifier isEqualToString:@"bookmark"]) {
        if (!_bookmarksController || subviewCount == 0) {
            // Load bookmarks 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
            [self historyController];
            
            // Put it in tab view
            [item setView:[_historyController view]];
        }
    }
    // For download
    if ([identifier isEqualToString:@"download"]) {
        if (!_downloadController || subviewCount == 0) {
            // Load download controller
            [self downloadController];
            
            // Put it in tab view
            [item setView:[_downloadController view]];
        }
    }
}

- (void)showTab:(SRSidebarTab)tab
{
    switch (tab) {
    case SRSidebarBookmarkTab: {
        if ([_drawer state] != NSDrawerClosedState) {
            [self _prepareTabViewItemWithIdentifier:@"bookmark"];
        }
        [_drawerTab selectTabViewItemWithIdentifier:@"bookmark"];
        break;
    }
    case SRSidebarHistoryTab: {
        if ([_drawer state] != NSDrawerClosedState) {
            [self _prepareTabViewItemWithIdentifier:@"history"];
        }
        [_drawerTab selectTabViewItemWithIdentifier:@"history"];
        break;
    }
    case SRSidebarDownloadTab: {
        if ([_drawer state] != NSDrawerClosedState) {
            [self _prepareTabViewItemWithIdentifier:@"download"];
        }
        [_drawerTab selectTabViewItemWithIdentifier:@"download"];
        break;
    }
    }
}

- (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 -- NSDrawer delegate --
//--------------------------------------------------------------//

- (void)drawerWillOpen:(NSNotification*)notification
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Prepare for tab view item
    [self _prepareTabViewItemWithIdentifier:[[_drawerTab selectedTabViewItem] identifier]];
    
    // 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
    NSRectEdge  edge;
    NSSize      contentSize;
    NSRect      windowFrame, withDrawerFrame, visibleFrame;
    static int  _outsideBorder = 12;
    edge = [_drawer edge];
    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 = -1;
    if ([identifier isEqualToString:@"bookmark"]) {
        selectedTab = SRSidebarBookmarkTab;
    }
    if ([identifier isEqualToString:@"history"]) {
        selectedTab = SRSidebarHistoryTab;
    }
    if ([identifier isEqualToString:@"download"]) {
        selectedTab = SRSidebarDownloadTab;
    }
    
    if (selectedTab != -1) {
        [defaults setInteger:selectedTab forKey:SRMainWindowSidebarSelectedTab];
    }
}

@end
