/*
SRBrowserController.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 "SRConstants.h"

#import "SRBookmark.h"

#import "SRAppController.h"
#import "SRBookmarkController.h"
#import "SRBrowserController.h"
#import "SRBrowserDocument.h"
#import "SRDefaultKeys.h"
#import "SRDocumentController.h"
#import "SRDownloadManager.h"
#import "SRFullScreenController.h"
#import "SRPageController.h"
#import "SRSearchFieldController.h"
#import "SRIconManager.h"
#import "SRURLCompleteDataSource.h"

#import "SRMenu.h"
#import "SRBookmarkBar.h"
#import "SRSearchField.h"
#import "SRStatusBar.h"
#import "SRToolbarItem.h"

#import "SRPlugInController.h"

#import "SRPrefDefaultKeys.h"

#import "SRWebView.h"

// Nofitication
NSString*   SRBrowserDidCommitLoad = @"SRBrowserDidCommitLoad";
NSString*   SRBrowserDidReceiveServerRedirect = @"SRBrowserDidReceiveServerRedirect";
NSString*   SRBrowserTitleReceived = @"SRBrowserTitleReceived";
NSString*   SRBrowserProgressStart = @"SRBrowserProgressStart";
NSString*   SRBrowserProgressFinish = @"SRBrowserProgressFinish";
NSString*   SRBrowserDidBecomeMain = @"SRBrowserDidBecomeMain";
NSString*   SRBrowserDidResignMain = @"SRBrowserDidResignMain";
NSString*   SRBrowserSelectedTabChanged = @"SRBrowserSelectedTabChanged";

// Toolbar identifier
NSString*   SRBrowserToolbarIdentifier = @"SRBrowserToolbarIdentifier";
NSString*   SRBrowserToolbarLabelTable = @"BrowserToolbar";

// Toolbar items
NSString*   SRBrowserGoBackItem = @"SRGoBack";
NSString*   SRBrowserGoForwardItem = @"SRGoForward";
NSString*   SRBrowserReloadPageItem = @"SRReloadPage";
NSString*   SRBrowserStopLoadingItem = @"SRStopLoading";
NSString*   SRBrowserGoHomeItem = @"SRGoHome";
NSString*   SRBrowserURLItem = @"SRURL";
NSString*   SRBrowserSearchItem = @"SRSearch";
NSString*   SRBrowserNewTabItem = @"SRNewTab";
NSString*   SRBrowserCloseTabItem = @"SRCloseTab";
NSString*   SRBrowserShelfItem = @"SRShelf";
NSString*   SRBrowserFullScreenItem = @"SRFullScreen";
NSString*   SRBrowserPrintPageItem = @"SRPrintPage";
NSString*   SRBrowserAddBookmarkItem = @"SRAddBookmark";
NSString*   SRBrowserBiggerTextItem = @"SRBiggerText";
NSString*   SRBrowserSmallerTextItem = @"SRSmallerText";
NSString*   SRBrowserBookmarkPanelItem = @"SRBookmarkPanel";
NSString*   SRBrowserHistoryPanelItem = @"SRHistoryPanel";
NSString*   SRBrowserPageInfoPanelItem = @"SRPageInfoPanel";
NSString*   SRBrowserFindPanelItem = @"SRFindPanel";
NSString*   SRBrowserDownloadPanelItem = @"SRDownloadPanel";
NSString*   SRBrowserRSSPanelItem = @"SRRSSPanel";

// Toolbar icons
NSDictionary*   SRAquaIconImageDict = nil;
NSDictionary*   SRMetalIconImageDict = nil;

// Full screen
static BOOL     _isFullScreen;

@implementation SRBrowserController

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

static NSMutableArray*  _browserControllers = nil;

+ (NSArray*)browserControllers
{
    return _browserControllers;
}

+ (SRBrowserController*)mainBrowserController
{
    NSEnumerator*           enumerator;
    SRBrowserController*    browserController;
    enumerator = [_browserControllers objectEnumerator];
    while (browserController = [enumerator nextObject]) {
        if ([[browserController window] isMainWindow]) {
            return browserController;
        }
    }
    
    return nil;
}

+ (BOOL)isFullScreen
{
    return _isFullScreen;
}

- (id)init
{
    self = [super initWithWindowNibName:@"BrowserWindow"];
    if (!self) {
        return nil;
    }
    
    // Register itself
    if (!_browserControllers) {
        // Crreate array which dose not retain contents
        CFArrayCallBacks    callbacks = { 0, NULL, NULL, NULL, NULL };
        _browserControllers = (NSMutableArray*)CFArrayCreateMutable(NULL, 0, &callbacks);
    }
    [_browserControllers addObject:self];
    
    // Initialize member variables
    _pageControllers = [[NSMutableArray array] retain];
    _searchFieldController = [[SRSearchFieldController alloc] init];
    [_searchFieldController setBrowserController:self];
    [_searchFieldController setSearchField:[self searchField]];
    _tabExposeController = [[SRTabExposeController alloc] init];
    [_tabExposeController setBrowserController:self];
    
    return self;
}

- (void)windowWillLoad
{
    // Register notifications
    NSNotificationCenter*   center;
    center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(pageDidStartProvisionalLoad:) 
            name:SRPageDidStartProvisionalLoad object:nil];
    [center addObserver:self selector:@selector(pageDidCommitLoad:) 
            name:SRPageDidCommitLoad object:nil];
    [center addObserver:self selector:@selector(pageDidFinishLoad:) 
            name:SRPageDidFinishLoad object:nil];
    [center addObserver:self selector:@selector(pageDidReceiveServerRedirect:) 
            name:SRPageDidReceiveServerRedirect object:nil];
    [center addObserver:self selector:@selector(pageTitleReceived:) 
            name:SRPageTitleReceived object:nil];
    [center addObserver:self selector:@selector(pageIconReceived:) 
            name:SRPageIconReceived object:nil];
    [center addObserver:self selector:@selector(pageProgressStart:) 
            name:SRPageProgressStart object:nil];
    [center addObserver:self selector:@selector(pageProgressEstimateChanged:) 
            name:SRPageProgressEstimateChanged object:nil];
    [center addObserver:self selector:@selector(pageProgressFinish:) 
            name:SRPageProgressFinish object:nil];
    
    [center addObserver:self selector:@selector(bookmarkBarHeightChanged:) 
            name:SRBookmarkBarHeightChanged object:_bookmarkBar];
    
    [center addObserver:self selector:@selector(hmTabItemAdded:) 
            name:HMTabViewItemAdded object:_tabView];
    
    // Register key value observation
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Bookmark preference
    [defaults addObserver:self forKeyPath:SRBookmarkBarType 
            options:NSKeyValueObservingOptionNew context:NULL];
    [defaults addObserver:self forKeyPath:SRBookmarkBarUseMultiLine 
            options:NSKeyValueObservingOptionNew context:NULL];
    
    // Tab preference
    [defaults addObserver:self forKeyPath:SRTabStyle 
            options:NSKeyValueObservingOptionNew context:NULL];
    [defaults addObserver:self forKeyPath:SRPageDockStyle 
            options:NSKeyValueObservingOptionNew context:NULL];
}

- (NSButton*)_createStatusButtonWithImageName:(NSString*)imageName 
        altImageName:(NSString*)altImageName action:(SEL)action
{
    NSImage*    image;
    NSImage*    altImage;
    NSRect      buttonFrame;
    NSButton*   button;
    image = [NSImage imageNamed:imageName];
    altImage = [NSImage imageNamed:altImageName];
    buttonFrame.origin = NSZeroPoint;
    buttonFrame.size = [image size];
    button = [[NSButton alloc] initWithFrame:buttonFrame];
    [button autorelease];
    if (image) {
        [button setImage:image];
    }
    if (altImage) {
        [button setAlternateImage:altImage];
    }
    [button setBezelStyle:NSRegularSquareBezelStyle];
    [button setButtonType:NSMomentaryChangeButton];
    [button setBordered:NO];
    [button setTarget:self];
    [button setAction:action];
    
    return button;
}

- (void)windowDidLoad
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get default window size
    NSString*   sizeString;
    sizeString = [defaults objectForKey:SRBrowserWindowContentSize];
    
    // Bookmarks bar and status bar visiblity
    [self setBookmarkBarVisible:[defaults boolForKey:SRBrowserWindowBookmarkBarVisible] display:NO];
    [self setStatusBarVisible:YES display:NO];
    
    // Get window
    HMWindow*   window;
    window = (HMWindow*)[self window];
    
    // Set default window size
    if (sizeString) {
        // Restore size
        NSSize  size;
        size = NSSizeFromString(sizeString);
        
        if (size.width > 200 && size.height > 200) { // Minimum size
            // Make window default size
            [window setContentSize:size];
        }
    }
    
    // For first window
    if ([[[NSDocumentController sharedDocumentController] documents] count] == 1) {
        // Get default window origin
        NSString*   originString;
        originString = [defaults objectForKey:SRBrowserWindowFrameOrigin];
        if (originString) {
            // Restore origin
            NSPoint origin;
            origin = NSPointFromString(originString);
            
            if (!NSEqualPoints(origin, NSZeroPoint)) {
                // Make window default origin
                [window setFrameTopLeftPoint:origin];
            }
        }
    }
    // For other windows
    else {
        // Get front window
        NSWindow*   frontWindow;
        frontWindow = SRGetFrontBrowserWindow();
        if (frontWindow) {
            // Calculate cascaded point
            NSRect  frontWindowFrame;
            NSPoint frontWindowPoint;
            frontWindowFrame = [frontWindow frame];
            frontWindowPoint = frontWindowFrame.origin;
            frontWindowPoint.y += frontWindowFrame.size.height;
            [window setFrameTopLeftPoint:[window cascadeTopLeftFromPoint:frontWindowPoint]];
        }
    }
    
    // Load toolbar icons
    [[self class] updateToolbarIcons];
    
    // Configure window
    [window setPassMenuValidationToDelegate:YES];
    
    // Create toolbar
    NSToolbar*  toolbar;
    toolbar = [[NSToolbar alloc] 
            initWithIdentifier:SRBrowserToolbarIdentifier];
    [toolbar setDelegate:self];
    [toolbar setAllowsUserCustomization:YES];
    [toolbar setAutosavesConfiguration:YES];
    
    // Set default configuration
    NSMutableDictionary*    config;
    config = [NSMutableDictionary dictionaryWithDictionary:[toolbar configurationDictionary]];
    [config setObject:[NSNumber numberWithInt:NSToolbarDisplayModeIconOnly] forKey:@"TB Display Mode"];
    [config setObject:[NSNumber numberWithBool:YES] forKey:@"TB Is Shown"];
    [toolbar setConfigurationFromDictionary:config];
    
    [window setToolbar:toolbar];
    [toolbar release];
    
    // Configure bookmark bar
    [_bookmarkBar setTarget:self];
    [_bookmarkBar setAction:@selector(openBookmarkBarBookmarkAction:)];
    
    SRBookmark* bookmarkForBookmarkBar;
    bookmarkForBookmarkBar = [[SRAppController sharedInstance] bookmarkForBookmarkBar];
    if (bookmarkForBookmarkBar) {
        // Get selected browser
        NSString*   browser;
        browser = [defaults objectForKey:SRBookmarkBarType];
        if (!browser || ![browser isKindOfClass:[NSString class]]) {
            browser = SRBrowserShiira;
        }
        
        // Get bookmark for bookmark bar
        SRBookmark* bookmark;
        bookmark = [[SRAppController sharedInstance] 
                bookmarkForBookmarkBarOfBrowser:browser];
        if (bookmark) {
            // Set bookmark
            [_bookmarkBar setBookmarks:[bookmark sortedChildren]];
        }
    }
    
    [_bookmarkBar setWrap:[defaults boolForKey:SRBookmarkBarUseMultiLine]];
    [_bookmarkBar sizeToFit];
    
    // Configure status bar
    HMEtchedTextField*  statusTextField;
    statusTextField = [_statusBar statusTextField];
    [statusTextField bind:@"value" 
            toObject:_browserController withKeyPath:@"selection.status" options:nil];
    
    _tabExposeButton = [[self _createStatusButtonWithImageName:@"tabExpose" 
            altImageName:@"tabExposePressed" action:@selector(showAllTabsAction:)] retain];
    [[_tabExposeButton cell] setFocusRingType:NSFocusRingTypeNone];
    [_statusBar addButton:_tabExposeButton];
    
    _pageDockButton = [[self _createStatusButtonWithImageName:@"hidePageDock" 
            altImageName:@"hidePageDockPressed" action:@selector(togglePageDockAction:)] retain];
    [[_pageDockButton cell] setFocusRingType:NSFocusRingTypeNone];
    [_statusBar addButton:_pageDockButton];
    
    _feedButton = [[self _createStatusButtonWithImageName:@"statusFeed" 
            altImageName:nil action:@selector(toggleFeedAction:)] retain];
    [_feedButton setToolTip:NSLocalizedString(@"Show RSS articles", nil)];
    [[_feedButton cell] setFocusRingType:NSFocusRingTypeNone];
    
    _IDNButton = [[self _createStatusButtonWithImageName:@"statusIDN" 
            altImageName:@"statusIDNSelected" action:@selector(toggleIDNAction:)] retain];
    [_IDNButton setButtonType:NSToggleButton];
    [[_IDNButton cell] setFocusRingType:NSFocusRingTypeNone];
    
    _lockedButton = [[self _createStatusButtonWithImageName:@"statusLocked" 
            altImageName:@"statusLockedSelected" action:@selector(toggleLockedAction:)] retain];
    [_lockedButton setButtonType:NSToggleButton];
    [[_lockedButton cell] setFocusRingType:NSFocusRingTypeNone];
    
    _cookieButton = [[self _createStatusButtonWithImageName:@"statusCookie" 
            altImageName:@"statusCookieSelected" action:@selector(showCookieAction:)] retain];
    [_cookieButton setButtonType:NSMomentaryPushInButton];
    [_cookieButton setToolTip:NSLocalizedString(@"Show cookies info", nil)];
    [[_cookieButton cell] setFocusRingType:NSFocusRingTypeNone];
    
    // Configure tab view
    int pageDockHeight;
    pageDockHeight = [defaults integerForKey:SRPageDockHeight];
    if (pageDockHeight > 0) {
        [_tabView setTabItemViewHigh:pageDockHeight];
    }
    [_tabView setDelegate:self];
    [[_tabView tabItemGroupView] setDelegate:self];
    [[_tabView tabItemGroupView] addDraggedTypes:
            [NSArray arrayWithObjects:
                    WebURLsWithTitlesPboardType, HMTreeControllerObjectIdPboardType, nil]]; 
    [self setTabStyle:[defaults integerForKey:SRTabStyle]];
}

- (void)dealloc
{
    // Unregister itself
    [_browserControllers removeObject:self];
    
    // Remove itself
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    // Remove observer
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObserver:self forKeyPath:SRBookmarkBarType];
    [defaults removeObserver:self forKeyPath:SRBookmarkBarUseMultiLine];
    [defaults removeObserver:self forKeyPath:SRTabStyle];
    [defaults removeObserver:self forKeyPath:SRPageDockStyle];
    
    // Release instance variables
    [_pageControllers release], _pageControllers = nil;
    [_searchFieldController release], _searchFieldController = nil;
    [_tabExposeController release], _tabExposeController = nil;
    [_URLDataSource release], _URLDataSource = nil;
    [_locationURLDataSource release], _locationURLDataSource = nil;
    [_fullScreenWindow release], _fullScreenWindow = nil;
    [_fullScreenController release], _fullScreenController = nil;
    [_fullScreenImageController release], _fullScreenImageController = nil;
    
    [_tabExposeButton release], _tabExposeButton = nil;
    [_pageDockButton release], _pageDockButton = nil;
    [_feedButton release], _feedButton = nil;
    [_IDNButton release], _IDNButton = nil;
    [_lockedButton release], _lockedButton = nil;
    [_cookieButton release], _cookieButton = nil;
    
    NSMenu* fileMenu;
    fileMenu = SRFileMenu();
    if ([fileMenu delegate] == self) {
        [fileMenu setDelegate:[SRAppController sharedInstance]];
    }
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- Page controller --
//--------------------------------------------------------------//

- (NSArray*)pageControllers
{
    return _pageControllers;
}

- (SRPageController*)pageControllerAtIndex:(int)index
{
    if ([_pageControllers count] < index) {
        return nil;
    }
    
    return [_pageControllers objectAtIndex:index];
}

- (SRPageController*)pageControllerForView:(NSView*)view
{
    NSEnumerator*       enumerator;
    SRPageController*   pageController;
    enumerator = [_pageControllers objectEnumerator];
    while (pageController = [enumerator nextObject]) {
        if ([pageController webView] == view) {
            return pageController;
        }
    }
    
    return nil;
}

//--------------------------------------------------------------//
#pragma mark -- Search field controller --
//--------------------------------------------------------------//

- (SRSearchFieldController*)searchFieldController
{
    return _searchFieldController;
}

//--------------------------------------------------------------//
#pragma mark -- Tab management --
//--------------------------------------------------------------//

- (HMTabView*)tabView
{
    return _tabView;
}

- (SRPageController*)addNewTabWithLabel:(NSString*)label 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName 
        select:(BOOL)select
{
    NSArray*    pageControllers;
    pageControllers = [self addNewTabsWithLabels:[NSArray arrayWithObject:label] 
            frameName:frameName groupName:groupName selectLast:select];
    return [pageControllers objectAtIndex:0];
}

- (NSArray*)addNewTabsWithLabels:(NSArray*)labels 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName 
        selectLast:(BOOL)selectLast
{

    NSMutableArray* pageControllers;
    NSMutableArray* tabViewItems;
    pageControllers = [NSMutableArray array];
    tabViewItems = [NSMutableArray array];
    
    // Add new labels
    NSEnumerator*   enumerator;
    NSString*       label;
    HMTabViewItem*  tabViewItem;
    enumerator = [labels objectEnumerator];
    while (label = [enumerator nextObject]) {
        // Create page controller
        SRPageController*   pageController;
        pageController = [[SRPageController alloc] 
                initWithBrowserController:self label:label frameName:frameName groupName:groupName];
        [_pageControllers addObject:pageController];
        [pageController release];
        
        [pageControllers addObject:pageController];
        
        // Get tab view item
        tabViewItem = [pageController tabViewItem];
        [tabViewItems addObject:tabViewItem];
    }
    
    // Add tab view items
    BOOL    animation = NO;
    if ([_tabView hasThumbnail]) {
        animation = [_tabView numberOfTabViewItems] > 0;
    }
    [_tabView addTabViewItems:tabViewItems animation:animation];
    
    // Set delegate
    enumerator = [tabViewItems objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        [[tabViewItem tabItemView] setDelegate:self];
    }
    
    // Keep select item
    tabViewItem = [tabViewItems lastObject];
    _willSelectTabViewItem = selectLast ? tabViewItem : nil;
    
    return pageControllers;
}

- (SRPageController*)insertNewTabWithLabel:(NSString*)label 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName 
        atIndex:(unsigned int)index 
        select:(BOOL)select
{
    // Create page controller
    SRPageController*   pageController;
    pageController = [[SRPageController alloc] 
            initWithBrowserController:self label:label frameName:frameName groupName:groupName];
    if (index < [_pageControllers count]) {
        [_pageControllers insertObject:pageController atIndex:index];
    }
    else {
        [_pageControllers addObject:pageController];
    }
    [pageController release];
    
    // Add tab view item
    HMTabViewItem*  tabViewItem;
    tabViewItem = [pageController tabViewItem];
    if (index < [_pageControllers count]) {
        [_tabView insertTabViewItem:tabViewItem atIndex:index];
    }
    else {
        [_tabView addTabViewItem:tabViewItem];
    }
    [[tabViewItem tabItemView] setDelegate:self];
    
    // Select page controller
    if (select) {
        [_tabView selectTabViewItem:tabViewItem];
    }
    
    // Return web view
    return pageController;
}

- (void)removeTabAtIndex:(unsigned int)index
{
    [self removeTabAtIndexes:[NSIndexSet indexSetWithIndex:index]];
}

- (void)removeTabAtIndexes:(NSIndexSet*)indexSet
{
    // Remove tab view item
    [_tabView removeTabViewItems:[[_tabView tabViewItems] objectsAtIndexes:indexSet]];
}

- (void)selectLeftTab
{
}

- (void)selectRightTab
{
}

- (BOOL)isPageDockVisible
{
    return [_tabView isTabItemViewShown];
}

- (void)setPageDockVisible:(BOOL)isVisible
{
    // Update PageDock thumbnail image
    if (isVisible) {
        NSEnumerator*       enumerator;
        SRPageController*   pageController;
        enumerator = [_pageControllers objectEnumerator];
        while (pageController = [enumerator nextObject]) {
            [pageController updateDocumentViewImage];
        }
    }
    
    // Set tab view visible
    [_tabView setTabItemViewShown:isVisible];
    [_tabView updateLayout];
    
    // Set button image
    NSImage*    image;
    NSImage*    altImage;
    image = [NSImage imageNamed:isVisible ? @"hidePageDock" : @"showPageDock"];
    altImage = [NSImage imageNamed:isVisible ? @"hidePageDockPressed" : @"showPageDockPressed"];
    [_pageDockButton setImage:image];
    [_pageDockButton setAlternateImage:altImage];
}

//--------------------------------------------------------------//
#pragma mark -- Web view and toolbar items --
//--------------------------------------------------------------//

- (SRPageController*)selectedPageController
{
    // Get selected index of tab
    int index;
    index = [_tabView indexOfSelectedTabViewItem];
    if (index == NSNotFound || [_pageControllers count] <= index) {
        return nil;
    }
    
    return [_pageControllers objectAtIndex:index];
}

- (HMImageComboBox*)URLComboBox
{
    // Get URL combo box from toolbar items
    NSEnumerator*   enumerator;
    NSToolbarItem*  toolbarItem;
    enumerator = [[[[self window] toolbar] visibleItems] objectEnumerator];
    while (toolbarItem = [enumerator nextObject]) {
        if ([[toolbarItem itemIdentifier] isEqualToString:SRBrowserURLItem]) {
            return (HMImageComboBox*)[toolbarItem view];
        }
    }
    
    return nil;
}

- (HMImageComboBox*)URLComboBoxOnSheet
{
    // Return first children of location URL view
    NSArray*    subviews;
    subviews = [[self locationURLView] subviews];
    
    if ([subviews count] < 1) {
        return nil;
    }
    
    id  view;
    view = [subviews objectAtIndex:0];
    
    return view;
}

- (SRSearchField*)searchField
{
    // Get search field from toolbar items
    NSEnumerator*   enumerator;
    NSToolbarItem*  toolbarItem;
    enumerator = [[[[self window] toolbar] visibleItems] objectEnumerator];
    while (toolbarItem = [enumerator nextObject]) {
        if ([[toolbarItem itemIdentifier] isEqualToString:SRBrowserSearchItem]) {
            return (SRSearchField*)[toolbarItem view];
        }
    }
    
    return nil;
}

- (SRSearchField*)searchFieldOnSheet
{
    return nil;
}

//--------------------------------------------------------------//
#pragma mark -- Key value coding --
//--------------------------------------------------------------//

- (id)browserContent
{
    return _browserContent;
}

//--------------------------------------------------------------//
#pragma mark -- Opening page with request --
//--------------------------------------------------------------//

- (SRPageController*)_openRequest:(NSURLRequest*)request withPageController:(SRPageController*)pageController
{
    // Check scheme
    NSString*	scheme;
    NSString*   lowercase;
    scheme = [[request URL] scheme];
    lowercase = [scheme lowercaseString];
    if (scheme && ![scheme isEqualToString:lowercase]) {
        // Change scheme
        NSMutableString*    URLString;
        NSRange             range;
        URLString = [NSMutableString stringWithString:[[request URL] absoluteString]];
        range = [URLString rangeOfString:scheme];
        if (range.location != NSNotFound) {
            [URLString replaceCharactersInRange:range withString:lowercase];
        }
        
        request = [self createRequestWithURLString:URLString];
    }
    
    // For feed scheme
    scheme = [[request URL] scheme];
    if ([scheme isEqualToString:@"feed"]) {
        // Change scheme
        NSMutableString*    URLString;
        NSRange             range;
        URLString = [NSMutableString stringWithString:[[request URL] absoluteString]];
        range = [URLString rangeOfString:scheme];
        if (range.location != NSNotFound) {
            [URLString replaceCharactersInRange:range withString:@"http"];
        }
        
        request = [self createRequestWithURLString:URLString];
    }
    
    // Open request
    [pageController openRequest:request];
    
    // Set URL string
    [_browserContent setValue:[[request URL] absoluteString] forKey:@"URLString"];
    
    return pageController;
}

- (SRPageController*)openRequest:(NSURLRequest*)request
{
    // Open request with selected page controller
    return [self _openRequest:request withPageController:[self selectedPageController]];
}

- (SRPageController*)openRequest:(NSURLRequest*)request atIndex:(int)index
{
    // Open request with page controller at index
    return [self _openRequest:request withPageController:[self pageControllerAtIndex:index]];
}

- (id)openRequest:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName 
        withOpenAction:(SROpenActionType)openAction
{
    switch (openAction) {
    case SROpenAction: {
        return [self openRequest:request];
    }
    case SROpenInNewTabAction: {
        return [self openInNewTabRequest:request frameName:frameName groupName:groupName select:YES];
    }
    case SROpenInNewBackgroundTabAction: {
        return [self openInNewTabRequest:request frameName:frameName groupName:groupName select:NO];
    }
    case SROpenInNewWindowAction: {
        return [self openInNewWindowRequest:request frameName:frameName groupName:groupName];
    }
    case SROpenInNewBackgroundWindowAction: {
        return [self openInNewBackgroundWindowRequest:request frameName:frameName groupName:groupName];
    }
    case SROpenOptionAction: {
        // Download it
        NSURLDownload*  download;
        download = [[SRDownloadManager sharedInstance] startDownloadWithRequest:request];
        
        // Show download panel automatically
        [[SRDownloadManager sharedInstance] showDownloadPanelAutomatically];
        
        return download;
    }
    }
    
    // Never reach here
    return nil;
}

- (SRPageController*)openInNewTabRequest:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName
{
    return [self openInNewTabRequest:request 
            frameName:frameName 
            groupName:groupName 
            select:[[NSUserDefaults standardUserDefaults] boolForKey:SRTabSelectNewTabs]];
}

- (NSArray*)_createUntitledLabels:(int)numberOfLabels
{
    // Get untitled name
    NSString*   untitled;
    untitled = NSLocalizedString(@"Untitled", nil);
    
    // Get largest label number
    int                 largestNumber = -1;
    NSEnumerator*       enumerator;
    SRPageController*   pageController;
    enumerator = [_pageControllers objectEnumerator];
    while (pageController = [enumerator nextObject]) {
        // Find 'untitled' label
        NSString*   label;
        label = [[pageController tabViewItem] label];
        
        NSRange range;
        range = [label rangeOfString:untitled options:NSLiteralSearch];
        if (range.location == 0) {
            int number = 0;
            if (range.length + 1 < [label length]) {
                number = [[label substringFromIndex:range.length + 1] intValue];
            }
            if (number > largestNumber) {
                largestNumber = number;
            }
        }
    }
    
    if (largestNumber == -1) {
        largestNumber = 1;
    }
    else {
        if (largestNumber == 0) {
            largestNumber = 1;
        }
        largestNumber += 1;
    }
    
    // Create untitled labels
    NSMutableArray* labels;
    labels = [NSMutableArray array];
    
    int i;
    for (i = largestNumber; i < largestNumber + numberOfLabels; i++) {
        if (i == 1) {
            [labels addObject:NSLocalizedString(@"Untitled", nil)];
        }
        else {
            [labels addObject:[NSString stringWithFormat:@"%@ %d", 
                    NSLocalizedString(@"Untitled", nil), i]];
        }
    }
    
    return labels;
}

- (NSString*)_createUntitledLabel
{
    return [[self _createUntitledLabels:1] objectAtIndex:0];
}

- (SRPageController*)openInNewTabRequest:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName 
        select:(BOOL)select
{
    // Create untitled label
    NSString*   label;
    label = [self _createUntitledLabel];
    
    // Add new tab
    [self addNewTabWithLabel:label 
            frameName:frameName 
            groupName:groupName 
            select:select];
    
    // Open request with last page controller
    return [self _openRequest:request withPageController:[_pageControllers lastObject]];
}

- (NSArray*)openInNewTabRequests:(NSArray*)requests 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName 
        select:(BOOL)select
{
    // Check first tab is empty or not
    BOOL    useFirstTab = NO;
    if ([_pageControllers count] == 1) {
        WebView*    webView;
        webView = [[_pageControllers objectAtIndex:0] webView];
        if (![[webView mainFrame] dataSource] && 
            ![[webView mainFrame] provisionalDataSource])
        {
            useFirstTab = YES;
        }
    }
    
    // Create untitled labels
    int         count;
    NSArray*    labels;
    count = [requests count];
    if (useFirstTab) {
        count--;
    }
    labels = [self _createUntitledLabels:count];
    
    // Add new tabs
    NSMutableArray* pageControllers;
    pageControllers = [NSMutableArray arrayWithArray:[self addNewTabsWithLabels:labels 
            frameName:frameName 
            groupName:groupName 
            selectLast:select]];
    if (useFirstTab) {
        [pageControllers insertObject:[_pageControllers objectAtIndex:0] atIndex:0];
    }
    
    // Open requests
    int i;
    for (i = 0; i < [requests count]; i++) {
        NSURLRequest*       request;
        SRPageController*   pageController;
        request = [requests objectAtIndex:i];
        pageController = [pageControllers objectAtIndex:i];
        
        [self _openRequest:request withPageController:pageController];
    }
    
    return pageControllers;
}

- (SRBrowserDocument*)openInNewWindowRequest:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName
{
    // Create new document
    SRDocumentController*   documentController;
    SRBrowserDocument*      document;
    documentController = [NSDocumentController sharedDocumentController];
    document = [documentController makeUntitledDocumentOfType:SRHTMLDocumentType];
    [documentController addDocument:document];
    
    // Make window controllers
    [document makeWindowControllersWithFrameName:frameName groupName:groupName];
    
    // Get browser controller
    SRBrowserController*    browserController;
    browserController = [document browserController];
    
    // Get window and make it front
    [[browserController window] makeKeyAndOrderFront:self];
    
    // Open request in new window
    [browserController openRequest:request];
    
    return document;
}

- (SRBrowserDocument*)openInNewBackgroundWindowRequest:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        groupName:(NSString*)groupName
{
    // Create new document
    SRDocumentController*   documentController;
    SRBrowserDocument*      document;
    documentController = [NSDocumentController sharedDocumentController];
    document = [documentController makeUntitledDocumentOfType:SRHTMLDocumentType];
    [documentController addDocument:document];
    
    // Make window controllers
    [document makeWindowControllersWithFrameName:frameName groupName:groupName];
    
    // Get browser controller
    SRBrowserController*    browserController;
    browserController = [document browserController];
    
    // Get window and make it back
    [[browserController window] orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
    
    // Open bookmark in new window
    [browserController openRequest:request];
    
    return document;
}

//--------------------------------------------------------------//
#pragma mark -- Opening page with URL string --
//--------------------------------------------------------------//

- (NSURLRequest*)createRequestWithURL:(NSURL*)url
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get timeout
    int timeout;
    timeout = [defaults integerForKey:SRGeneralTimeout];
    if (timeout == -1) {
        // Never timeout
        timeout = 60000;
    }
    
    // Create request
    return [NSURLRequest requestWithURL:url 
            cachePolicy:NSURLRequestUseProtocolCachePolicy 
            timeoutInterval:timeout];
}

- (NSURLRequest*)createRequestWithURLString:(NSString*)URLString
{
    return [self createRequestWithURL:[NSURL _web_URLWithUserTypedString:URLString]];
}

- (SRPageController*)openURLString:(NSString*)URLString
{
    // Create and open request
    return [self openRequest:[self createRequestWithURLString:URLString]];
}

- (SRPageController*)openURLString:(NSString*)URLString atIndex:(int)index
{
    // Create and open request
    return [self openRequest:[self createRequestWithURLString:URLString] atIndex:index];
}

- (id)openURLString:(NSString*)URLString withOpenAction:(SROpenActionType)openAction
{
    // Create and open request
    return [self openRequest:[self createRequestWithURLString:URLString] 
            frameName:nil 
            groupName:nil 
            withOpenAction:openAction];
}

- (SRPageController*)openInNewTabURLString:(NSString*)URLString
{
    // Create and open request
    return [self openInNewTabRequest:[self createRequestWithURLString:URLString] 
            frameName:nil 
            groupName:nil];
}

- (SRPageController*)openInNewTabURLString:(NSString*)URLString select:(BOOL)select
{
    // Create and open request
    return [self openInNewTabRequest:[self createRequestWithURLString:URLString] 
            frameName:nil 
            groupName:nil 
            select:select];
}

- (SRBrowserDocument*)openInNewWindowURLString:(NSString*)URLString
{
    // Create and open request
    return [self openInNewWindowRequest:[self createRequestWithURLString:URLString] 
            frameName:nil 
            groupName:nil];
}

- (SRBrowserDocument*)openInNewBackgroundWindowURLString:(NSString*)URLString
{
    // Create and open request
    return [self openInNewBackgroundWindowRequest:[self createRequestWithURLString:URLString] 
            frameName:nil 
            groupName:nil];
}

- (NSArray*)openInNewTabsURLStrings:(NSArray*)URLStrings select:(BOOL)select
{
    NSMutableArray* requests;
    requests = [NSMutableArray array];
    
    // Create requests
    NSEnumerator*   enumerator;
    NSString*       URLString;
    enumerator = [URLStrings objectEnumerator];
    while (URLString = [enumerator nextObject]) {
        NSURLRequest*   request;
        request = [self createRequestWithURLString:URLString];
        if (request) {
            [requests addObject:request];
        }
    }
    
    return [self openInNewTabRequests:requests frameName:nil groupName:nil select:select];
}

//--------------------------------------------------------------//
#pragma mark -- Opening page with URLs --
//--------------------------------------------------------------//

- (SRPageController*)openURL:(NSURL*)url
{
    // Create and open request
    return [self openRequest:[self createRequestWithURL:url]];
}

- (SRPageController*)openURL:(NSURL*)url atIndex:(int)index
{
    // Create and open request
    return [self openRequest:[self createRequestWithURL:url] atIndex:index];
}

- (id)openURL:(NSURL*)url withOpenAction:(SROpenActionType)openAction
{
    // Create and open request
    return [self openRequest:[self createRequestWithURL:url] 
            frameName:nil 
            groupName:nil 
            withOpenAction:openAction];
}

- (SRPageController*)openInNewTabURL:(NSURL*)url
{
    // Create and open request
    return [self openInNewTabRequest:[self createRequestWithURL:url] 
            frameName:nil 
            groupName:nil];
}

- (SRPageController*)openInNewTabURL:(NSURL*)url select:(BOOL)select
{
    // Create and open request
    return [self openInNewTabRequest:[self createRequestWithURL:url] 
            frameName:nil 
            groupName:nil 
            select:select];
}

- (SRBrowserDocument*)openInNewWindowURL:(NSURL*)url
{
    // Create and open request
    return [self openInNewWindowRequest:[self createRequestWithURL:url] 
            frameName:nil 
            groupName:nil];
}

- (SRBrowserDocument*)openInNewBackgroundWindowURL:(NSURL*)url
{
    // Create and open request
    return [self openInNewBackgroundWindowRequest:[self createRequestWithURL:url] 
            frameName:nil 
            groupName:nil];
}

//--------------------------------------------------------------//
#pragma mark -- Opening page with bookmark --
//--------------------------------------------------------------//

- (SRPageController*)openBookmark:(SRBookmark*)bookmark
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openURLString:[bookmark valueForKey:@"urlString"]];
    }
    
    return nil;
}

- (SRPageController*)openBookmark:(SRBookmark*)bookmark atIndex:(int)index
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openURLString:[bookmark valueForKey:@"urlString"] atIndex:index];
    }
    
    return nil;
}

- (id)openBookmark:(SRBookmark*)bookmark withOpenAction:(SROpenActionType)openAction
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openURLString:[bookmark valueForKey:@"urlString"] withOpenAction:openAction];
    }
    
    return nil;
}

- (SRPageController*)openInNewTabBookmark:(SRBookmark*)bookmark
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openInNewTabURLString:[bookmark valueForKey:@"urlString"]];
    }
    
    return nil;
}

- (SRPageController*)openInNewTabBookmark:(SRBookmark*)bookmark select:(BOOL)select
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openInNewTabURLString:[bookmark valueForKey:@"urlString"] select:select];
    }
    
    return nil;
}

- (SRBrowserDocument*)openInNewWindowBookmark:(SRBookmark*)bookmark
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openInNewWindowURLString:[bookmark valueForKey:@"urlString"]];
    }
    
    return nil;
}

- (SRBrowserDocument*)openInNewBackgroundWindowBookmark:(SRBookmark*)bookmark
{
    // For HTML bookmark
    if (![[bookmark isFolder] boolValue]) {
        // Open URL string
        return [self openInNewBackgroundWindowURLString:[bookmark valueForKey:@"urlString"]];
    }
    
    return nil;
}

- (NSArray*)openInTabsBookmark:(SRBookmark*)bookmark
{
    // For bookmark folder
    if ([[bookmark isFolder] boolValue]) {
        // Open children
        return [self openInTabsBookmarks:[bookmark sortedChildren]];
    }
    
    return nil;
}

- (NSArray*)openInTabsBookmarks:(NSArray*)bookmarks
{
    // Collect URL strings
    NSMutableArray* URLStrings;
    NSEnumerator*   enumerator;
    SRBookmark*     bookmark;
    URLStrings = [NSMutableArray array];
    enumerator = [bookmarks objectEnumerator];
    while (bookmark = [enumerator nextObject]) {
        // Get URL string
        NSString*   URLString;
        URLString = [bookmark valueForKey:@"urlString"];
        if (URLString) {
            [URLStrings addObject:URLString];
        }
    }
    
    // Open URL strings
    return [self openInNewTabsURLStrings:URLStrings select:YES];
}

//--------------------------------------------------------------//
#pragma mark -- Opening page with history --
//--------------------------------------------------------------//

- (SRPageController*)openHistory:(WebHistoryItem*)historyItem
{
    // Open URL string
    return [self openURLString:[historyItem URLString]];
}

- (SRPageController*)openHistory:(WebHistoryItem*)historyItem atIndex:(int)index
{
    // Open URL string
    return [self openURLString:[historyItem URLString] atIndex:index];
}

- (id)openHistory:(WebHistoryItem*)historyItem withOpenAction:(SROpenActionType)openAction
{
    // Open URL string
    return [self openURLString:[historyItem URLString] withOpenAction:openAction];
}

- (SRPageController*)openInNewTabHistory:(WebHistoryItem*)historyItem
{
    // Open URL string
    return [self openInNewTabURLString:[historyItem URLString]];
}

- (SRPageController*)openInNewTabHistory:(WebHistoryItem*)historyItem select:(BOOL)select
{
    // Open URL string
    return [self openInNewTabURLString:[historyItem URLString] select:select];
}

- (SRBrowserDocument*)openInNewWindowHistory:(WebHistoryItem*)historyItem
{
    // Open URL string
    return [self openInNewWindowURLString:[historyItem URLString]];
}

- (SRBrowserDocument*)openInNewBackgroundWindowHistory:(WebHistoryItem*)historyItem
{
    // Open URL string
    return [self openInNewBackgroundWindowURLString:[historyItem URLString]];
}

- (NSArray*)openInTabsHistory:(NSArray*)historyItems
{
    return nil;
}

//--------------------------------------------------------------//
#pragma mark -- Opening Shelf --
//--------------------------------------------------------------//

- (SRPageController*)openShelf:(NSString*)shelfId
{
    // Create URL for shelf
    NSURL*  url;
    url = [NSURL URLWithString:@"shiira://shelf"];
    
    // If shelf is already opend, use it
    WebView*        shelfWebView = nil;
    NSEnumerator*   enumerator;
    HMTabViewItem*  tabViewItem;
    enumerator = [[_tabView tabViewItems] objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        WebView*    webView;
        webView = (WebView*)[tabViewItem view];
        if ([[[[[webView mainFrame] dataSource] request] URL] isEqual:url]) {
            shelfWebView = webView;
            break;
        }
    }
    
    if (shelfWebView && tabViewItem) {
        // Select it
        [_tabView selectTabViewItem:tabViewItem];
    }
    else {
        // Check selected web view
        WebView*    webView;
        webView = [[self selectedPageController] webView];
        if (webView && ![[webView mainFrame] dataSource]) {
            [[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:url]];
            shelfWebView = webView;
        }
        else {
            // Create web view for shelf
            shelfWebView = [[self openInNewTabURL:url select:YES] webView];
        }
    }
    
    // Get page controller for web view
    SRPageController*   pageController;
    pageController = [self pageControllerForView:shelfWebView];
    
    // Show shelf with ID
    [pageController setSelectedShelfId:shelfId];
    
    return pageController;
}

//--------------------------------------------------------------//
#pragma mark -- Opening URL --
//--------------------------------------------------------------//

- (WebView*)reloadURLIfExists:(NSURL*)url
{
    NSEnumerator*   enumerator;
    HMTabViewItem*  tabViewItem;
    enumerator = [[_tabView tabViewItems] objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        WebView*    webView;
        webView = (WebView*)[tabViewItem view];
        if ([webView isKindOfClass:[WebView class]]) {
            if ([url isEqual:[[[[webView mainFrame] dataSource] request] URL]]) {
                // Select and reload URL
                [_tabView selectTabViewItem:tabViewItem];
                [webView reload:self];
                [self showWindow:self];
                
                return webView;
            }
        }
    }
    
    return nil;
}

//--------------------------------------------------------------//
#pragma mark -- Close page --
//--------------------------------------------------------------//

- (void)closePageController:(SRPageController*)pageController
{
    // Check page controller
    if (![_pageControllers containsObject:pageController]) {
        return;
    }
    
    // Where there is only one tab
    if ([_tabView numberOfTabViewItems] == 1) {
        // Close itself
        [[self window] performClose:self];
        return;
    }
    
    // Close tab
    int index;
    index = [_pageControllers indexOfObject:pageController];
    [self removeTabAtIndex:index];
}

//--------------------------------------------------------------//
#pragma mark -- Toolbar icon --
//--------------------------------------------------------------//

+ (NSArray*)toolbarItemIdentifiers
{
    static NSArray* _toolbarItems = nil;
    if (!_toolbarItems) {
        _toolbarItems = [[NSArray arrayWithObjects:
                SRBrowserGoBackItem, SRBrowserGoForwardItem, 
                SRBrowserReloadPageItem, SRBrowserStopLoadingItem, 
                SRBrowserGoHomeItem, SRBrowserURLItem, 
                SRBrowserSearchItem, SRBrowserShelfItem, 
                SRBrowserFullScreenItem, 
                SRBrowserNewTabItem, SRBrowserCloseTabItem, 
                SRBrowserPrintPageItem, 
                SRBrowserAddBookmarkItem, 
                SRBrowserBiggerTextItem, SRBrowserSmallerTextItem, 
                SRBrowserFindPanelItem, SRBrowserPageInfoPanelItem, 
                SRBrowserBookmarkPanelItem, SRBrowserHistoryPanelItem, 
                SRBrowserDownloadPanelItem, SRBrowserRSSPanelItem, 
                nil] retain];
    }
    
    NSMutableArray* toolbarItems;
    toolbarItems = [NSMutableArray arrayWithArray:_toolbarItems];
    
    // Add plug-in toolbar item
    NSArray*        plugInInfoDicts;
    NSEnumerator*   enumerator;
    NSDictionary*   infoDict;
    plugInInfoDicts = [[SRPlugInController sharedInstance] plugInInfoDicts];
    enumerator = [plugInInfoDicts objectEnumerator];
    while (infoDict = [enumerator nextObject]) {
        if ([infoDict objectForKey:@"SRPlugInScheme"] && 
            [infoDict objectForKey:@"CFBundleIdentifier"])
        {
            [toolbarItems addObject:[infoDict objectForKey:@"CFBundleIdentifier"]];
        }
    }
    
    return toolbarItems;
}

+ (NSArray*)defaultToolbarItemIdentifiers
{
    static NSArray* _toolbarDefaultItems = nil;
    if (!_toolbarDefaultItems) {
        _toolbarDefaultItems = [[NSArray arrayWithObjects:
                SRBrowserGoBackItem, SRBrowserGoForwardItem, 
                SRBrowserReloadPageItem, SRBrowserStopLoadingItem, 
                SRBrowserURLItem, 
                SRBrowserAddBookmarkItem, SRBrowserShelfItem, 
                SRBrowserBookmarkPanelItem, SRBrowserHistoryPanelItem, 
                SRBrowserSearchItem, SRBrowserNewTabItem, 
                nil] retain];
    }
    
    return _toolbarDefaultItems;
}

+ (void)updateToolbarIcons
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Load aqua icons
    NSString*       iconName;
    NSDictionary*   iconImageDict;
    iconName = [defaults stringForKey:SRThemeAquaIconNameKey];
    if (!iconName) {
        iconName = SRIconAquaDefaultName;
    }
    // Load new icons
    iconImageDict = [[SRIconManager sharedInstance] iconDictForName:iconName];
    if (iconImageDict) {
        [SRAquaIconImageDict release];
        SRAquaIconImageDict = [iconImageDict retain];
    }
    
    // Load metal icons
    iconName = [defaults stringForKey:SRThemeMetalIconNameKey];
    if (!iconName) {
        iconName = SRIconMetalDefaultName;
    }
    // Load new icons
    iconImageDict = [[SRIconManager sharedInstance] iconDictForName:iconName];
    if (iconImageDict) {
        [SRMetalIconImageDict release];
        SRMetalIconImageDict = [iconImageDict retain];
    }
    
#if 0
    // Update toolbar icon
    NSArray*        items;
    NSEnumerator*   enumerator;
    NSToolbarItem*  item;
    items = [[[self window] toolbar] items];
    enumerator = [items objectEnumerator];
    while (item = [enumerator nextObject]) {
        NSImage*    image;
        image = [_iconImageDict objectForKey:[item itemIdentifier]];
        if (image) {
            [item setImage:image];
        }
    }
#endif
}

//--------------------------------------------------------------//
#pragma mark -- Outlet accessors --
//--------------------------------------------------------------//

- (void)_loadDialogs
{
    // Load BrowserWindowDialogs.nib
    if (![NSBundle loadNibNamed:@"BrowserWindowDialogs" owner:self]) {
        // Error
        NSLog(@"Could not load BrowserWindowDialogs.nib");
    }
}

- (id)addBookmarkPanel
{
    if (!_addBookmarkPanel) {
        [self _loadDialogs];
    }
    return _addBookmarkPanel;
}

- (id)addBookmarkTextField
{
    if (!_addBookmarkTextField) {
        [self _loadDialogs];
    }
    return _addBookmarkTextField;
}

- (id)addBookmarkPopup
{
    if (!_addBookmarkPopup) {
        [self _loadDialogs];
    }
    return _addBookmarkPopup;
}

- (id)bookmarkAllPanel
{
    if (!_bookmarkAllPanel) {
        [self _loadDialogs];
    }
    return _bookmarkAllPanel;
}

- (id)bookmarkAllPopup
{
    if (!_bookmarkAllPopup) {
        [self _loadDialogs];
    }
    return _bookmarkAllPopup;
}

- (id)newFolderPanel
{
    if (!_newFolderPanel) {
        [self _loadDialogs];
    }
    return _newFolderPanel;
}

- (id)newFolderTextField
{
    if (!_newFolderTextField) {
        [self _loadDialogs];
    }
    return _newFolderTextField;
}

- (id)addToBarPanel
{
    if (!_addToBarPanel) {
        [self _loadDialogs];
    }
    return _addToBarPanel;
}

- (id)addToBarTextField
{
    if (!_addToBarTextField) {
        [self _loadDialogs];
    }
    return _addToBarTextField;
}

- (id)locationPanel
{
    if (!_locationPanel) {
        [self _loadDialogs];
    }
    return _locationPanel;
}

- (id)locationURLView
{
    if (!_locationURLView) {
        [self _loadDialogs];
    }
    return _locationURLView;
}

- (id)searchPanel
{
    if (!_searchPanel) {
        [self _loadDialogs];
    }
    return _searchPanel;
}

- (id)searchFieldView
{
    if (!_searchFieldView) {
        [self _loadDialogs];
    }
    return _searchFieldView;
}

//--------------------------------------------------------------//
#pragma mark -- Appearnace --
//--------------------------------------------------------------//

- (BOOL)isBookmarkBarVisible
{
    return ![_bookmarkBar isHidden];
}

- (void)setBookmarkBarVisible:(BOOL)isVisible 
        display:(BOOL)display
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Show bookmarks bar
    if (isVisible && [_bookmarkBar isHidden]) {
        // Show bookmarks bar
        [_bookmarkBar setHidden:NO];
        
        // Get frames
        NSRect  barFrame, windowFrame;
        barFrame = [_bookmarkBar frame];
        windowFrame = [[self window] frame];
        
        // Expand window
        int mask;
        mask = [_tabView autoresizingMask];
        [_tabView setAutoresizingMask:NSViewMaxYMargin];
        [[self window] setFrame:NSMakeRect(
                windowFrame.origin.x, 
                windowFrame.origin.y - barFrame.size.height - 1, 
                windowFrame.size.width, 
                windowFrame.size.height + barFrame.size.height + 1) display:display animate:YES]; 
        [_tabView setAutoresizingMask:mask];
    }
    
    // Hide bookmarks bar
    else if (!isVisible && ![_bookmarkBar isHidden]) {
        // Get frames
        NSRect  barFrame, windowFrame;
        barFrame = [_bookmarkBar frame];
        windowFrame = [[self window] frame];
        
        // Shrink window
        int mask;
        mask = [_tabView autoresizingMask];
        [_tabView setAutoresizingMask:NSViewMaxYMargin];
        [[self window] setFrame:NSMakeRect(
                windowFrame.origin.x, 
                windowFrame.origin.y + barFrame.size.height + 1, 
                windowFrame.size.width, 
                windowFrame.size.height - barFrame.size.height - 1) display:display animate:YES]; 
        [_tabView setAutoresizingMask:mask];
        
        // Hide bookmarks box
        [_bookmarkBar setHidden:YES];
    }
    
    // Set it default database
    if (!_isResizedByJavaScript) {
        [defaults setBool:isVisible forKey:SRBrowserWindowBookmarkBarVisible];
    }
}

- (BOOL)isStatusBarVisible
{
    return ![_statusBar isHidden];
}

- (void)setStatusBarVisible:(BOOL)isVisible 
        display:(BOOL)display
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Show status bar
    if (isVisible && [_statusBar isHidden]) {
        // Get frames
        NSRect  statusBarFrame, windowFrame;
        statusBarFrame = [_statusBar frame];
        windowFrame = [[self window] frame];
        
        // Expand window
        int mask;
        mask = [_tabView autoresizingMask];
        [_tabView setAutoresizingMask:NSViewMinYMargin];
        [[self window] setFrame:NSMakeRect(
                windowFrame.origin.x, 
                windowFrame.origin.y - statusBarFrame.size.height, 
                windowFrame.size.width, 
                windowFrame.size.height + statusBarFrame.size.height) display:display animate:YES]; 
        [_tabView setAutoresizingMask:mask];
        
        // Show status bar
        [_statusBar setHidden:NO];
    }
    
    // Hide status bar
    else if (!isVisible && ![_statusBar isHidden]) {
        // Get frames
        NSRect  statusBarFrame, windowFrame;
        statusBarFrame = [_statusBar frame];
        windowFrame = [[self window] frame];
        
        // Hide status bar
        [_statusBar setHidden:YES];
        
        // Shrink window
        int mask;
        mask = [_tabView autoresizingMask];
        [_tabView setAutoresizingMask:NSViewMinYMargin];
        [[self window] setFrame:NSMakeRect(
                windowFrame.origin.x, 
                windowFrame.origin.y + statusBarFrame.size.height, 
                windowFrame.size.width, 
                windowFrame.size.height - statusBarFrame.size.height) display:display animate:YES]; 
        [_tabView setAutoresizingMask:mask];
    }
}

- (BOOL)isTabVisible
{
    return [_tabView isTabItemViewShown];
}

- (void)setTabVisible:(BOOL)isVisible 
        display:(BOOL)display
{
    [_tabView setTabItemViewShown:isVisible];
}

- (BOOL)isResizedByJavaScript
{
    return _isResizedByJavaScript;
}

- (void)setResizedByJavaScript:(BOOL)flag
{
    _isResizedByJavaScript = flag;
}

- (NSRect)tabViewFrame
{
    // Get conent view frame
    NSRect  frame;
    frame = [[[self window] contentView] frame];
    frame.size.height += 1;
    
    if ([self isBookmarkBarVisible]) {
        frame.size.height -= [_bookmarkBar bounds].size.height;
    }
    if ([self isStatusBarVisible]) {
        frame.origin.y += [_statusBar bounds].size.height;
        frame.size.height -= [_statusBar bounds].size.height;
    }
    
    return frame;
}

- (SRTabStyleType)tabStyle
{
    if ([_tabView hasThumbnail]) {
        return SRTabStylePageDock;
    }
    return SRTabStyleTab;
}

- (void)setTabStyle:(SRTabStyleType)tabStyle
{
    switch (tabStyle) {
    case SRTabStylePageDock: {
        // Set page dock style
        SRPageDockStyleType pageDockStyle;
        pageDockStyle = [self pageDocSytle];
        
        switch (pageDockStyle) {
        case SRPageDockStyleHorizontal: {
            [_tabView setTabViewPoision:HMTabViewBottom];
            break;
        }
        case SRPageDockStyleVertical: {
            [_tabView setTabViewPoision:HMTabViewRight];
            break;
        }
        }
        
        // Configure tab view
        [_tabView setHasThumbnail:YES];
        [_tabView setTabItemViewShown:YES];
        [_tabView updateLayout];
        
        // Enable page dock button
        [_pageDockButton setEnabled:YES];
        [_statusBar addButton:_pageDockButton];
        
        break;
    }
    case SRTabStyleTab: {
        // Configure tab view
        [_tabView setTabViewPoision:HMTabViewTop];
        [_tabView setHasThumbnail:NO];
        [_tabView updateLayout];
        
        // Disable page dock button
        [_pageDockButton setEnabled:NO];
        [_statusBar removeButton:_pageDockButton];
        
        break;
    }
    }
}

- (SRPageDockStyleType)pageDocSytle
{
    int style;
    style = [[NSUserDefaults standardUserDefaults] integerForKey:SRPageDockStyle];
    return (SRPageDockStyleType)style;
}

- (void)setPageDockStyle:(SRPageDockStyleType)pageDockStyle
{
}

//--------------------------------------------------------------//
#pragma mark -- Full screen --
//--------------------------------------------------------------//

- (void)switchToFullScreenWithMenu:(BOOL)isMenuVisible
{
    // Fade out
    CGError error;
    CGDisplayFadeReservationToken   token = 0;
    error = CGAcquireDisplayFadeReservation(3.0, &token);
    if (error == kCGErrorSuccess) {
        CGDisplayFade(token, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0, true);
    }
    
    // Hide system UI
    OSStatus    status;
    //status = SetSystemUIMode(kUIModeAllHidden, isMenuVisible ? kUIOptionAutoShowMenuBar : 0);
    status = SetSystemUIMode(kUIModeAllHidden, 0);
    
    // Get screen frame
    NSScreen*   screen;
    NSRect      frame;
    screen = [[self window] screen];
    frame = [screen frame];
    
    // Create full screen controller
    if (!_fullScreenController) {
        _fullScreenController = [[SRFullScreenController alloc] init];
        [_fullScreenController setBrowserController:self];
    }
    
    // Create window for full screen
    if (!_fullScreenWindow) {
        _fullScreenWindow = [[HMWindow alloc] initWithContentRect:frame 
                styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
        [_fullScreenWindow setReleasedWhenClosed:NO];
        [_fullScreenWindow setAcceptsMouseMovedEvents:YES];
        [_fullScreenWindow addMouseMoveListener:_fullScreenController];
    }
    
    // Swap tab view
    [_tabView retain];
    [_tabView removeFromSuperview];
    [_tabView setFrame:frame];
    [[_fullScreenWindow contentView] addSubview:_tabView];
    [_tabView release];
    
    _fullScreenTabItemViewShown = [_tabView isTabItemViewShown];
    if (_fullScreenTabItemViewShown) {
        [_tabView setTabItemViewShown:NO];
        [_tabView updateLayout];
    }
    
    // Show full screen window
    [_fullScreenController goToFullScreenMode];
    [_fullScreenWindow makeKeyAndOrderFront:self];
    
    // Fade in
    if (error == kCGErrorSuccess) {
        CGDisplayFade(token, 0.5, 1.0, 0.0, 0.0, 0.0, 0.0, true);
    }
    
    // Release token
    if (token) {
        CGReleaseDisplayFadeReservation(token);
    }
    
    // Set flag
    _isFullScreen = YES;
}

- (void)backToNormalMode
{
    // Fade out
    CGError error;
    CGDisplayFadeReservationToken   token = 0;
    error = CGAcquireDisplayFadeReservation(3.0, &token);
    if (error == kCGErrorSuccess) {
        CGDisplayFade(token, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, true);
    }
    
    // Show system UI
    OSStatus    status;
    status = SetSystemUIMode(kUIModeNormal, 0);
    
    // Swap tab view
    NSRect  frame;
    frame = [self tabViewFrame];
    [_tabView retain];
    [_tabView removeFromSuperview];
    [_tabView setFrame:frame];
    [[[self window] contentView] addSubview:_tabView];
    [_tabView release];
    
    if ([_tabView isTabItemViewShown] != _fullScreenTabItemViewShown) {
        [_tabView setTabItemViewShown:_fullScreenTabItemViewShown];
        [_tabView updateLayout];
    }
    
    // Close full screen window
    [_fullScreenController backToNormalMode];
    [_fullScreenWindow orderOut:self];
    
    // Fade in
    if (error == kCGErrorSuccess) {
        CGDisplayFade(token, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, true);
    }
    
    // Release token
    if (token) {
        CGReleaseDisplayFadeReservation(token);
    }
    
    // Set flag
    _isFullScreen = NO;
}

- (BOOL)isFullScreenMode
{
    if (!_fullScreenWindow) {
        return NO;
    }
    
    return [_fullScreenWindow isVisible];
}

- (HMWindow*)fullScreenWindow
{
    return _fullScreenWindow;
}

@end

#pragma mark -

@implementation SRURLToolbarItem : NSToolbarItem

- (void)configureForDisplayMode:(int)displayMode andSizeMode:(int)sizeMode
{
    // Decide control size
    NSControlSize   controlSize;
    controlSize = sizeMode == NSToolbarSizeModeSmall ? NSSmallControlSize : NSRegularControlSize;
    
    // Get combo box
    HMImageComboBox*    URLComboBox;
    URLComboBox = (HMImageComboBox*)[self view];
    
    // Set control size
    [[URLComboBox cell] setControlSize:controlSize];
    [URLComboBox setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]]];
    [URLComboBox sizeToFit];
    
    // Set size
    [self setMinSize:NSMakeSize(48, [URLComboBox frame].size.height)];
    [self setMaxSize:NSMakeSize(10224, [URLComboBox frame].size.height)];
}

@end

#pragma mark -

SROpenActionType SROpenActionTypeFromModifierFlags(
        unsigned modifierFlags, 
        BOOL enableTabbedBrowsing, 
        BOOL selectNewTabs)
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get modifier key flag
    unsigned int    cmdFlag, optionFlag, shiftFlag;
    cmdFlag = modifierFlags & NSCommandKeyMask;
    optionFlag = modifierFlags & NSAlternateKeyMask;
    shiftFlag = modifierFlags & NSShiftKeyMask;
    
    // For option key
    if (!cmdFlag && optionFlag && !shiftFlag) {
        return SROpenOptionAction;
    }
    
    // If tabbed browsing is enable
    if (enableTabbedBrowsing) {
        // If select new tabs
        if (selectNewTabs) {
            // Open in new tabs and select it
            if (cmdFlag && !optionFlag && !shiftFlag) {
                return SROpenInNewTabAction;
            }
            // Open in new tabs
            else if (cmdFlag && !optionFlag && shiftFlag) {
                return SROpenInNewBackgroundTabAction;
            }
            // Open in new window
            else if (cmdFlag && optionFlag && !shiftFlag) {
                return SROpenInNewWindowAction;
            }
            // Open in new window in background
            else if (cmdFlag && optionFlag && shiftFlag) {
                return SROpenInNewBackgroundWindowAction;
            }
        }
        // If not select new tabs
        else {
            // Open in new tabs
            if (cmdFlag && !optionFlag && !shiftFlag) {
                return SROpenInNewBackgroundTabAction;
            }
            // Open in new tabs and select it
            else if (cmdFlag && !optionFlag && shiftFlag) {
                return SROpenInNewTabAction;
            }
            // Open in new window in background
            else if (cmdFlag && optionFlag && !shiftFlag) {
                return SROpenInNewBackgroundWindowAction;
            }
            // Open in new window
            else if (cmdFlag && optionFlag && shiftFlag) {
                return SROpenInNewWindowAction;
            }
        }
    }
    // If tabbed browsing is disable
    else {
        // Open in new window
        if (cmdFlag && !shiftFlag) {
            return SROpenInNewWindowAction;
        }
        // Open in new window in background
        else if (cmdFlag && shiftFlag) {
            return SROpenInNewBackgroundWindowAction;
        }
    }
    
    return SROpenAction;
}

NSWindow* SRGetFrontBrowserWindow()
{
    // Get window number list
    int     count;
    int*    list;
    NSCountWindowsForContext((int)NULL, &count);
    list = malloc(sizeof(int) * count);
    NSWindowListForContext((int)NULL, sizeof(int) * count, list);
    
    // Find browser window
    NSWindow*   window = nil;
    int         i;
    for (i = 0; i < count; i++) {
        // Get window
        window = [NSApp windowWithWindowNumber:list[i]];
        if (!window) {
            continue;
        }
        
        // Get window controller
        id  windowController;
        windowController = [window windowController];
        if ([windowController isKindOfClass:[SRBrowserController class]]) {
            break;
        }
    }
    
    free(list);
    
    return window;
}

NSString* SRErrorURLWithWebView(
        WebView* webView)
{
    // Get DOM document
    DOMDocument*    document;
    document = [[webView mainFrame] DOMDocument];
    if (!document) {
        return nil;
    }
    
    // Get link elements
    DOMNodeList*    linkNodes;
    linkNodes = [document getElementsByTagName:@"link"];
    
    // Find alternate link
    int i;
    for (i = 0; i < [linkNodes length]; i++) {
        DOMHTMLLinkElement* link;
        link = (DOMHTMLLinkElement*)[linkNodes item:i];
        
        if ([[link rel] isEqualToString:@"alternate"]) {
            NSString*   href;
            href = [link href];
            if (!href) {
                href = @"";
            }
            
            return href;
        }
    }
    
    return nil;
}
