/*
SRPageController.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 "SRSearchEngine.h"

#import "SRAppController.h"
#import "SRAutoFillManager.h"
#import "SRBrowserController.h"
#import "SRBrowserDocument.h"
#import "SRDefaultKeys.h"
#import "SRDocumentController.h"
#import "SRDownloadManager.h"
#import "SRPageController.h"
#import "SRPageInfoController.h"
#import "SRSearchFieldController.h"
#import "SRSoundManager.h"

#import "SRWebViewContextMenu.h"

#import "SRPreference.h"
#import "SRPrefDefaultKeys.h"

#import "SRShelfController.h"
#import "SRShelfRepresentation.h"

#import "SRPlugInController.h"

#import "SRWebView.h"

// Notifications
NSString*   SRPageDidStartProvisionalLoad = @"SRPageDidStartProvisionalLoad";
NSString*   SRPageDidCommitLoad = @"SRPageDidCommitLoad";
NSString*   SRPageDidFinishLoad = @"SRPageDidFinishLoad";
NSString*   SRPageDidReceiveServerRedirect = @"SRPageDidReceiveServerRedirect";
NSString*   SRPageTitleReceived = @"SRPageTitleReceived";
NSString*   SRPageIconReceived = @"SRPageIconReceived";
NSString*   SRPageProgressStart = @"SRPageProgressStart";
NSString*   SRPageProgressEstimateChanged = @"SRPageProgressEstimateChanged";
NSString*   SRPageProgressFinish = @"SRPageProgressFinish";

static NSArray* _templateKeys = nil;

@interface SRPageController (Private)
- (void)_setScalingWithWebView:(WebView*)webView;
- (void)_setUserAgentWithWebView:(WebView*)webView;
@end

@implementation SRPageController

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

- (id)initWithBrowserController:(SRBrowserController*)browserController 
        label:(NSString*)label frameName:(NSString*)frameName groupName:(NSString*)groupName
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    // Initialize instance varibles
    _browserController = browserController;
    _documentViewNeedsUpdate = YES;
    _webViewNeedsUpdate = YES;
    
    // Create web view
    WebView*    webView;
//    webView = [[SRWebView alloc] initWithFrame:NSZeroRect 
    webView = [[WebView alloc] initWithFrame:NSZeroRect 
            frameName:frameName groupName:groupName];
    
    [webView autorelease];
    [webView setHostWindow:[_browserController window]];  // For Plug-in, JavaScript
    [webView setFrameLoadDelegate:self];
    [webView setResourceLoadDelegate:self];
    [webView setPolicyDelegate:self];
    [webView setUIDelegate:self];
    [webView setDownloadDelegate:[SRDownloadManager sharedInstance]];
    [webView setPreferences:[SRPreference webPreferences]];
    
    // Scaling
    [self _setScalingWithWebView:webView];
    
    // Set user agent
    [self _setUserAgentWithWebView:webView];
    
    // Dummy
    WebPreferences* pref;
    int             defaultFontSize;
    pref = [webView preferences];
    defaultFontSize = [pref defaultFontSize];
    [pref setDefaultFontSize:defaultFontSize + 1];
    [pref setDefaultFontSize:defaultFontSize];
    
    // Create tab view item
    _tabViewItem = [[HMTabViewItem alloc] initWithIdentifier:@""];
    [_tabViewItem setLabel:label];
    [_tabViewItem setView:webView];
    
    // Register notification
    NSNotificationCenter*   center;
    center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(webViewProgressStarted:) 
            name:WebViewProgressStartedNotification object:webView];
    [center addObserver:self selector:@selector(webViewProgressEstimateChanged:) 
            name:WebViewProgressEstimateChangedNotification object:webView];
    [center addObserver:self selector:@selector(webViewProgressFinished:) 
            name:WebViewProgressFinishedNotification object:webView];
    
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    [defaults addObserver:self forKeyPath:SRUniversalAccessScaling 
            options:NSKeyValueObservingOptionNew context:NULL];
    
    // Create template keys
    if (!_templateKeys) {
        _templateKeys = [[NSArray arrayWithObjects:
                @"$ERROR_TITLE$", @"$ERROR_MESSAGE$", @"$ERROR_URL$", nil] retain];
    }
    
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObserver:self forKeyPath:SRUniversalAccessScaling];
    
    // Stop loading
    WebView* webView;
    webView = [self webView];
    [webView stopLoading:self];
    
    // To close web view
	[webView setHostWindow:nil];
    [webView setFrameLoadDelegate:nil];
    [webView setResourceLoadDelegate:nil];
    [webView setPolicyDelegate:nil];
    [webView setUIDelegate:nil];
    [webView setDownloadDelegate:nil];
    
    // Close web view
    // I'm not sure I need to call it...
    [webView _close];
    
    [_documentViewImage release], _documentViewImage = nil;
    [_documentViewImageRep release], _documentViewImageRep = nil;
    [_webViewImage release], _webViewImage = nil;
    [_webViewImageRep release], _webViewImageRep = nil;
    [_tabViewItem release], _tabViewItem = nil;
    [_shelfIdWillOpen release], _shelfIdWillOpen = nil;
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- Controller --
//--------------------------------------------------------------//

- (SRBrowserController*)browserController
{
    return _browserController;
}

//--------------------------------------------------------------//
#pragma mark -- Tab view item --
//--------------------------------------------------------------//

- (HMTabViewItem*)tabViewItem
{
    return _tabViewItem;
}

//--------------------------------------------------------------//
#pragma mark -- Web view --
//--------------------------------------------------------------//

- (WebView*)webView
{
    return (WebView*)[_tabViewItem view];
}

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

- (WebView*)openRequest:(NSURLRequest*)request
{
    // Get web view
    WebView*    webView;
    webView = [self webView];
    
    // Evaluate JavaScript
    NSString*   URLString;
    URLString = [[request URL] absoluteString];
    if ([URLString hasPrefix:@"javascript:"]) {
        NSString*   script;
        NSString*   result;
        script = [URLString substringWithRange:NSMakeRange(11, [URLString length] - 11)]; // Remove 'javascript:'
        script = [script stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        result = [webView stringByEvaluatingJavaScriptFromString:script];
        
        return webView;
    }
    
    // Open request
    [[webView mainFrame] loadRequest:request];
    
#if 0
    // Set icon
    if ([self selectedWebView] == webView) {
        [[self URLComboBox] setImage:[[WebIconDatabase sharedIconDatabase] 
                defaultIconWithSize:NSMakeSize(16, 16)]];
    }
#endif
    
    return webView;
}

//--------------------------------------------------------------//
#pragma mark -- Page info --
//--------------------------------------------------------------//

- (float)loadingTime
{
    return _loadingTime;
}

//--------------------------------------------------------------//
#pragma mark -- Page image --
//--------------------------------------------------------------//

static float    _ratio = 1.0f;

- (void)_updateDocumentViewImage
{
    // Check needs update
    if (!_documentViewNeedsUpdate) {
        return;
    }
    _documentViewNeedsUpdate = NO;
    
    // Get web view and document view
    WebView*    webView;
    id          documentView;
    webView = [self webView];
    documentView = [[[webView mainFrame] frameView] documentView];
    if (!documentView) {
        return;
    }
    
    // Check size of web view
    NSRect  webFrame, oldWebFrame;
    webFrame = [webView frame];
    oldWebFrame = webFrame;
    if (NSIsEmptyRect(webFrame)) {
        webFrame.origin = NSZeroPoint;
        webFrame.size = [[_tabViewItem tabView] frame].size;
        [webView setFrame:webFrame];
    }
    
#if 0
    webFrame = [webView frame];
    if (webFrame.size.height < webFrame.size.width * _ratio) {
        webFrame.size.height = webFrame.size.width * _ratio;
        [webView setFrame:webFrame];
    }
#endif
    
    // Layout if needed
    if ([documentView respondsToSelector:@selector(_layoutIfNeeded)]) {
        [documentView _layoutIfNeeded];
    }
    
    // Decide document frame and image frame
    NSRect  documentFrame, imageFrame;
    documentFrame = [documentView frame];
    documentFrame.origin = NSZeroPoint;
    imageFrame = documentFrame;
    if (imageFrame.size.height > imageFrame.size.width * _ratio) {
        float   oldHeight;
        oldHeight = imageFrame.size.height;
        imageFrame.size.height = floor(imageFrame.size.width * _ratio);
    }
    
    // Check size
    if (NSEqualSizes(documentFrame.size, NSZeroSize)) {
        return;
    }
    
    // Create bitmap image representation
    if (!_documentViewImageRep || !NSEqualSizes([_documentViewImageRep size], documentFrame.size)) {
        [_documentViewImage release], _documentViewImage = nil;
        [_documentViewImageRep release], _documentViewImageRep = nil;
        
        _documentViewImageRep = [[documentView bitmapImageRepForCachingDisplayInRect:documentFrame] retain];
        _documentViewImage = [[NSImage alloc] initWithSize:documentFrame.size];
    }
    
    if (![[_documentViewImage representations] containsObject:_documentViewImageRep]) {
        [_documentViewImage addRepresentation:_documentViewImageRep];
    }
    
    // Cache bitmap
    [documentView cacheDisplayInRect:imageFrame toBitmapImageRep:_documentViewImageRep];
    [documentView setNeedsDisplay:YES];
    
    // Restore web frame
    if (!NSIsEmptyRect(oldWebFrame) && !NSEqualRects([webView frame], oldWebFrame)) {
        [webView setFrame:oldWebFrame];
    }
}

- (void)_updateWebViewImage
{
    // Check needs update
    if (!_webViewNeedsUpdate) {
        return;
    }
    _webViewNeedsUpdate = NO;
    
    // Get web view
    WebView*    webView;
    webView = [self webView];
    if (!webView) {
        return;
    }
    
    // Check size of web view
    NSRect  webFrame, oldWebFrame;
    webFrame = [webView frame];
    oldWebFrame = webFrame;
    if (NSIsEmptyRect(webFrame)) {
        webFrame.origin = NSZeroPoint;
        webFrame.size = [[_tabViewItem tabView] frame].size;
        [webView setFrame:webFrame];
    }
    
    // Get web bounds
    NSRect  webBounds;
    webBounds = [webView bounds];
    
    // Create image
    [_webViewImage release], _webViewImage = nil;
    _webViewImage = [[NSImage alloc] initWithSize:webBounds.size];
    
    // Get bitmap image repsentation
    NSBitmapImageRep*   imageRep;
    imageRep = [webView bitmapImageRepForCachingDisplayInRect:webBounds];
    if (![[_webViewImage representations] containsObject:imageRep]) {
        [_webViewImage addRepresentation:imageRep];
    }
    
    // Cache bitmap
    [webView cacheDisplayInRect:webBounds toBitmapImageRep:imageRep];
    [webView setNeedsDisplay:YES];
    
    // Create btimap image repsentation from TIFF
    [_webViewImageRep release], _webViewImageRep = nil;
    _webViewImageRep = [[NSBitmapImageRep imageRepWithData:[_webViewImage TIFFRepresentation]] retain];
}

- (NSImage*)documentViewImage
{
    // Update document view image
    [self _updateDocumentViewImage];
    
    return _documentViewImage;
}

- (NSBitmapImageRep*)documentViewImageBitmapRep
{
    // Update document view image
    [self _updateDocumentViewImage];
    
    return _documentViewImageRep;
}

- (NSImage*)webViewImage
{
//_webViewNeedsUpdate = YES;
    // Update web view image
    [self _updateWebViewImage];
    
    return _webViewImage;
}

- (NSBitmapImageRep*)webViewImageBitmapRep
{
//_webViewNeedsUpdate = YES;
    // Update web view image
    [self _updateWebViewImage];
    
    return _webViewImageRep;
}

- (void)updateDocumentViewImage
{
    // Update document view image
    NSImage*    image;
    image = [self documentViewImage];
    
    // Set it tab view item
    [_tabViewItem setThumbnailImage:image];
}

- (void)updateWebViewImage
{
}

- (void)clearPageImage
{
    // Set page image
    [_tabViewItem setThumbnailImage:_documentViewImage];
    
    // Remove image
    [_documentViewImage release], _documentViewImage = nil;
    [_documentViewImageRep release], _documentViewImageRep = nil;
    _documentViewNeedsUpdate = YES;
    [_webViewImage release], _webViewImage = nil;
    [_webViewImageRep release], _webViewImageRep = nil;
    _webViewNeedsUpdate = YES;
}

//--------------------------------------------------------------//
#pragma mark -- Scaling --
//--------------------------------------------------------------//

- (void)_setScalingWithWebView:(WebView*)webView
{
    // Check Web document view
    if (![[[[webView mainFrame] frameView] documentView] isKindOfClass:NSClassFromString(@"WebHTMLView")]) {
        return;
    }
    
    // Get scaling
    NSUserDefaults* defaults;
    NSNumber*       scaling;
    defaults = [NSUserDefaults standardUserDefaults];
    scaling = [defaults objectForKey:SRUniversalAccessScaling];
    if (scaling) {
#if 1
        float   size;
        size = [scaling floatValue] + 1.0f;
#else
        float   scalingValue;
        float   size = 1.0f;
        scalingValue = [scaling floatValue];
        if (scalingValue >= 0.0f && scalingValue <= 0.5f) {
            size = 0.5f + 0.5f * scalingValue * 2;
        }
        else if (scalingValue <= 1.0f) {
            size = 1.0f + (scalingValue - 0.5f) * 2;
        }
#endif
        
        // Set scaling
        WebFrameView*   frameView;
        frameView = [[webView mainFrame] frameView];
        [[frameView _drawMatrix] makeIdentity];
        
        if (size != 1.0f) {
            [frameView scaleUnitSquareToSize:NSMakeSize(size, size)];
        }
        else {
            [webView resizeSubviewsWithOldSize:NSZeroSize];
        }
        
        NSRect  frame;
        frame = [webView frame];
        frame.origin = NSZeroPoint;
        [frameView setFrame:frame];
        
        [webView setNeedsDisplay:YES];
    }
}

//--------------------------------------------------------------//
#pragma mark -- User agent --
//--------------------------------------------------------------//

- (void)_setUserAgentWithWebView:(WebView*)webView
{
#if 1
    [webView setCustomUserAgent:nil];
    
    // Get version
    NSBundle*   bundle;
    NSString*   version;
    NSString*   userAgentName = @"Shiira";
    bundle = [NSBundle mainBundle];
    version = [[bundle infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    if (version) {
        userAgentName = [NSString stringWithFormat:@"%@/%@", userAgentName, version];
    }
    [webView setApplicationNameForUserAgent:userAgentName];
    
    // Get composited user agent name
    NSString*   compUserAgentName;
    compUserAgentName = [webView userAgentForURL:[NSURL URLWithString:@"http://local"]];
    
    // If user agent name dose not contain 'Safari', add it
    if ([compUserAgentName rangeOfString:@"Safari"].location == NSNotFound) {
        compUserAgentName = [NSString stringWithFormat:@"%@ Safari/125", compUserAgentName];
    }
    [webView setCustomUserAgent:compUserAgentName];
#else
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Set user agent
    int         userAgent;
    NSString*   customUserAgentName;
    userAgent = [defaults integerForKey:SRUserAgent];
    customUserAgentName = [defaults stringForKey:SRUserAgentOtherName];
    
    // For Shiira user agent
    if (userAgent == SRUserAgentShiira) {
        [webView setCustomUserAgent:nil];
        
        // Get version
        NSBundle*   bundle;
        NSString*   version;
        NSString*   userAgentName = @"Shiira";
        bundle = [NSBundle mainBundle];
        version = [[bundle infoDictionary] objectForKey:@"CFBundleShortVersionString"];
        if (version) {
            userAgentName = [NSString stringWithFormat:@"%@/%@", userAgentName, version];
        }
        [webView setApplicationNameForUserAgent:userAgentName];
        
        // Get composited user agent name
        NSString*   compUserAgentName;
        compUserAgentName = [webView userAgentForURL:[NSURL URLWithString:@"http://local"]];
        
        // If user agent name dose not contain 'Safari', add it
        if ([compUserAgentName rangeOfString:@"Safari"].location == NSNotFound) {
            compUserAgentName = [NSString stringWithFormat:@"%@ Safari/125", compUserAgentName];
        }
        [webView setCustomUserAgent:compUserAgentName];
        
        // Show user agent name on preferences panel
        [defaults setValue:compUserAgentName forKey:SRUserAgentShiiraName];
    }
    // For default user agents
    if (userAgent > SRUserAgentShiira && userAgent < SRUserAgentOther) {
        // Get user agents plist
        NSArray*    userAgents;
        userAgents = [SRPreferencesController userAgents];
        if (userAgents && [userAgents count] > userAgent - 1) {
            NSDictionary*   userAgentInfo;
            NSString*       userAgentName;
            userAgentInfo = [userAgents objectAtIndex:userAgent - 1];
            userAgentName = [userAgentInfo objectForKey:@"userAgent"];
            if (userAgentName) {
                [webView setCustomUserAgent:userAgentName];
                
                // Show user agent name on preferences panel
                [defaults setValue:userAgentName forKey:SRUserAgentShiiraName];
            }
        }
    }
    // For other
    if (userAgent == SRUserAgentOther) {
        [webView setCustomUserAgent:customUserAgentName];
        
        // Set other user agent name on preferences panel
        [defaults setValue:customUserAgentName forKey:SRUserAgentShiiraName];
    }
#endif
}

- (void)setUserAgent:(int)userAgent
{
#if 0
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get custom user agent name
    NSString*   customUserAgentName;
    customUserAgentName = [defaults stringForKey:SRUserAgentOtherName];
    
    // Set it web view
    NSEnumerator*   enumerator;
    NSTabViewItem*  tabViewItem;
    enumerator = [[[_srTabView tabView] tabViewItems] objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        // Get web view
        WebView*    webView;
        webView = (WebView*)[tabViewItem view];
        
        // Set user agent
        [self _setUserAgentWithWebView:webView];
    }
#endif
}

//--------------------------------------------------------------//
#pragma mark -- Supported schemes --
//--------------------------------------------------------------//

- (BOOL)isSchemeSupported:(NSString *)scheme
{
    if (!scheme || [scheme length] <= 0) {
        return YES;
    }
    
    if ([scheme isEqualToString:@"http"] || 
       [scheme isEqualToString:@"https"] || 
       [scheme isEqualToString:@"file"] || 
       [scheme isEqualToString:@"shiira"] || 
       [scheme isEqualToString:@"rss"])
    {
        return YES;
    }
    
    // Get plug in shceme
    if ([[[SRPlugInController sharedInstance] plugInSchemes] containsObject:scheme]) {
        return YES;
    }
    
    return NO;
}

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

- (void)setSelectedShelfId:(NSString*)shelfId
{
    // Get web view and data source
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [self webView];
    dataSource = [[webView mainFrame] dataSource];
    
    // Get shelf representation
    id  representation;
    representation = [dataSource representation];
    if (!representation) {
        // Store shelf ID
        [_shelfIdWillOpen release], _shelfIdWillOpen = nil;
        _shelfIdWillOpen = [shelfId copy];
    }
    else {
        if ([representation isKindOfClass:[SRShelfRepresentation class]]) {
            // Select Shelf
            SRShelfController*  shelfController;
            shelfController = [representation shelfController];
            [shelfController setSelectedShelfId:shelfId];
        }
    }
}

//--------------------------------------------------------------//
#pragma mark -- WebFrameLoadDelegate --
//--------------------------------------------------------------//

- (void)webView:(WebView*)webView 
        didStartProvisionalLoadForFrame:(WebFrame*)frame
{
    // Resign first responder
    if (self == [_browserController selectedPageController]) {
        if ([webView mainFrame] == frame) {
            [[webView window] makeFirstResponder:nil];
        }
    }
    
    // For main frame
    if ([webView mainFrame] == frame) {
        // Get provisional data source
        WebDataSource*  provisionalDataSource;
        provisionalDataSource = [frame provisionalDataSource];
        
        // Get URL string
        NSString*   URLString;
        URLString = [[[provisionalDataSource request] URL] _web_userVisibleString];
        
        // Set tab label
        [_tabViewItem setLabel:URLString];
        [_tabViewItem setSubLabel:URLString];
        
        // Notify change
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRPageDidStartProvisionalLoad object:self];
    }
}

- (void)webView:(WebView*)webView 
        didCommitLoadForFrame:(WebFrame*)frame
{
    // Get request, response, and URL
    WebDataSource*  dataSource;
    NSURLRequest*   request;
    NSURLResponse*  response;
    dataSource = [frame dataSource];
    request = [dataSource request];
    response = [dataSource response];
    
    // Get window
    NSWindow*   window;
    window = [webView window];
    
    // When this page is selected
    if ([_browserController selectedPageController] == self) {
        // For main frame
        if (frame == [webView mainFrame]) {
            if (webView && [window firstResponder] != webView) {
                [window makeFirstResponder:webView];
            }
        }
        else {
            // Get web frame view
            WebFrameView*   webFrameView;
            webFrameView = [frame frameView];
            
            // Check frame element
            DOMHTMLElement* frameElement;
            frameElement = [[webFrameView webFrame] frameElement];
            if ([frameElement isKindOfClass:[DOMHTMLFrameElement class]]) {
                // Check focus
                if (webFrameView && [window firstResponder] != webFrameView) {
                    [window makeFirstResponder:webFrameView];
                }
            }
        }
    }
    
    // For main frame
    if ([webView mainFrame] == frame) {
        // Notify progress
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRPageDidCommitLoad object:self];
    }
}

- (void)webView:(WebView*)webView 
        didFinishLoadForFrame:(WebFrame*)frame
{
    // For main frame
    if ([webView mainFrame] == frame) {
        // Notify progress
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRPageDidFinishLoad object:self];
        
        // For shelf
        if (_shelfIdWillOpen) {
            WebDataSource*  dataSource;
            dataSource = [frame dataSource];
            if ([[[[dataSource initialRequest] URL] absoluteString] isEqualToString:@"shiira://shelf"]) {
                // Get shelf representation
                id  representation;
                representation = [dataSource representation];
                if ([representation isKindOfClass:[SRShelfRepresentation class]]) {
                    // Select Shelf
                    SRShelfController*  shelfController;
                    shelfController = [representation shelfController];
                    [shelfController setSelectedShelfId:_shelfIdWillOpen];
                }
            }
            
            [_shelfIdWillOpen release], _shelfIdWillOpen = nil;
        }
        
        // For auto fill
        [[SRAutoFillManager sharedInstance] fillFormsWithWebView:webView];
    }
}

- (void)webView:(WebView*)webView 
        willCloseFrame:(WebFrame*)frame
{
}

- (void)webView:(WebView*)webView 
        didChangeLocationWithinPageForFrame:(WebFrame*)frame
{
#if 0
    // Notify change
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRMainWindowDidChangeLocationWithinPage object:webView];
#endif
}

- (void)webView:(WebView*)webView 
        didReceiveTitle:(NSString*)title 
        forFrame:(WebFrame*)frame
{
    // For main frame
    if ([webView mainFrame] == frame) {
        // Set tab label
        [_tabViewItem setLabel:title];
        
        // Notify change
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRPageTitleReceived object:self];
    }
}

- (void)webView:(WebView*)webView 
        didReceiveIcon:(NSImage*)icon 
        forFrame:(WebFrame*)frame
{
    // For main frame
    if ([webView mainFrame] == frame) {
        // Notify change
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRPageIconReceived object:self];
    }
}

- (NSString*)_valueForTemplateKey:(NSString*)key 
        error:(NSError*)error frame:(WebFrame*)frame dataSource:(WebDataSource*)dataSource;
{
    // Get error domain and code
    NSString*   domain;
    int         code;
    domain = [error domain];
    code = [error code];
    
    // Get error message
    NSString*   msgText = nil;
    NSString*   infoText = nil;
    NSString*   statusText = nil;
    HMGetWebKitErrorMessage(error, frame, &msgText, &infoText, &statusText);
    
    // title
    if ([key isEqualToString:@"$ERROR_TITLE$"]) {
        return msgText;
    }
    // message
    if ([key isEqualToString:@"$ERROR_MESSAGE$"]) {
        return infoText;
    }
    // error URL
    if ([key isEqualToString:@"$ERROR_URL$"]) {
        NSString*   urlString;
        urlString = [[[dataSource request] URL] absoluteString];
        if (!urlString) {
            urlString = @"";
        }
        return urlString;
    }
    
    return nil;
}

- (NSString*)_createHTMLWithError:(NSError*)error 
        frame:(WebFrame*)frame dataSource:(WebDataSource*)dataSource
{
    // Check arguments
    if (!error) {
        return nil;
    }
    
    // Load template
    NSString*   resPath;
    NSString*   path;
    NSString*   errorTemplate;
    resPath = [[NSBundle mainBundle] resourcePath];
    path = [resPath stringByAppendingPathComponent:@"template/ErrorTemplate.html"];
    errorTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    if (!errorTemplate) {
        // Error
        NSLog(@"Can't load ErrorTemplate.html");
        return nil;
    }
    
    // Create buffer
    NSMutableString*    html;
    html = [NSMutableString stringWithString:errorTemplate];
    
    // Replace keys
    NSEnumerator*   enumerator;
    NSString*       templateKey;
    enumerator = [_templateKeys objectEnumerator];
    while (templateKey = [enumerator nextObject]) {
        // Find in buffer
        if ([html rangeOfString:templateKey].location == NSNotFound) {
            continue;
        }
        
        // Get value for template key
        NSString*   value;
        value = [self _valueForTemplateKey:templateKey error:error frame:frame dataSource:dataSource];
        if (!value) {
            value = @"";
        }
        
        // Replace it
        [html replaceOccurrencesOfString:templateKey 
                withString:value options:0 range:NSMakeRange(0, [html length])];
    }
    
    return html;
}

- (void)_certificateAllowingAlertDidEnd:(NSAlert*)alert 
        returnCode:(int)returnCode 
        contextInfo:(void*)contextInfo
{
    // For continue
    if (returnCode == NSAlertFirstButtonReturn) {
        // Get URL string
        NSString*   URLString;
        URLString = (NSString*)contextInfo;
        
        if (URLString) {
            // Allow any certifiate from this host
            [NSURLRequest setAllowsAnyHTTPSCertificate:YES 
                    forHost:[[NSURL _web_URLWithUserTypedString:URLString] host]];
            
            // Reload
            [_browserController openURLString:URLString];
        }
        
        [(id)contextInfo release];
    }
}

- (void)_webView:(WebView*)webView 
        didFailLoadWithError:(NSError*)error 
        forFrame:(WebFrame*)frame
        dataSource:(WebDataSource*)dataSource
{
    // Check error
    NSString*   domain;
    int         code;
    domain = [error domain];
    code = [error code];
    if (([domain isEqualToString:NSURLErrorDomain] && code == NSURLErrorCancelled) || 
        ([domain isEqualToString:WebKitErrorDomain] && code == WebKitErrorFrameLoadInterruptedByPolicyChange))
    {
        return;
    }
    
    // For sound
    if ([[NSUserDefaults standardUserDefaults] boolForKey:SRUniversalAccessPlaySoundEffect]) {
        // Play sound
        [[SRSoundManager sharedInstance] 
                playSoundForAction:SRUniversalAccessSoundPageLoadError];
    }
    
    // Create HTML for error
    NSString*   html;
    html = [self _createHTMLWithError:error frame:frame dataSource:dataSource];
    
    // Load HTML
    NSString*   path;
    path = HMApplicationSupportFolder(@"Shiira");
    path = [path stringByAppendingPathComponent:@"template/tmpError.html"];
    [[html dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES];
    [frame loadRequest:
            [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
}

- (void)webView:(WebView*)webView 
        didFailProvisionalLoadWithError:(NSError*)error 
        forFrame:(WebFrame*)frame
{
    // Get error domain and code
    NSString*   domain;
    int         code;
    domain = [error domain];
    code = [error code];
    
    // For certification error
    if ([domain isEqualToString:NSURLErrorDomain] && 
        (code == NSURLErrorServerCertificateHasBadDate || 
         code == NSURLErrorServerCertificateHasUnknownRoot || 
         code == NSURLErrorServerCertificateUntrusted))
    {
        // Get error message
        NSString*   msgText = nil;
        NSString*   infoText = nil;
        NSString*   statusText = nil;
        HMGetWebKitErrorMessage(error, frame, &msgText, &infoText, &statusText);
        
        // Show dialog for certifacte allowing
        if (msgText && infoText) {
            // Get host
            NSURLRequest*   request;
            NSURL*          URL;
            NSString*       host;
            request = [[frame provisionalDataSource] request];
            if (!request) {
                request = [[frame dataSource] request];
            }
            URL = [request URL];
            host = [URL host];
            if (!host || [host length] == 0) {
                request = [[frame provisionalDataSource] initialRequest];
                URL = [request URL];
                host = [URL host];
            }
            
            // Create alert
            NSAlert*    alert;
            alert = [[NSAlert alloc] init];
            [alert autorelease];
            [alert setMessageText:msgText];
            [alert setInformativeText:infoText];
            [alert setAlertStyle:NSWarningAlertStyle];
            [alert addButtonWithTitle:NSLocalizedString(@"Continue", nil)];
            [alert addButtonWithTitle:NSLocalizedString(@"Cancel", nil)];
            
            // Show alert
            [alert beginSheetModalForWindow:[webView window] 
                    modalDelegate:self 
                    didEndSelector:@selector(_certificateAllowingAlertDidEnd:returnCode:contextInfo:) 
                    contextInfo:[[URL _web_userVisibleString] retain]];
        }
    }
    else {
        // Show error
        [self _webView:webView didFailLoadWithError:error 
                forFrame:frame dataSource:[frame provisionalDataSource]];
    }
}

- (void)webView:(WebView*)webView 
        didFailLoadWithError:(NSError*)error 
        forFrame:(WebFrame*)frame
{
    // Show error
    [self _webView:webView didFailLoadWithError:error 
            forFrame:frame dataSource:[frame dataSource]];
}

- (void)webView:(WebView*)sender 
        didCancelClientRedirectForFrame:(WebFrame*)frame
{
}

- (void)webView:(WebView*)webView 
        willPerformClientRedirectToURL:(NSURL*)URL 
        delay:(NSTimeInterval)seconds 
        fireDate:(NSDate*)date 
        forFrame:(WebFrame*)frame
{
#if 0
    // Get original request
    NSString*   originlURL;
    originlURL = [[[[frame dataSource] request] URL] absoluteString];
    
    // Swap searching URL
    NSString*   templateURL;
    templateURL = [_searchingURLDict objectForKey:originlURL];
    if (templateURL) {
        [_searchingURLDict setObject:templateURL forKey:[URL absoluteString]];
    }
#endif
}

- (void)webView:(WebView*)webView 
        didReceiveServerRedirectForProvisionalLoadForFrame:(WebFrame*)frame
{
    // For main frame
    if ([webView mainFrame] == frame) {
        // Get provisional data source
        WebDataSource*  provisionalDataSource;
        provisionalDataSource = [frame provisionalDataSource];
        
        // Get URL string
        NSString*   URLString;
        URLString = [[[provisionalDataSource request] URL] _web_userVisibleString];
        
        // Set tab label
        [_tabViewItem setLabel:URLString];
        [_tabViewItem setSubLabel:URLString];
        
        // Notify change
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRPageDidReceiveServerRedirect object:self];
    }
}

//--------------------------------------------------------------//
#pragma mark -- WebPolicyDelegate --
//--------------------------------------------------------------//

- (BOOL)_webView:(WebView*)webView 
        decidePolicyForNavigationByBrowseModeAction:(NSDictionary*)info 
        request:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Check modifier key flag
    unsigned int    modifierFlags = 0;
    modifierFlags = [[info objectForKey:WebActionModifierFlagsKey] unsignedIntValue];
    if ((modifierFlags & (NSAlphaShiftKeyMask | 
                          NSShiftKeyMask | 
                          NSControlKeyMask | 
                          NSAlternateKeyMask | 
                          NSCommandKeyMask)) != 0)
    {
        // Ignore browse mode
        return NO;
    }
    
    // Get browse mode
    int browseMode;
    browseMode = [defaults integerForKey:SRBrowseMode];
    switch (browseMode) {
    case SRSingleWindowMode: {
        // Open in same web view
        [listener use];
        return YES;
    }
    case SRSmartBrowseMode: {
        // Get domain name
        NSString*   initialDomain;
        NSString*   currentDomain;
        NSString*   newDomain;
        initialDomain = [[[[[webView mainFrame] dataSource] initialRequest] URL] host];
        currentDomain = [[[[[webView mainFrame] dataSource] request] URL] host];
        newDomain = [[request URL] host];
        
        // When domain is not decided yet
        if (!currentDomain || [currentDomain length] == 0 || 
            !newDomain || [newDomain length] == 0)
        {
            [listener use];
            return YES;
        }
        
        // Open in same web view when host name is same
//        if ([currentDomain isEqualToString:newDomain]) {
        if ([initialDomain isEqualToString:newDomain]) {
            [listener use];
            return YES;
        }
        
        // Open in new tab
        [_browserController openInNewTabRequest:request 
                frameName:frameName groupName:nil select:[defaults boolForKey:SRTabSelectNewTabs]];
        [listener ignore];
        return YES;
    }
    }
    
    return NO;
}

- (BOOL)_webView:(WebView*)webView 
        decideTabPolicyAction:(NSDictionary*)info 
        request:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get modifier key flag
    unsigned int    modifierFlags = 0;
    modifierFlags = [[info objectForKey:WebActionModifierFlagsKey] unsignedIntValue];
    if (!modifierFlags) {
        return NO;
    }
    
    // Get open action
    SROpenActionType    openAction;
    openAction = SROpenActionTypeFromModifierFlags(
            modifierFlags, YES, [defaults boolForKey:SRTabSelectNewTabs]);
    
    // Check open action
    switch (openAction) {
    case SROpenAction: {
        // Do nothing
        break;
    }
    // For opening with tab or window
    case SROpenInNewTabAction:
    case SROpenInNewBackgroundTabAction:
    case SROpenInNewWindowAction:
    case SROpenInNewBackgroundWindowAction: {
        [_browserController openRequest:request frameName:frameName groupName:nil withOpenAction:openAction];
        [listener ignore];
        return YES;
    }
    case SROpenOptionAction: {
        [listener download];
        
        // Show download panel automatically
        [[SRDownloadManager sharedInstance] showDownloadPanelAutomatically];
        
        return YES;
    }
    }
    
    return NO;
}

- (void)webView:(WebView*)webView 
        decidePolicyForNavigationAction:(NSDictionary*)info 
        request:(NSURLRequest*)request 
        frame:(WebFrame*)frame 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get navigation type
    int navigationType;
    navigationType = [[info objectForKey:WebActionNavigationTypeKey] intValue];
    
    // For submit
    if (navigationType == WebNavigationTypeFormSubmitted) {
        // Register form contents
        [[SRAutoFillManager sharedInstance] registerFormsWithWebView:webView];
    }
    
    // Check full screen mode
    if ([_browserController isFullScreenMode]) {
        [listener use];
        return;
    }
    
    // Get action element
    NSDictionary*   element;
    NSURL*          linkURL;
    NSString*       linkTargetFrame;
    element = [info objectForKey:WebActionElementKey];
    linkURL = [info objectForKey:WebActionOriginalURLKey];;
    linkTargetFrame = [[element objectForKey:WebElementLinkTargetFrameKey] name];
    
    // Check scheme
    NSString*	scheme;
    NSString*   lowercase;
    scheme = [linkURL scheme];
    lowercase = [scheme lowercaseString];
    if (scheme && ![scheme isEqualToString:lowercase]) {
        // Change scheme
        NSMutableString*    URLString;
        NSRange             range;
        URLString = [NSMutableString stringWithString:[linkURL absoluteString]];
        range = [URLString rangeOfString:scheme];
        if (range.location != NSNotFound) {
            [URLString replaceCharactersInRange:range withString:lowercase];
            linkURL = [NSURL URLWithString:URLString];
            scheme = [linkURL scheme];
        }
    }
    
    // For about scheme
    if ([scheme isEqualToString:@"about"]) {
        // Just use
        [listener use];
        return;
    }
    
    // For other schemes
    if (![self isSchemeSupported:scheme]) {
        // only if it's mailto, or if the default is set to allow all schemes
        if ([scheme isEqualToString:@"mailto"] || 
            [defaults boolForKey:SRSecurityAllowAllURLSchemes])
        {
            // Launch external viewer
            [[NSWorkspace sharedWorkspace] openURL:linkURL];
            [listener ignore];
            return;
        }
    }
    
    // For link click
    if (navigationType == WebNavigationTypeLinkClicked) {
        // Check browse mode
        if ([self _webView:webView decidePolicyForNavigationByBrowseModeAction:info 
                    request:request frameName:linkTargetFrame decisionListener:listener])
        {
            return;
        }
        
        // Check tab policy
        if ([self _webView:webView decideTabPolicyAction:info 
                request:request frameName:linkTargetFrame decisionListener:listener])
        {
            return;
        }
    }
    // For submit
    if (navigationType == WebNavigationTypeFormSubmitted) {
        // Register form contents
        //[[SRAutofillController sharedInstance] registerFormsWithWebView:webView];
    }
    // For resubmit
    if (navigationType == WebNavigationTypeFormResubmitted) {
    }
    // For other
    if (navigationType == WebNavigationTypeOther) {
        // Check browse mode
        if ([self _webView:webView decidePolicyForNavigationByBrowseModeAction:info 
                request:request frameName:linkTargetFrame decisionListener:listener])
        {
            return;
        }
        
        if ([self _webView:webView decideTabPolicyAction:nil 
                request:request frameName:nil decisionListener:listener])
        {
            return;
        }
    }
    
    // If listener is nil, it should come from representation view
    if (!listener) {
        [self openRequest:request];
    }
    
    [listener use];
}

- (BOOL)_webView:(WebView*)webView 
        decidePolicyForNewWindowByBrowseModeAction:(NSDictionary*)info 
        request:(NSURLRequest*)request 
        frameName:(NSString*)frameName 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Check modifier key flag
    unsigned int    modifierFlags = 0;
    modifierFlags = [[info objectForKey:WebActionModifierFlagsKey] unsignedIntValue];
    if ((modifierFlags & (NSAlphaShiftKeyMask | 
                          NSShiftKeyMask | 
                          NSControlKeyMask | 
                          NSAlternateKeyMask | 
                          NSCommandKeyMask)) != 0)
    {
        // Ignore browse mode
        return NO;
    }
    
    // Get browse mode
    int browseMode;
    browseMode = [defaults integerForKey:SRBrowseMode];
    switch (browseMode) {
    case SRSingleWindowMode: {
        // Open in same web view
        [self openRequest:request];
        [listener ignore];
        return YES;
    }
    case SRSmartBrowseMode: {
        // Get domain name
        NSString*   currentDomain;
        NSString*   newDomain;
        currentDomain = [[[[[webView mainFrame] dataSource] request] URL] host];
        newDomain = [[request URL] host];
        
        // Open in same web view when host name is same
        if ([currentDomain isEqualToString:newDomain]) {
            [self openRequest:request];
            [listener ignore];
            return YES;
        }
        
        // Open in new tab
        [_browserController openInNewTabRequest:request 
                frameName:frameName groupName:nil select:[defaults boolForKey:SRTabSelectNewTabs]];
        [listener ignore];
        return YES;
    }
    }
    
    return NO;
}

- (void)webView:(WebView*)webView 
        decidePolicyForNewWindowAction:(NSDictionary*)info 
        request:(NSURLRequest*)request 
        newFrameName:(NSString*)frameName 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Check full screen mode
    if ([_browserController isFullScreenMode]) {
        [self openRequest:request];
        [listener ignore];
        return;
    }
    
    // Check browse mode
    if ([self _webView:webView decidePolicyForNewWindowByBrowseModeAction:info 
            request:request frameName:frameName decisionListener:listener])
    {
        return;
    }
    
    // For tabbed browsing
    if ([self _webView:webView 
            decideTabPolicyAction:info 
            request:request 
            frameName:frameName 
            decisionListener:listener])
    {
        return;
    }
    
    // Find named frame
    NSEnumerator*   enumerator;
    id              document;
    enumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator];
    while (document = [enumerator nextObject]) {
        if (![document isKindOfClass:[SRBrowserDocument class]]) {
            continue;
        }
        
        // Get brrowser controller
        SRBrowserController*    browserController;
        browserController = [document browserController];
        if (!browserController) {
            continue;
        }
        
#if 0
        // Check all web view
        SRTabView*      srTabView;
        NSEnumerator*   tabViewItemEnumerator;
        NSTabViewItem*  tabViewItem;
        srTabView = [windowController srTabView];
        tabViewItemEnumerator = [[[srTabView tabView] tabViewItems] objectEnumerator];
        while (tabViewItem = [tabViewItemEnumerator nextObject]) {
            
            // Find named frame
            WebView*    webView;
            WebFrame*   namedFrame;
            webView = [tabViewItem view];
            if (!webView) {
                continue;
            }
            
            namedFrame = [[webView mainFrame] srFindFrameNamed:frameName];
            
            // Open in named frame
            if (namedFrame) {
                [listener ignore];
                [namedFrame loadRequest:request];
                [[srTabView tabView] selectTabViewItem:tabViewItem];
                
                // Make window front
                [[windowController window] makeKeyAndOrderFront:self];
                
                return;
            }
        }
#endif
    }
    
    // Open target link in tab
    if ([defaults boolForKey:SRTabTargetLinkUseTab]) {
        [_browserController openRequest:request frameName:frameName groupName:nil 
                withOpenAction:SROpenActionTypeFromModifierFlags(
                        NSCommandKeyMask, YES, [defaults boolForKey:SRTabSelectNewTabs])];
        
        [listener ignore];
        return;
    }
    
    // Always ignore
    [listener ignore];
    
    // Open in new background
    [_browserController openInNewWindowRequest:request frameName:frameName groupName:nil];
}

- (void)webView:(WebView*)webView 
        decidePolicyForMIMEType:(NSString*)type 
        request:(NSURLRequest*)request 
        frame:(WebFrame*)frame 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    // Check HTTP header fields
    id  response;
    response = [[frame provisionalDataSource] response];
    if (response && [response respondsToSelector:@selector(allHeaderFields)]) {
        NSDictionary*   headerFields;
        headerFields = [response allHeaderFields];
        
        // For Content-Disposition
        NSString*   contentDisposition;
        contentDisposition = [headerFields objectForKey:@"Content-Disposition"];
        if (contentDisposition && [contentDisposition rangeOfString:@"attachment"].location != NSNotFound) {
            // Download
            [listener download];
            
            // Show download panel automatically
            [[SRDownloadManager sharedInstance] showDownloadPanelAutomatically];
            
            return;
        }
        
        // For Content-Type
        NSString*   contentType;
        contentType = [headerFields objectForKey:@"Content-Type"];
        if (contentType && [contentType rangeOfString:@"application/octet-stream"].location != NSNotFound) {
            // Download
            [listener download];
            
            // Show download panel automatically
            [[SRDownloadManager sharedInstance] showDownloadPanelAutomatically];
            
            return;
        }
    }
    
    // Check path extension
    NSString*   extension;
    extension = [[[request URL] path] pathExtension];
    if ([extension isEqualToString:@"html"] || [extension isEqualToString:@"htm"]) {
        // Use this resource
        [listener use];
        return;
    }
    
    // Check MIME type WebView can show
    if ([WebView canShowMIMEType:type]) {
        // Use this MIME type
        [listener use];
        return;
    }
    
    // Download
    [listener download];
    
    // Show download panel automatically
    [[SRDownloadManager sharedInstance] showDownloadPanelAutomatically];
}

//--------------------------------------------------------------//
#pragma mark -- WebUIDelegate --
//--------------------------------------------------------------//

- (WebView*)webView:(WebView*)webView
        createWebViewWithRequest:(NSURLRequest*)request
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get browse mode
    int browseMode;
    browseMode = [defaults integerForKey:SRBrowseMode];
    
    // For single window mode
    if (browseMode == SRSingleWindowMode) {
        // Open request by itself
        [self openRequest:request];
        return webView;
    }
    
    // Check target link opening way
    BOOL    doseTargetLinkUseTab;
    doseTargetLinkUseTab = [defaults boolForKey:SRTabTargetLinkUseTab];
    if (doseTargetLinkUseTab) {
        WebView*    webView;
        webView = [[_browserController openInNewTabRequest:request 
                frameName:nil groupName:nil select:[defaults boolForKey:SRTabSelectNewTabs]] webView];
        return webView;
    }
    
    // Create new document
    SRDocumentController*   documentController;
    SRBrowserDocument*      document;
    documentController = [NSDocumentController sharedDocumentController];
    document = [documentController makeUntitledDocumentOfType:SRHTMLDocumentType];
    [documentController addDocument:document];
    
    // Make window controllers
    [document makeWindowControllers];
    
    // Get browser controller
    SRBrowserController*    browserController;
    browserController = [document browserController];
    
    // Open request in new window, 
    // but not show it yet
    [browserController openRequest:request];
    
    return [[browserController selectedPageController] webView];
}

- (void)webViewClose:(WebView*)webView
{
    // Close page
    [_browserController closePageController:self];
}

- (void)webViewShow:(WebView*)webView
{
    // Get document from web view
    id  document;
    document = [[NSDocumentController sharedDocumentController] 
            documentForWindow:[webView window]];
    
    // Show window
    [document showWindows];
}

- (NSResponder*)webViewFirstResponder:(WebView*)webView
{
    return [[webView window] firstResponder];
}

- (void)webView:(WebView*)webView 
        makeFirstResponder:(NSResponder*)responder
{
    // Make first responder
    [[webView window] makeFirstResponder:responder];
}

- (void)webView:(WebView*)webView 
        mouseDidMoveOverElement:(NSDictionary*)info 
        modifierFlags:(unsigned int)flags
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    NSString*   status = nil;
    
    // Get URL string
    NSString*   URLString;
    URLString = [[info objectForKey:WebElementLinkURLKey] _web_userVisibleString];
    
    if (URLString) {
        // Get scheme
        NSURL*      URL;
        NSString*   scheme;
        URL = [NSURL _web_URLWithUserTypedString:URLString];
        scheme = [URL scheme];
        
        // For mailto:
        if ([scheme isEqualToString:@"mailto"]) {
            status = NSLocalizedString(UTF8STR("Send e-mail to “%@”"), nil);
            goto finalize;
        }
        
        // Modifier flag is specified
        if (flags) {
            // Check key mask
            unsigned int    cmdFlag, optionFlag, shiftFlag;
            cmdFlag = flags & NSCommandKeyMask;
            optionFlag = flags & NSAlternateKeyMask;
            shiftFlag = flags & NSShiftKeyMask;
            
            // Download linked file
            if (!cmdFlag && optionFlag && !shiftFlag) {
                status = NSLocalizedString(UTF8STR("Download “%@”"), nil);
                goto finalize;
            }
            
            // Check tab browsing
            BOOL    selectNewTabs;
            selectNewTabs = [defaults boolForKey:SRTabSelectNewTabs];
            
            // If select new tabs
            if (selectNewTabs) {
                // Open in new tabs and select it
                if (cmdFlag && !optionFlag && !shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new tab"), nil);
                    goto finalize;
                }
                // Open in new tabs
                else if (cmdFlag && !optionFlag && shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new background tab"), nil);
                    goto finalize;
                }
                // Open in new window
                else if (cmdFlag && optionFlag && !shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new window"), nil);
                    goto finalize;
                }
                // Open in new window in background
                else if (cmdFlag && optionFlag && shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new background window"), nil);
                    goto finalize;
                }
            }
            // If not select new tabs
            else {
                // Open in new tabs
                if (cmdFlag && !optionFlag && !shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new background tab"), nil);
                    goto finalize;
                }
                // Open in new tabs and select it
                else if (cmdFlag && !optionFlag && shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new tab"), nil);
                    goto finalize;
                }
                // Open in new window in background
                else if (cmdFlag && optionFlag && !shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new background window"), nil);
                    goto finalize;
                }
                // Open in new window
                else if (cmdFlag && optionFlag && shiftFlag) {
                    status = NSLocalizedString(UTF8STR("Open “%@” in a new window"), nil);
                    goto finalize;
                }
            }
            
            // Open in new window
            if (cmdFlag && !shiftFlag) {
                status = NSLocalizedString(UTF8STR("Open “%@” in a new window"), nil);
                goto finalize;
            }
            // Open in new window in background
            else if (cmdFlag && shiftFlag) {
                status = NSLocalizedString(UTF8STR("Open “%@” in a new background window"), nil);
                goto finalize;
            }
        }
        
        // Get browse mode
        int browseMode;
        browseMode = [defaults integerForKey:SRBrowseMode];
        switch (browseMode) {
        case SRSingleWindowMode: {
            // Go to URL
            status = NSLocalizedString(UTF8STR("Go to “%@”"), nil);
            goto finalize;
        }
        }
        
        // Get target
        WebFrame*   target;
        target = [info objectForKey:WebElementLinkTargetFrameKey];
        
        // Target is in this frame
        if (target) {
            // Go to URL
            status = NSLocalizedString(UTF8STR("Go to “%@”"), nil);
            goto finalize;
        }
        else {
            if ([defaults boolForKey:SRTabTargetLinkUseTab]) {
                // Target link use tab
                status = NSLocalizedString(UTF8STR("Open “%@” in a new tab"), nil);
            } else {
                // Open page in new window
                status = NSLocalizedString(UTF8STR("Open “%@” in a new window"), nil);
            }
            
            goto finalize;
        }
    }
    
finalize:
    if (status) {
        [[_browserController browserContent] setValue:[NSString stringWithFormat:status, URLString]
                forKey:@"status"];
    }
    else {
        [[_browserController browserContent] setValue:@"" forKey:@"status"];
    }
}

- (NSMenuItem*)_createSerachMenuItemByEngine:(SRSearchEngine*)engine 
        searchString:(NSString*)searchString
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get menu item for finding by search engine
    NSMenu*     menu;
    NSMenuItem* menuItem;
    menu = [SRWebViewContextMenu contextMenu];
    menuItem = HMCopyMenuItemWithTag(menu, SRFindBySearchEngineTag, nil);
    
    // Get engine name
    NSString*   engineName;
    engineName = [engine valueForKey:@"title"];
    
    // Craate search URL string
    NSString*   URLString;
    URLString = SRCreateSearchURLStringFromSearchEngine(searchString, engine);
    
    // Create menu title
    NSString*   menuTitle;
    menuTitle = [NSString stringWithFormat:NSLocalizedString(@"Search using %@", nil), engineName];
    
    // Create search item
    NSMutableDictionary*    searchItem;
    searchItem = [NSMutableDictionary dictionaryWithObjectsAndKeys:
            searchString, @"string", 
            engineName, @"title", 
            URLString, @"URLString", 
            nil];
    
    // Create 'Search by serach engine' menu item
    menuItem = [[NSMenuItem alloc] initWithTitle:menuTitle 
            action:[menuItem action] 
            keyEquivalent:[menuItem keyEquivalent]];
    [menuItem setRepresentedObject:searchItem];
    
    // Get icon
    NSString*   templateURL;
    templateURL = [engine valueForKey:@"templateURL"];
    
    NSImage*    icon;
    icon = [[WebIconDatabase sharedIconDatabase] iconForURL:templateURL withSize:NSMakeSize(16, 16)];
    if (icon) {
        [menuItem setImage:icon];
    }
    
    return menuItem;
}

- (NSArray*)webView:(WebView*)webView 
        contextMenuItemsForElement:(NSDictionary*)element 
        defaultMenuItems:(NSArray*)defaultMenuItems
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get web view context menu
    NSMenu*     menu;
    NSMenuItem* menuItem;
    NSMenuItem* altMenuItem;
    menu = [SRWebViewContextMenu contextMenu];
    
    // Get copy menu item
    id  copyTarget = nil;
    SEL copyAction = NULL;
    
    NSEnumerator*   enumerator;
    enumerator = [defaultMenuItems objectEnumerator];
    while (menuItem = [enumerator nextObject]) {
        if ([menuItem tag] == WebMenuItemTagCopy) {
            copyTarget = [menuItem target];
            copyAction = [menuItem action];
        }
    }
    
    // Get URL string
    NSString*   urlString;
    BOOL        isError;
    urlString = [[[[[webView mainFrame] dataSource] request] URL] absoluteString];
    isError = [urlString hasSuffix:@"Shiira/template/tmpError.html"];
    
    // Get element info
    NSURL*      linkURL;
    NSURL*      imageURL;
    WebFrame*   webFrame;
    BOOL        isSelected;
    linkURL = [element objectForKey:WebElementLinkURLKey];
    imageURL = [element objectForKey:WebElementImageURLKey];
    webFrame = [element objectForKey:WebElementFrameKey];
    isSelected = [[element objectForKey:WebElementIsSelectedKey] boolValue];
    
    // Check tab browsing
    BOOL    selectNewTabs;
    selectNewTabs = [defaults boolForKey:SRTabSelectNewTabs];
    
    // Check full screen mode
    BOOL    isFullScreen;
    isFullScreen = [SRBrowserController isFullScreen];
    
    // Create array
    NSMutableArray* items;
    items = [NSMutableArray array];
    
    // Get selected string
    NSString*   selectedString = nil;
    if (isSelected) {
        NSView* documentView;
        documentView = [[[element objectForKey:WebElementFrameKey] frameView] documentView];
        if ([documentView respondsToSelector:@selector(selectedString)]) {
            selectedString = [documentView performSelector:@selector(selectedString)];
        }
    }
    
    // Get selected links
    DOMRange*       range;
    DOMNode*        startContainer = nil;
    NSMutableArray* linkURLStrings;
    range = [webView selectedDOMRange];
    startContainer = [range startContainer];
    linkURLStrings = [NSMutableArray array];
    if (startContainer) {
        HMDOMRangeFilter*   filter;
        DOMNodeIterator*    iterator;
        DOMNode*            node;
        filter = [[HMDOMRangeFilter alloc] initWithDOMRange:range nodeName:@"A"];
        iterator = [[webFrame DOMDocument] createNodeIterator:startContainer :DOM_SHOW_ALL :filter :NO];
        while (node = [iterator nextNode]) {
            // Get URL string
            NSString*   URLString = nil;
            if ([node respondsToSelector:@selector(href)]) {
                URLString = [(DOMHTMLLinkElement*)node href];
            }
            if (URLString) {
                // Check scheme
                NSString*   scheme;
                scheme = [[NSURL URLWithString:URLString] scheme];
                if (![scheme isEqualToString:@"javascript"]) {
                    [linkURLStrings addObject:URLString];
                }
            }
        }
        [filter release];
    }
    
    // When link is contained
    if (linkURL) {
        if ([WebView _canHandleRequest:[NSURLRequest requestWithURL:linkURL]] && !isFullScreen) {
            // 'Open Link in New Tab' and 'Open Link in Background Tab'
            if (selectNewTabs) {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewTabTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewBackgroundTabTag, _browserController);
            }
            else {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewBackgroundTabTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewTabTag, _browserController);
            }
            [menuItem setRepresentedObject:linkURL];
            [items addObject:menuItem];
            
            [altMenuItem setRepresentedObject:linkURL];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            [items addObject:altMenuItem];
            
            // 'Open Link in New Window' and 'Open Link in Background Window'
            if (selectNewTabs) {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewWindowTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewBackgroundWindowTag, _browserController);
            }
            else {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewBackgroundWindowTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenLinkInNewWindowTag, _browserController);
            }
            [menuItem setRepresentedObject:linkURL];
            [items addObject:menuItem];
            
            [altMenuItem setRepresentedObject:linkURL];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            [items addObject:altMenuItem];
        }
    }
    
    // 'Open All Links in New Tabs' and 'Open All Links in Background Tabs'
    if ([linkURLStrings count] > 1 && !isFullScreen) {
        if (selectNewTabs) {
            menuItem = HMCopyMenuItemWithTag(menu, SROpenAllLinksInNewTabsTag, _browserController);
            altMenuItem = HMCopyMenuItemWithTag(menu, SROpenAllLinksInNewBackgroundTabsTag, _browserController);
        }
        else {
            menuItem = HMCopyMenuItemWithTag(menu, SROpenAllLinksInNewBackgroundTabsTag, _browserController);
            altMenuItem = HMCopyMenuItemWithTag(menu, SROpenAllLinksInNewTabsTag, _browserController);
        }
        
        [menuItem setTitle:[NSString stringWithFormat:[menuItem title], [linkURLStrings count]]];
        [menuItem setRepresentedObject:linkURLStrings];
        [items addObject:menuItem];
        
        [altMenuItem setTitle:[NSString stringWithFormat:[menuItem title], [linkURLStrings count]]];
        [altMenuItem setRepresentedObject:linkURLStrings];
        [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
        [altMenuItem setAlternate:YES];
        [items addObject:altMenuItem];
    }
    
    // When link is contained
    if (linkURL) {
        // 'Download Linked File' and 'Download Link File to Location'
        menuItem = HMCopyMenuItemWithTag(menu, SRDownloadLinkedFileTag, _browserController);
        [menuItem setRepresentedObject:linkURL];
        [items addObject:menuItem];
        //menuItem = HMCopyMenuItemWithTag(menu, SRDownloadLinkedFileToLocationTag, _browserController);
        //[menuItem setRepresentedObject:linkURL];
        //[items addObject:menuItem];
        
        // 'Add Link to Bookmarks'
        if (!isFullScreen) {
            menuItem = HMCopyMenuItemWithTag(menu, SRAddLinkToBookmarksTag, _browserController);
            [menuItem setRepresentedObject:element];
            [items addObject:menuItem];
        }
        
        // 'Copy Link'
        menuItem = HMCopyMenuItemWithTag(menu, SRCopyLinkTag, _browserController);
        [menuItem setRepresentedObject:element];
        [items addObject:menuItem];
    }
    
    // When image is contained
    if (imageURL) {
        // Add separator
        if ([items count] > 0) {
            [items addObject:[NSMenuItem separatorItem]];
        }
        
        if (!isFullScreen) {
            // 'Open Image in New Tab' and 'Open Image in Background Tab'
            if (selectNewTabs) {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewTabTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewBackgroundTabTag, _browserController);
            }
            else {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewBackgroundTabTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewTabTag, _browserController);
            }
            [menuItem setRepresentedObject:imageURL];
            [items addObject:menuItem];
            
            [altMenuItem setRepresentedObject:imageURL];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            [items addObject:altMenuItem];
            
            // 'Open Image in New Window' and 'Open Image in Background Window'
            if (selectNewTabs) {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewWindowTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewBackgroundWindowTag, _browserController);
            }
            else {
                menuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewBackgroundWindowTag, _browserController);
                altMenuItem = HMCopyMenuItemWithTag(menu, SROpenImageInNewWindowTag, _browserController);
            }
            [menuItem setRepresentedObject:imageURL];
            [items addObject:menuItem];
            
            [altMenuItem setRepresentedObject:imageURL];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            [items addObject:altMenuItem];
        }
        
        // 'Download Image' and 'Download Image to Location'
        menuItem = HMCopyMenuItemWithTag(menu, SRDownloadImageTag, _browserController);
        [menuItem setRepresentedObject:imageURL];
        [items addObject:menuItem];
        //menuItem = HMCopyMenuItemWithTag(menu, SRDownloadImageToLocationTag, nil);
        //[items addObject:menuItem];
        
        // 'Copy Image to Clipboard' and 'Copy Image Location to Clipboard'
        menuItem = HMCopyMenuItemWithTag(menu, SRCopyImageTag, _browserController);
        [menuItem setRepresentedObject:element];
        [items addObject:menuItem];
        menuItem = HMCopyMenuItemWithTag(menu, SRCopyImageURLTag, _browserController);
        [menuItem setRepresentedObject:element];
        [items addObject:menuItem];
        
        // 'Open Image in Full Screen'
        if (!isFullScreen) {
            menuItem = HMCopyMenuItemWithTag(menu, SROpenImageInFullScreenTag, _browserController);
            [menuItem setRepresentedObject:element];
            [items addObject:menuItem];
        }
    }
    
    // When text is selected
    if (isSelected) {
        // Add separator
        if ([items count] > 0) {
            [items addObject:[NSMenuItem separatorItem]];
        }
        
        // 'Copy'
        menuItem = HMCopyMenuItemWithTag(menu, SRWebTextCopyTag, _browserController);
        if (copyTarget && copyAction) {
            [menuItem setTarget:copyTarget];
            [menuItem setAction:copyAction];
            [menuItem setTag:WebMenuItemTagCopy];
        }
        [items addObject:menuItem];
        
        // 'Open Text As URL'
        if (selectedString) {
            menuItem = HMCopyMenuItemWithTag(menu, SROpenTextAsURLTag, _browserController);
            [menuItem setRepresentedObject:selectedString];
            [items addObject:menuItem];
        }
    }
    
    // When text is selcted
    if (selectedString) {
        // Get current search engine
        SRSearchEngine* currentEngine;
        currentEngine = [[_browserController searchFieldController] currentSearchEngine];
        
        if (currentEngine) {
            // Add separator
            if ([items count] > 0) {
                [items addObject:[NSMenuItem separatorItem]];
            }
            
            // Add 'Search by serach engine'
            NSMenuItem* searchMenuItem;
            searchMenuItem = [self _createSerachMenuItemByEngine:currentEngine 
                    searchString:selectedString];
            [items addObject:searchMenuItem];
            
            // Find other search engines
            NSMutableArray* otherEngines;
            NSArray*        engines;
            NSEnumerator*   enumerator;
            SRSearchEngine* engine;
            otherEngines = [NSMutableArray array];
            engines = [[SRAppController sharedInstance] searchEngines];
            enumerator = [engines objectEnumerator];
            while (engine = [enumerator nextObject]) {
                if ([[engine valueForKey:@"isUsing"] boolValue] && 
                    ![[engine valueForKey:@"title"] isEqualToString:[currentEngine valueForKey:@"title"]])
                {
                    [otherEngines addObject:engine];
                }
            }
            
            // Add search by other engines menu
            if ([otherEngines count] > 0) {
                // Add 'Search by other'
                menuItem = HMCopyMenuItemWithTag(menu, SRFindByOtherSearchEngineTag, _browserController);
                [items addObject:menuItem];
                
                // Create submenu
                NSMenu* otherEnginesSubmenu;
                otherEnginesSubmenu = [[NSMenu alloc] initWithTitle:@"Other engine"];
                [menuItem setSubmenu:otherEnginesSubmenu];
                
                enumerator = [otherEngines objectEnumerator];
                while (engine = [enumerator nextObject]) {
                    // Add 'Search by serach engine'
                    NSMenuItem* searchMenuItem;
                    searchMenuItem = [self _createSerachMenuItemByEngine:engine 
                            searchString:selectedString];
                    [otherEnginesSubmenu addItem:searchMenuItem];
                }
            }
        }
    }
                
    // When nothing is selected
    if (!isSelected && !linkURL && !imageURL) {
        // 'Go Back'
        if ([webView canGoBack]) {
            menuItem = HMCopyMenuItemWithTag(menu, SRWebViewGoBackTag, _browserController);
            [items addObject:menuItem];
        }
        // 'Go Forward'
        if ([webView canGoForward]) {
            menuItem = HMCopyMenuItemWithTag(menu, SRWebViewGoForwardTag, _browserController);
            [items addObject:menuItem];
        }
        // 'Reload Page'
        if (![webView isLoading]) {
            menuItem = HMCopyMenuItemWithTag(menu, SRWebViewReloadPageTag, _browserController);
            [items addObject:menuItem];
        }
        // 'Stop Loading'
        if ([webView isLoading]) {
            menuItem = HMCopyMenuItemWithTag(menu, SRWebViewStopLoadingTag, _browserController);
            [items addObject:menuItem];
        }
        
        // Frame and sub frame
        if ([[webView mainFrame] dataSource] || webFrame != [webView mainFrame]) {
            // Add separator
            if ([items count] > 0) {
                [items addObject:[NSMenuItem separatorItem]];
            }
            
            // When in sub frame
            if (webFrame != [webView mainFrame] && !isFullScreen) {
                // Get frame URL
                WebDataSource*  dataSource;
                NSURL*          frameURL;
                dataSource = [[element objectForKey:WebElementFrameKey] dataSource];
                frameURL = [dataSource unreachableURL];
                if (!frameURL) {
                    frameURL = [[dataSource request] URL];
                }
                
                // 'Open Frame in New Tab' and 'Open Frame in Background Tab'
                if (selectNewTabs) {
                    menuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewTabTag, _browserController);
                    altMenuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewBackgroundTabTag, _browserController);
                }
                else {
                    menuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewBackgroundTabTag, _browserController);
                    altMenuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewTabTag, _browserController);
                }
                [menuItem setRepresentedObject:frameURL];
                [items addObject:menuItem];
                
                [altMenuItem setRepresentedObject:frameURL];
                [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
                [altMenuItem setAlternate:YES];
                [items addObject:altMenuItem];
                
                // 'Open Frame in New Window' and 'Open Frame in Background Window'
                if (selectNewTabs) {
                    menuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewWindowTag, _browserController);
                    altMenuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewBackgroundWindowTag, _browserController);
                }
                else {
                    menuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewBackgroundWindowTag, _browserController);
                    altMenuItem = HMCopyMenuItemWithTag(menu, SROpenFrameInNewWindowTag, _browserController);
                }
                [menuItem setRepresentedObject:frameURL];
                [items addObject:menuItem];
                
                [altMenuItem setRepresentedObject:frameURL];
                [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
                [altMenuItem setAlternate:YES];
                [items addObject:altMenuItem];
            }
            
            // 'View Source'
            if ([[webView mainFrame] dataSource] && !isFullScreen) {
                if (!isError) {
                    menuItem = HMCopyMenuItemWithTag(menu, SRViewSourceTag, _browserController);
                    [items addObject:menuItem];
                }
            }
            
            // 'View Frame Source'
            if (webFrame != [webView mainFrame] && !isFullScreen) {
                menuItem = HMCopyMenuItemWithTag(menu, SRViewFrameSourceTag, _browserController);
                [items addObject:menuItem];
            }
        }
    }
    
    // Remove last separator
    if ([[items lastObject] isSeparatorItem]) {
        [items removeLastObject];
    }
    
    return items;
}

- (void)webView:(WebView*)sender 
        runJavaScriptAlertPanelWithMessage:(NSString*)message
{
    // Create alert panel
    NSAlert*    alert;
    alert = [[NSAlert alloc] init];
    
    // Configure alert panel
    [alert setMessageText:@"JavaScript"];
    [alert setInformativeText:message];
    [alert addButtonWithTitle:@"OK"];
    
    // For sound
    if ([[NSUserDefaults standardUserDefaults] boolForKey:SRUniversalAccessPlaySoundEffect]) {
        // Play sound
        [[SRSoundManager sharedInstance] 
                playSoundForAction:SRUniversalAccessSoundJavaScriptDialog];
    }
    
    // Display alert panel
    [alert runModal];
    [alert release];
}

- (BOOL)webView:(WebView*)sender 
        runJavaScriptConfirmPanelWithMessage:(NSString*)message
{
    // Create alert panel
    NSAlert*    alert;
    alert = [[NSAlert alloc] init];
    
    // Configure alert panel
    [alert setMessageText:@"JavaScript"];
    [alert setInformativeText:message];
    [alert addButtonWithTitle:@"OK"];
    [alert addButtonWithTitle:@"Cancel"];
    
    // Display alert panel
    int result;
    result = [alert runModal];
   [alert release];
    
    // Return result
    return result == NSAlertFirstButtonReturn;
}

#if 0
- (NSString*)webView:(WebView*)sender 
        runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt 
        defaultText:(NSString*)defaultText
{
    // Create panel for text input
    SRTextInputPanelManager*    inputMgr;
    inputMgr = [[SRTextInputPanelManager alloc] init];
    [inputMgr autorelease];
    
    // Configure text input panel
    [inputMgr setPrompt:prompt];
    [inputMgr setMessage:defaultText];
    
    // Display text input panel
    int result;
    result = [inputMgr runModal];
    
    // Return result
    if (result == SRTextInputOK) {
        return [inputMgr message];
    }
    else {
        return nil;
    }
}
#endif

- (void)webView:(WebView*)sender 
        runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)listener
{
    // Create open panel
    NSOpenPanel*    openPanel;
    openPanel = [NSOpenPanel openPanel];
    
    // Display open panel
    int result;
    result = [openPanel runModal];
    
    // Return result
    if (result == NSOKButton) {
        [listener chooseFilename:[openPanel filename]];
    }
    else {
        [listener cancel];
    }
}

- (void)webView:(WebView*)webView 
        setFrame:(NSRect)frame
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
#if 0
    // Get browse mode
    int browseMode;
    browseMode = [defaults integerForKey:SRBrowseMode];
    if (browseMode != SRDefaultBrowseMode) {
        // Ignore it
        return;
    }
#endif
    
    // Check opened in tab
    BOOL    doseTargetLinkUseTab;
    doseTargetLinkUseTab = [defaults boolForKey:SRTabTargetLinkUseTab];
    if (doseTargetLinkUseTab) {
        // Ignore it
        return;
    }
    if ([[_browserController tabView] numberOfTabViewItems] > 1) {
        // Ignore it
        return;
    }
    
    // Set flag
    [_browserController setResizedByJavaScript:YES];
    
    // Resize window
    [[_browserController window] setFrame:frame display:NO];
}

- (BOOL)webViewAreToolbarsVisible:(WebView*)webView
{
    return [[[webView window] toolbar] isVisible];
}

- (void)webView:(WebView*)webView 
        setToolbarsVisible:(BOOL)visible
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
#if 0
    // Get browse mode
    int browseMode;
    browseMode = [defaults integerForKey:SRBrowseMode];
    if (browseMode != SRDefaultBrowseMode) {
        // Ignore it
        return;
    }
#endif
    
    // Check opened in tab
    BOOL    doseTargetLinkUseTab;
    doseTargetLinkUseTab = [defaults boolForKey:SRTabTargetLinkUseTab];
    if (doseTargetLinkUseTab) {
        // Ignore it
        return;
    }
    if ([[_browserController tabView] numberOfTabViewItems] > 1) {
        // Ignore it
        return;
    }
    
    // Set flag, it might be requested by Java Script
    [_browserController setResizedByJavaScript:YES];
    
    // Set visiblity of toolbar, bookmarks bar, and tabs
    NSToolbar*  toolbar;
    toolbar = [[webView window] toolbar];
    [toolbar setAutosavesConfiguration:NO];
    [toolbar setVisible:visible];
    [_browserController setBookmarkBarVisible:visible display:NO];
    [_browserController setTabVisible:visible display:NO];
}

- (BOOL)webViewIsStatusBarVisible:(WebView*)webView
{
    return [_browserController isStatusBarVisible];
}

- (void)webView:(WebView*)webView 
        setStatusBarVisible:(BOOL)visible
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
#if 0
    // Get browse mode
    int browseMode;
    browseMode = [defaults integerForKey:SRBrowseMode];
    if (browseMode != SRDefaultBrowseMode) {
        // Ignore it
        return;
    }
#endif
    
    // Check opened in tab
    BOOL    doseTargetLinkUseTab;
    doseTargetLinkUseTab = [defaults boolForKey:SRTabTargetLinkUseTab];
    if (doseTargetLinkUseTab) {
        // Ignore it
        return;
    }
    if ([[_browserController tabView] numberOfTabViewItems] > 1) {
        // Ignore it
        return;
    }
    
    // Set flag, it might be requested by Java Script
    [_browserController setResizedByJavaScript:YES];
    
    [_browserController setStatusBarVisible:visible display:NO];
}

//--------------------------------------------------------------//
#pragma mark -- WebView notification --
//--------------------------------------------------------------//

- (void)webViewProgressStarted:(NSNotification*)notification
{
    // Clear loading time and set start time
    _loadingTime = -1;
    _startTime = CFAbsoluteTimeGetCurrent();
    _documentViewNeedsUpdate = YES;
    _webViewNeedsUpdate = YES;
    
    // Clear page image
    [self clearPageImage];
    
    // Set tab status
    [_tabViewItem setWorking:YES];
    [_tabViewItem setEstimatedProgress:0];
    
    // Notify progress
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRPageProgressStart object:self];
}

- (void)_documentViewUpdateTimerFired:(NSTimer*)timer
{
    // Update document view
    [self updateDocumentViewImage];
    
    // Clear timer
    _documentViewUpdateTimer = nil;
}

- (void)webViewProgressEstimateChanged:(NSNotification*)notification
{
    // Get progress
    float   progress;
    progress = [[self webView] estimatedProgress];
    
    // Set image needs update
    _documentViewNeedsUpdate = YES;
    _webViewNeedsUpdate = YES;
    
    // Set tab thumbnail image
    HMTabView*  tabView;
    tabView = [_tabViewItem tabView];
    if ([tabView hasThumbnail] && [tabView isTabItemViewShown]) {
        if (!_documentViewUpdateTimer) {
            // Start document view update timer
            _documentViewUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5f 
                    target:self selector:@selector(_documentViewUpdateTimerFired:) 
                    userInfo:nil repeats:NO];
        }
    }
    
    // Set tab status
    [_tabViewItem setWorking:YES];
    [_tabViewItem setEstimatedProgress:progress];
    
    // Notify progress
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRPageProgressEstimateChanged object:self];
}

- (void)webViewProgressFinished:(NSNotification*)notification
{
    // Set loading time
    _loadingTime = CFAbsoluteTimeGetCurrent() - _startTime;
    
    // Set image needs update
    _documentViewNeedsUpdate = YES;
    _webViewNeedsUpdate = YES;
    
    // Set tab thumbnail image
    HMTabView*  tabView;
    tabView = [_tabViewItem tabView];
    if ([tabView hasThumbnail] && [tabView isTabItemViewShown]) {
        // Cancel timer
        if (_documentViewUpdateTimer) {
            [_documentViewUpdateTimer invalidate];
            _documentViewUpdateTimer = nil;
        }
        
        // Start document view update tiemr
        _documentViewUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5f 
                target:self selector:@selector(_documentViewUpdateTimerFired:) 
                userInfo:nil repeats:NO];
    }
    
    // Set tab status
    [_tabViewItem setWorking:NO];
    [_tabViewItem setEstimatedProgress:0.0];
    
    // Update web view image
    [self performSelector:@selector(webViewImage) withObject:nil afterDelay:0.0];
    
    // For sound
    if ([[NSUserDefaults standardUserDefaults] boolForKey:SRUniversalAccessPlaySoundEffect]) {
        // Get stauts code
        int statusCode = 0;
        id  response;
        response = [[[[self webView] mainFrame] dataSource] response];
        if ([response respondsToSelector:@selector(statusCode)]) {
            statusCode = [response statusCode];
        }
        
        // Play sound
        if (statusCode == 200) {
            [[SRSoundManager sharedInstance] 
                    playSoundForAction:SRUniversalAccessSoundPageLoadDone];
        }
    }
    
    // Notify progress
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRPageProgressFinish object:self];
}

//--------------------------------------------------------------//
#pragma mark -- SRPageInfoController notification --
//--------------------------------------------------------------//

- (void)linkSelected:(NSNotification*)notification
{
    // Get anchor node
    DOMHTMLAnchorElement*   anchor;
    anchor = [[notification userInfo] objectForKey:@"domNode"];
    
    // Gey web view
    WebView*    webView;
    webView = [self webView];
    
    // Compare DOM documents
    DOMDocument*    document;
    document = [anchor ownerDocument];
    if (![webView containsDOMDocument:document]) {
        return;
    }
    
    // Create DOM range
    DOMRange*   range;
    range = [document createRange];
    [range setStartBefore:anchor];
    [range setEndAfter:anchor];
    
    // Select DOM range
    [webView setSelectedDOMRange:range affinity:NSSelectionAffinityDownstream];
    
    // Jump to selection
    WebFrame*   frame;
    id          documentView;
    frame = [document webFrame];
    documentView = [[frame frameView] documentView];
    if ([documentView respondsToSelector:@selector(jumpToSelection:)]) {
        [documentView jumpToSelection:self];
    }
}

//--------------------------------------------------------------//
#pragma mark -- Key value observation --
//--------------------------------------------------------------//

- (void)observeValueForKeyPath:(NSString*)keyPath 
        ofObject:(id)object 
        change:(NSDictionary*)change 
        context:(void *)context
{
    // For user defaults
    if (object == [NSUserDefaults standardUserDefaults]) {
        // Universal access pref
        if ([keyPath isEqualToString:SRUniversalAccessScaling]) {
            // Set scaling
            [self _setScalingWithWebView:[self webView]];
            
            return;
        }
    }
}

@end
