/*
SRBookmarkMenuProvider.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 "SRBookmark.h"

#import "SRAppController.h"
#import "SRBookmarkMenuProvider.h"
#import "SRMenu.h"

#import "SRConstants.h"

#import "SRPrefDefaultKeys.h"

// Consntats
int  SRNumberOfDefaultBookmarkMenu = 6;

@implementation SRBookmarkMenuProvider

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

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

//--------------------------------------------------------------//
#pragma mark -- NSMenu delegate --
//--------------------------------------------------------------//

- (BOOL)menuHasKeyEquivalent:(NSMenu*)menu 
        forEvent:(NSEvent*)event 
        target:(id*)target 
        action:(SEL*)action
{
    return NO;
}

- (void)menuNeedsUpdate:(NSMenu*)menu
{
    if ([menu delegate] != self) {
        return;
    }
    
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get usage flags
    NSDictionary*   usageFlags;
    usageFlags = [[NSUserDefaults standardUserDefaults] objectForKey:SRBookmarkMenuUsageFlags];
    if (![usageFlags isKindOfClass:[NSDictionary class]]) {
        usageFlags = nil;
    }
    
    // Get bookmark for bookmark bar
    NSString*   browser;
    SRBookmark* bookmarkBarBookmark;
    browser = [defaults objectForKey:SRBookmarkBarType];
    if (!browser || ![browser isKindOfClass:[NSString class]]) {
        browser = SRBrowserShiira;
    }
    bookmarkBarBookmark = [[SRAppController sharedInstance] 
            bookmarkForBookmarkBarOfBrowser:browser];
    
    SRBookmark* bookmarkMenu;
    NSMenuItem* menuItem;
    
    // For bookmark menu
    if (menu == SRBookmarkMenu()) {
        // Remove old bookmarks
        int i;
        for (i = [menu numberOfItems] - 1; i > SRNumberOfDefaultBookmarkMenu - 1; i--) {
            [menu removeItemAtIndex:i];
        }
        
        //
        // Bookmark bar
        //
        
        if (bookmarkBarBookmark) {
            // Create bookmarks bar item
            menuItem = [[NSMenuItem alloc] 
                    initWithTitle:[bookmarkBarBookmark title] action:NULL keyEquivalent:@""];
            [menuItem autorelease];
            [menuItem setImage:[bookmarkBarBookmark icon]];
            
            // Create bookmarks bar menu
            SRMenu*     bookmarksBarMenu;
            bookmarksBarMenu = [[SRMenu alloc] initWithTitle:@"Bookmarks bar"];
            [bookmarksBarMenu autorelease];
            [bookmarksBarMenu setRepresentedObject:bookmarkBarBookmark];
            [bookmarksBarMenu setDelegate:self];
            [menuItem setSubmenu:bookmarksBarMenu];
            
            _bookmarksBarMenu = bookmarksBarMenu;
            
            // Add bookmarks bar
            [menu addItem:menuItem];
        }
        
        // Check bookmark availability
        BOOL    isShiiraAvail, isSafariAvail, isFirefoxAvail;
        isShiiraAvail = [[usageFlags objectForKey:SRBrowserShiira] boolValue];
        isSafariAvail = [[usageFlags objectForKey:SRBrowserSafari] boolValue];
        isFirefoxAvail = [[usageFlags objectForKey:SRBrowserFirefox] boolValue];
        
        //
        // For Shiira
        //
        if (isShiiraAvail) {
            // Get Shiira bookmark menu
            bookmarkMenu = [[SRAppController sharedInstance] 
                    bookmarkForBookmarkMenuOfBrowser:SRBrowserShiira];
            
            // Appned bookmarks
            NSMutableArray* bookmarks;
            bookmarks = [NSMutableArray arrayWithArray:[bookmarkMenu sortedChildren]];
            [bookmarks removeObject:bookmarkBarBookmark];
            if ([bookmarks count] > 0) {
                // Add separator
                [menu addItem:[NSMenuItem separatorItem]];
                
                // Add 'Shiira bookmarks'
                if (isSafariAvail || isFirefoxAvail) {
                    NSString*   title;
                    title = [NSString stringWithFormat:@"- %@ -", 
                            NSLocalizedStringFromTable(@"Shiira Bookmarks", nil, nil)];
                    menuItem = [menu addItemWithTitle:title action:NULL keyEquivalent:@""];
                    [menuItem setEnabled:NO];
                }
                
                // Append menu
                [self appendBookmarks:bookmarks intoMenu:menu withShortcut:YES];
            }
        }
        
        //
        // For Safari
        //
        
        if (isSafariAvail) {
            // Get Safari bookmark menu
            bookmarkMenu = [[SRAppController sharedInstance] 
                    bookmarkForBookmarkMenuOfBrowser:SRBrowserSafari];
            
            // Append bookmarks
            NSArray*    safariBookmarks;
            safariBookmarks = [bookmarkMenu sortedChildren];
            if ([safariBookmarks count] > 0) {
                // Add separator
                [menu addItem:[NSMenuItem separatorItem]];
                
                // Add 'Safari bookmarks'
                if (isShiiraAvail || isFirefoxAvail) {
                    NSString*   title;
                    title = [NSString stringWithFormat:@"- %@ -", 
                            NSLocalizedStringFromTable(@"Safari Bookmarks", nil, nil)];
                    menuItem = [menu addItemWithTitle:title action:NULL keyEquivalent:@""];
                    [menuItem setEnabled:NO];
                }
                
                // Append menu
                [self appendBookmarks:safariBookmarks intoMenu:menu withShortcut:YES];
            }
        }
        
        //
        // For Firefox
        //
        
        if (isFirefoxAvail) {
            // Get Firefox bookmark menu
            bookmarkMenu = [[SRAppController sharedInstance] 
                    bookmarkForBookmarkMenuOfBrowser:SRBrowserFirefox];
            
            // Append bookmarks
            NSArray*    firefoxBookmarks;
            firefoxBookmarks = [bookmarkMenu sortedChildren];
            if ([firefoxBookmarks count] > 0) {
                // Add separator
                [menu addItem:[NSMenuItem separatorItem]];
                
                // Add 'Firefox bookmarks'
                if (isShiiraAvail || isSafariAvail) {
                    NSString*   title;
                    title = [NSString stringWithFormat:@"- %@ -", 
                            NSLocalizedStringFromTable(@"Firefox Bookmarks", nil, nil)];
                    menuItem = [menu addItemWithTitle:title action:NULL keyEquivalent:@""];
                    [menuItem setEnabled:NO];
                }
                
                // Append menu
                [self appendBookmarks:firefoxBookmarks intoMenu:menu withShortcut:YES];
            }
        }
    }
    // Other sub menu
    else {
        if ([menu isKindOfClass:[SRMenu class]]) {
            // Get represented object
            id  object;
            object = [(SRMenu*)menu representedObject];
            if (object) {
                SRBookmark* bookmark;
                bookmark = (SRBookmark*)object;
                
                // Append boomarks
                NSArray*    children;
                children = [bookmark sortedChildren];
                if ([children count] > 0) {
                    [self appendBookmarks:children intoMenu:menu withShortcut:YES];
                }
            }
        }
    }
}

//--------------------------------------------------------------//
#pragma mark -- Menu management --
//--------------------------------------------------------------//

- (void)appendBookmarks:(NSArray*)bookmarks 
        intoMenu:(NSMenu*)menu withShortcut:(BOOL)bookmarkBarShortCut
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Enumerate bookmark
    NSEnumerator*   enumerator;
    SRBookmark*     bookmark;
    NSMenuItem*     menuItem;
    int             shortCut = 1;
    enumerator = [bookmarks objectEnumerator];
    while (bookmark = [enumerator nextObject]) {
        // Case of not folder type
        if (![[bookmark isFolder] boolValue]) {
#if 1
            // For bookmarks bar
            NSString*   shortCutKey = @"";
            if (menu == _bookmarksBarMenu && bookmarkBarShortCut) {
                if (shortCut < 10) {
                    shortCutKey = [NSString stringWithFormat:@"%d", shortCut++];
                }
            }
#else
            // Check parent
            BOOL        isBookmarkBar;
            NSString*   shortCutKey = @"";
            isBookmarkBar = [[[bookmark valueForKey:@"parent"] 
                    valueForKey:@"type"] isEqualToString:SRBookmarkTypeBookmarkBar];
            if (isBookmarkBar && bookmarkBarShortCut) {
                if (shortCut < 10) {
                    shortCutKey = [NSString stringWithFormat:@"%d", shortCut++];
                }
            }
#endif
            
            // Create menu item
            menuItem = [menu addItemWithTitle:[bookmark title] 
                    action:@selector(openBookmarkAction:) 
                    keyEquivalent:shortCutKey];
            [menuItem setRepresentedObject:bookmark];
            [menuItem setImage:[bookmark icon]];
        }
        
        // Case of bookmark folder
        else {
            // Create menu item and submenu
            SRMenu* submenu;
            menuItem = [menu addItemWithTitle:[bookmark title] 
                    action:NULL 
                    keyEquivalent:@""];
            submenu = [[SRMenu alloc] initWithTitle:@""];
            [submenu autorelease];
            [submenu setRepresentedObject:bookmark];
            [submenu setDelegate:[menu delegate]];
            
            [menuItem setSubmenu:submenu];
            [menuItem setImage:[bookmark icon]];
        }
    }
    
    // Append open all in tabs
    [menu addItem:[NSMenuItem separatorItem]];
    menuItem = [menu addItemWithTitle:NSLocalizedString(@"Open in Tabs", nil) 
            action:@selector(openBookmarkInTabsAction:) 
            keyEquivalent:@""];
    [menuItem setRepresentedObject:bookmarks];
}

@end

//--------------------------------------------------------------//
#pragma mark -- Utility --
//--------------------------------------------------------------//

void _SRBookmarkFolderMenu(
        SRBookmark* bookmark, 
        NSMenu* menu, 
        int level)
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Check type and mutability
    if (![[bookmark isFolder] boolValue] || ![bookmark isMutable]) {
        return;
    }
    
    // Create menu item
    NSMenuItem* item;
    item = [[NSMenuItem alloc] initWithTitle:[bookmark title] 
            action:nil 
            keyEquivalent:@""];
    [item autorelease];
    [item setIndentationLevel:level];
    [item setRepresentedObject:bookmark];
    [item setImage:[bookmark icon]];
    
    // Add menu item
    [menu addItem:item];
    
    // Check children
    NSEnumerator*   enumerator;
    SRBookmark*     child;
    enumerator = [[bookmark sortedChildren] objectEnumerator];
    while (child = [enumerator nextObject]) {
        _SRBookmarkFolderMenu(child, menu, level + 1);
    }
}

NSMenu* SRBookmarkFolderMenu(
        SRBookmark* bookmark)
{
    // Create menu
    NSMenu* menu;
    menu = [[NSMenu alloc] initWithTitle:@""];
    [menu autorelease];
    
    // For root
    if ([[bookmark type] isEqualToString:@"Root"]) {
        NSEnumerator*   enumerator;
        SRBookmark*     child;
        enumerator = [[bookmark sortedChildren] objectEnumerator];
        while (child = [enumerator nextObject]) {
            _SRBookmarkFolderMenu(child, menu, 0);
        }
    }
    else {
        // Create folder menu
        _SRBookmarkFolderMenu(bookmark, menu, 0);
    }
    
    return menu;
}

void _SRBookmarkItemMenu(
        SRBookmark* bookmark, 
        NSMenu* menu)
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Create menu item
    NSMenuItem* item;
    item = [[NSMenuItem alloc] initWithTitle:[bookmark title] 
            action:nil 
            keyEquivalent:@""];
    [item autorelease];
    [item setRepresentedObject:bookmark];
    [item setImage:[bookmark icon]];
    
    // Add menu item
    [menu addItem:item];
    
    // For folder
    if ([[bookmark isFolder] boolValue]) {
        // Create menu
        NSMenu* submenu;
        submenu = [[NSMenu alloc] initWithTitle:@""];
        [submenu autorelease];
        
        // Check children
        NSEnumerator*   enumerator;
        SRBookmark*     child;
        enumerator = [[bookmark sortedChildren] objectEnumerator];
        while (child = [enumerator nextObject]) {
            _SRBookmarkItemMenu(child, submenu);
        }
        
        // Set submenu
        [item setSubmenu:submenu];
    }
}

NSMenu* SRBookmarkItemMenu(
        SRBookmark* bookmark)
{
    // Create menu
    NSMenu* menu;
    menu = [[NSMenu alloc] initWithTitle:@""];
    [menu autorelease];
    
    // For root
    if ([[bookmark type] isEqualToString:@"Root"]) {
        NSEnumerator*   enumerator;
        SRBookmark*     child;
        enumerator = [[bookmark sortedChildren] objectEnumerator];
        while (child = [enumerator nextObject]) {
            _SRBookmarkItemMenu(child, menu);
        }
    }
    else {
        // Create menu
        _SRBookmarkItemMenu(bookmark, menu);
    }
    
    return menu;
}
