/*
SRSearchFieldController.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 "SRBrowserController.h"
#import "SRSearchFieldController.h"
#import "SRDefaultKeys.h"

#import "SRMenu.h"
#import "SRConstants.h"

@interface SRSearchFieldController (private)
// Appearance
- (void)_updateSearchMenu;
- (void)_updatePlaceholderString;
@end

@implementation SRSearchFieldController

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

- (id)init
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    // Initialize instance variables
    _currentEngine = nil;
    
    // Set current engine
    SRSearchEngine* engine = nil;
    NSString*       title;
    title = [[NSUserDefaults standardUserDefaults] stringForKey:SRSearchEngineDefaultTitle];
    if (title) {
        engine = [self searchEngineWithTitle:title];
    }
    if (!engine) {
        NSArray*    engines;
        engines = [self rootSearchEngines];
        if (engines && [engines count] > 0) {
            engine = [engines objectAtIndex:0];
        }
    }
    if (engine) {
        [self setCurrentSearchEngine:engine];
    }
    
    return self;
}

//--------------------------------------------------------------//
#pragma mark -- Search engine --
//--------------------------------------------------------------//

- (SRSearchEngine*)currentSearchEngine
{
    return _currentEngine;
}

- (void)setCurrentSearchEngine:(SRSearchEngine*)searchEngine
{
    _currentEngine = searchEngine;
    
    // Update appearance
    [self _updatePlaceholderString];
}

- (SRSearchEngine*)searchEngineWithTitle:(NSString*)title
{
    // Get context manager
    NSManagedObjectContext* context;
    context = [[NSApp delegate] managedObjectContext];
    
    // Create fetch request
    NSFetchRequest*         request;
    NSEntityDescription*    entity;
    NSPredicate*            predicate;
    request = [[NSFetchRequest alloc] init];
    [request autorelease];
    
    entity = [NSEntityDescription entityForName:@"SearchEngine" inManagedObjectContext:context];
    [request setEntity:entity];
    
    predicate = [NSPredicate predicateWithFormat:@"title == %@", title];
    [request setPredicate:predicate];
    
    // Fetch search engine
    NSArray*    engines;
    engines = [context executeFetchRequest:request error:NULL];
    if (!engines || [engines count] == 0) {
        return nil;
    }
    
    return [engines objectAtIndex:0];
}

- (NSArray*)rootSearchEngines
{
    // Get context manager
    NSManagedObjectContext* context;
    context = [[NSApp delegate] managedObjectContext];
    
    // Create fetch request
    NSFetchRequest*         request;
    NSEntityDescription*    entity;
    NSPredicate*            predicate;
    NSSortDescriptor*       sortDescriptor;
    request = [[NSFetchRequest alloc] init];
    [request autorelease];
    
    entity = [NSEntityDescription entityForName:@"SearchEngine" inManagedObjectContext:context];
    [request setEntity:entity];
    
    predicate = [NSPredicate predicateWithFormat:@"parent == nil"];
    [request setPredicate:predicate];
    
    sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES];
    [sortDescriptor autorelease];
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    
    // Fetch search engine
    return [context executeFetchRequest:request error:NULL];
}

//--------------------------------------------------------------//
#pragma mark -- Accessors --
//--------------------------------------------------------------//

- (SRBrowserController*)browserController
{
    return _browserController;
}

- (void)setBrowserController:(SRBrowserController*)browserController
{
    _browserController = browserController;
}

- (SRSearchField*)searchField
{
    return _searchField;
}

- (void)setSearchField:(SRSearchField*)searchField
{
    _searchField = searchField;
    
    // Update appearance
    [self _updateSearchMenu];
    [self _updatePlaceholderString];
}

//--------------------------------------------------------------//
#pragma mark -- Appearance --
//--------------------------------------------------------------//

- (void)_addSearchEngines:(NSArray*)engines intoMenu:(NSMenu*)menu
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    NSMenuItem* item;
    
    // Check favicon using
//    BOOL    isFaviconUsed, isFaviconUsedSearchEngine;
//    isFaviconUsed = [defaults boolForKey:SRIconUseFavicon];
//    isFaviconUsedSearchEngine = [defaults boolForKey:SRIconUseFaviconSearchEngine];
    
    // Add engines
    NSEnumerator*   enumerator;
    SRSearchEngine* engine;
    enumerator = [engines objectEnumerator];
    while (engine = [enumerator nextObject]) {
        // Get type
        NSString*   type;
        type = [engine valueForKey:@"type"];
        
        // For seaparator
        if ([type isEqualToString:SRSearchEngineTypeSeparator]) {
            // Add separator
            int number;
            number = [menu numberOfItems];
            if (number == 0 || ![[menu itemAtIndex:number - 1] isSeparatorItem]) {
                [menu addItem:[NSMenuItem separatorItem]];
            }
            continue;
        }
        
        // Check using flag and title
        BOOL        isUsing;
        NSString*   title;
        isUsing = [[engine valueForKey:@"isUsing"] boolValue];
        title = [engine valueForKey:@"title"];
        if (!isUsing || !title || [title length] == 0) {
            continue;
        }
        
        // For folder
        if ([type isEqualToString:SRSearchEngineTypeFolder]) {
            // Get icon
            //NSImage*    icon = nil;
            //if (isFaviconUsed && isFaviconUsedSearchEngine) {
            //    icon = [[NSImage imageNamed:@"otherFolder"] copy];
            //    [icon setScalesWhenResized:YES];
            //    [icon setSize:NSMakeSize(14, 14)];
            //}
            
            // Add folder item
            item = [menu addItemWithTitle:title action:NULL keyEquivalent:@""];
            //if (isFaviconUsed && isFaviconUsedSearchEngine) {
            //    [item setImage:icon];
            //}
            
            // Get children
            NSArray*    children;
            children = [engine valueForKey:@"children"];
            if (children && [children count] > 0) {
                // Create submenu
                NSMenu* submenu;
                submenu = [[NSMenu alloc] initWithTitle:@""];
                [self _addSearchEngines:children intoMenu:submenu];
                
                // Add submenu
                [item setSubmenu:submenu];
                [submenu release];
            }
            
            continue;
        }
        
        // For normal engine
        if (isUsing && title) {
            // Get icon
            //NSImage*    icon = nil;
            //if (isFaviconUsed && isFaviconUsedSearchEngine) {
            //    NSString*   URLString;
            //    URLString = [engine objectForKey:@"templateURL"];
            //    icon = [[WebIconDatabase sharedIconDatabase] iconForURL:URLString withSize:NSMakeSize(16, 16)];
            //    icon = [[icon copy] autorelease];
            //    [icon setScalesWhenResized:YES];
            //    [icon setSize:NSMakeSize(14, 14)];
            //}
            
            // Add direct search item
            item = [menu addItemWithTitle:title 
                    action:@selector(selectEngineAndSearchAction:) 
                    keyEquivalent:@""];
            [item setTarget:self];
            [item setRepresentedObject:engine];
            [item setTag:SRSearchEngineTag];
            //if (isFaviconUsed && isFaviconUsedSearchEngine) {
            //    [item setImage:icon];
            //}
            
            continue;
        }
    }
}

- (void)_updateSearchMenu
{
    // Create search menu
    NSMenu* menu;
    menu = [[NSMenu alloc] initWithTitle:@"Search"];
    [menu autorelease];
    [menu setDelegate:self];
    
    // Add engines
    [self _addSearchEngines:[self rootSearchEngines] intoMenu:menu];
    
    // Add separator
    int number;
    number = [menu numberOfItems];
    if (number == 0 || ![[menu itemAtIndex:number - 1] isSeparatorItem]) {
        [menu addItem:[NSMenuItem separatorItem]];
    }
    
    // Set menu template
    [[_searchField cell] setSearchMenuTemplate:menu];
}

- (void)_updatePlaceholderString
{
    if (!_searchField) {
        return;
    }
    
    // If current engine is nil, disable search engine and clear placehodler
    if (!_currentEngine) {
        [[_searchField cell] setPlaceholderString:@""];
        [_searchField setNeedsDisplay:YES];
        [_searchField setEnabled:NO];
        
        return;
    }
    
    // Enable search engine and set placeholder
    if (![_searchField isEnabled]) {
        [_searchField setEnabled:YES];
    }
    [[_searchField cell] setPlaceholderString:[_currentEngine valueForKey:@"title"]];
    [_searchField setNeedsDisplay:YES];
}

//--------------------------------------------------------------//
#pragma mark -- Action --
//--------------------------------------------------------------//

- (void)searchAction:(id)sender
{
    // Get search string
    NSString*   searchString;
    searchString = [_searchField stringValue];
    if (!searchString || [searchString length] == 0) {
        return;
    }
    
    // Craate search URL string
    NSString*   URLString;
    URLString = SRCreateSearchURLStringFromSearchEngine(searchString, _currentEngine);
    
    // Add to recent item
//    [[SRSearchEnginesManager sharedInstance] addRecentWord:searchString 
//            engineName:[engine objectForKey:@"title"] 
//            URLString:URLString];
    
    // Set search string to find window
//    [[[NSApp delegate] findWindowController] setStringValue:searchString];
    
    // Search string with current modifierFlags
    SROpenActionType    openAction;
    WebView*            webView;
    openAction = SROpenActionTypeFromModifierFlags([[NSApp currentEvent] modifierFlags], YES, YES);
    if(openAction == SROpenOptionAction) {
        openAction = SROpenAction;
    }
    webView = [_browserController openURLString:URLString withOpenAction:openAction];
    
    // Set template URL string
//    [_mainWindowController setSearchTemplateURL:[engine objectForKey:@"templateURL"] requestURLString:URLString];
}

- (void)selectEngineAndSearchAction:(id)sender
{
    // Select engine
    SRSearchEngine* engine;
    engine = [sender representedObject];
    if (engine) {
        [self setCurrentSearchEngine:engine];
    }
    
    // Search with current engine
    [self searchAction:nil];
}

@end

#pragma mark -

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

NSString* SRCreateSearchURLStringFromSearchEngine(
        NSString* searchString, 
        SRSearchEngine* engine)
{
    // Get encoding and template URL
    NSStringEncoding    encoding;
    NSString*           templateURL;
    encoding = [[engine valueForKey:@"encoding"] unsignedIntValue];
    templateURL = [engine valueForKey:@"templateURL"];
    
    // Create escaped search string
    NSString*   escapedSearchString;
    escapedSearchString = (NSString*)CFURLCreateStringByAddingPercentEscapes(
            NULL, 
            (CFStringRef)searchString, 
            NULL, 
            CFSTR("+"), 
            CFStringConvertNSStringEncodingToEncoding(encoding));
    

    // Create URL string
    // Doing stringWithFormat: with the percent escapes in place can have weird effects, so just
    // do a manual replace instead
    NSRange     keywordRange;
    keywordRange = [templateURL rangeOfString:@"%@"];
    
    if (keywordRange.length) {
        NSString* prefix;
        prefix = [templateURL substringWithRange:NSMakeRange(0, keywordRange.location)];
        
        NSString* suffix;
        
        if([templateURL length] > NSMaxRange(keywordRange)) {
            suffix = [templateURL substringWithRange:
                NSMakeRange(NSMaxRange(keywordRange), [templateURL length] - NSMaxRange(keywordRange))];
        }
        else {
            suffix = @"";
        }
        
        return [NSString stringWithFormat:@"%@%@%@", prefix, escapedSearchString, suffix];
    }
    
    return templateURL;
}
