//  SearchLoad Options: A Firefox addon that extends the capabilities of the searchbar.
//  Copyright (C) 2012  Esteban Torres
//  
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//  
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//  
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

const Cc = Components.classes, Ci = Components.interfaces;

searchLoad_Preferences = {
    updateListeners: function(){
        let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
        let enumerator = wm.getEnumerator("navigator:browser");

        while (enumerator.hasMoreElements())
        {
            let win = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);
            if( win.searchLoad_Options )
                win.searchLoad_Options.setSearchbarListeners();
        }
    },

    pref: {},

    prefObserver: {

        branch   : null,

        register : function(){
            let prefService = Cc["@mozilla.org/preferences-service;1"]
                                        .getService(Ci.nsIPrefService);
            this.branch = prefService.getBranch("extensions.searchload.");
            this.branch.addObserver("", this, false);
        },

        unregister : function(){
            this.branch.removeObserver("", this);
        },

        observe : function(aSubject, aTopic, aData){
            switch(aData){
                case "clear_on_submission" : searchLoad_Preferences.pref.clear_on_submission = this.branch.getBoolPref( "clear_on_submission" );
                                             searchLoad_Preferences.updateListeners();
                                             break;
                case "clear_on_blur"       : searchLoad_Preferences.pref.clear_on_blur       = this.branch.getBoolPref( "clear_on_blur"       );
                                             searchLoad_Preferences.updateListeners();
                                             break;
                case "clear_delay"         : searchLoad_Preferences.pref.clear_delay         = this.branch.getIntPref ( "clear_delay"         );
                                             searchLoad_Preferences.pref.clear_delay *= 1000;
                                             searchLoad_Preferences.updateListeners();
                                             break;
                case "defaultengine"       : searchLoad_Preferences.pref.defaultengine       = this.branch.getCharPref( "defaultengine"       );
                                             searchLoad_Preferences.pref.defaultengine = decodeURIComponent( escape(searchLoad_Preferences.pref.defaultengine) );
                                             break;
                case "reset_on_submission" : searchLoad_Preferences.pref.reset_on_submission = this.branch.getBoolPref( "reset_on_submission" );
                                             searchLoad_Preferences.updateListeners();
                                             break;
                case "reset_on_blur"       : searchLoad_Preferences.pref.reset_on_blur       = this.branch.getBoolPref( "reset_on_blur"       );
                                             searchLoad_Preferences.updateListeners();
                                             break;
                case "reset_delay"         : searchLoad_Preferences.pref.reset_delay         = this.branch.getIntPref ( "reset_delay"         );
                                             searchLoad_Preferences.pref.reset_delay *= 1000;
                                             searchLoad_Preferences.updateListeners();
                                             break;
                case "default_tab"         : searchLoad_Preferences.pref.default_tab         = this.branch.getIntPref ( "default_tab"         ); break;
                case "detect_blank_tab"    : searchLoad_Preferences.pref.detect_blank_tab    = this.branch.getBoolPref( "detect_blank_tab"    ); break;
                case "detect_home_tab"     : searchLoad_Preferences.pref.detect_home_tab     = this.branch.getBoolPref( "detect_home_tab"     ); break;
                case "detect_new_tab_page" : searchLoad_Preferences.pref.detect_new_tab_page = this.branch.getBoolPref( "detect_new_tab_page" ); break;
            }
        }
    }
};

function searchLoad_Options (win)
{
    var self      = this;
    var window    = win;
    var searchbar = win.document.getElementById("searchbar");

    this.MOZhandleSearch = null;
    this.MOZdoSearch = null;

    this.eventModifier = false;
    this.eventShift = false;
    this.clearTID = null; //Timeout ID
    this.resetTID = null; //Timeout ID
    this.paused    = false;
    this.submitted = false;

    this.searchbarFocusListening = false;
    this.searchbarBlurListening  = false;

    this.tbListener = function(event){
        switch( event.type ){
            case "customizationstarting": self.restoreSearchbar(); break;
            case "customizationending": self.init(); break;
        }
    };

    window.gNavToolbox.addEventListener('customizationstarting', self.tbListener, false );
    window.gNavToolbox.addEventListener('customizationending'  , self.tbListener, false );

    this.searchbarFocusListener = function(event){
        if( self.paused || ( self.clearTID==null && self.resetTID==null ) )
            return;

        window.clearTimeout(self.clearTID);
        window.clearTimeout(self.resetTID);
        self.paused = true;
    };

    this.searchbarBlurListener = function(event){
        if( searchbar.textbox.hasAttribute("focused") )
            return;

        if( searchLoad_Preferences.pref.clear_on_blur )
            self.clearSearchbar( searchLoad_Preferences.pref.clear_delay );

        if( searchLoad_Preferences.pref.reset_on_blur )
            self.resetSearchEngine( searchLoad_Preferences.pref.reset_delay );

        if( !self.paused )
            return;

        if( self.submitted && searchLoad_Preferences.pref.clear_on_submission )
            self.clearSearchbar( searchLoad_Preferences.pref.clear_delay );

        if( self.submitted && searchLoad_Preferences.pref.reset_on_submission )
            self.resetSearchEngine( searchLoad_Preferences.pref.reset_delay );

        self.paused = false;
    };

    this.removeSearchbarListeners = function(){
        searchbar.removeEventListener('focus',        self.searchbarFocusListener, false);
        searchbar.removeEventListener('blur',         self.searchbarBlurListener , false);
        searchbar.removeEventListener('popupshowing', self.searchbarFocusListener, false);
        searchbar.removeEventListener('popuphiding',  self.searchbarBlurListener , false);
        self.searchbarFocusListening = false;
        self.searchbarBlurListening  = false;
    };

    this.setSearchbarListeners = function(){
        if( !searchbar )
            return;

        if( ((searchLoad_Preferences.pref.clear_delay > 0 ) && (searchLoad_Preferences.pref.clear_on_blur || searchLoad_Preferences.pref.clear_on_submission)) ||
            ((searchLoad_Preferences.pref.reset_delay > 0 ) && (searchLoad_Preferences.pref.reset_on_blur || searchLoad_Preferences.pref.reset_on_submission)) )
        {
            if( !self.searchbarFocusListening )
            {
                if( searchLoad_Preferences.pref.clear_delay > 0 ||
                    searchLoad_Preferences.pref.reset_delay > 0 )
                {
                    searchbar.addEventListener('focus',        self.searchbarFocusListener, false);
                    searchbar.addEventListener('popupshowing', self.searchbarFocusListener, false);
                    self.searchbarFocusListening = true;
                }
            }
            if( !self.searchbarBlurListening )
            {
                searchbar.addEventListener('blur',        self.searchbarBlurListener, false);
                searchbar.addEventListener('popuphiding', self.searchbarBlurListener, false);
                self.searchbarBlurListening = true;
            }
        }
        else if( searchLoad_Preferences.pref.clear_on_blur || searchLoad_Preferences.pref.reset_on_blur )
        {
            if( !self.searchbarBlurListening )
            {
                searchbar.addEventListener('blur',        self.searchbarBlurListener, false);
                searchbar.addEventListener('popuphiding', self.searchbarBlurListener, false);
                self.searchbarBlurListening = true;
            }
            if( self.searchbarFocusListening )
            {
                searchbar.removeEventListener('focus',        self.searchbarFocusListener, false);
                searchbar.removeEventListener('popupshowing', self.searchbarFocusListener, false);
                self.searchbarFocusListening = false;
            }
        }
        else
            self.removeSearchbarListeners();
    };

    this.clearSearchbar = function(delay){
        window.clearTimeout(self.clearTID);
        self.clearTID = window.setTimeout(
            function(){
                searchbar.value = '';
                let changeEvent = window.document.createEvent('Event');
                changeEvent.initEvent('input', true, true);
                window.setTimeout( function(){searchbar.dispatchEvent(changeEvent);}, 0 );

                self.clearTID = null;
                self.submitted = false;
            }, delay
        );
    };

    this.resetSearchEngine = function(delay){
        let selectedEngine = searchbar.currentEngine.name;

        if(selectedEngine != searchLoad_Preferences.pref.defaultengine)
        {
            window.clearTimeout(self.resetTID);
            self.resetTID = window.setTimeout(
                function(){
                    if( searchbar.searchService.getEngineByName(searchLoad_Preferences.pref.defaultengine) )
                        searchbar.currentEngine = searchbar.searchService.getEngineByName(searchLoad_Preferences.pref.defaultengine);

                    let changeEvent = window.document.createEvent('Event');
                    changeEvent.initEvent('input', true, true);
                    window.setTimeout( function(){searchbar.dispatchEvent(changeEvent);}, 0 );

                    self.resetTID = null;
                    self.submitted = false;
                }, delay
            );
        }
    };

    this.configure = function(){
        let winManager = Cc["@mozilla.org/appshell/window-mediator;1"]
                                   .getService(Ci.nsIWindowMediator);
        let recentWin = winManager.getMostRecentWindow("SearchLoadOptions:Preferences");
        if( recentWin )
            recentWin.focus();
        else
            window.openDialog("chrome://searchload/content/search-options.xul", "", "dialog,centerscreen");
    };

    this.init = function (){
        if(!searchbar)
            return;

        this.setSearchbarListeners();

        let stringBundle = window.document.getElementById("stringbundle-searchloadoptions");
        if( !stringBundle )
        {
            let bundleset = window.document.getElementById("stringbundleset");
            stringBundle = window.document.createElement("stringbundle");
            stringBundle.setAttribute("id","stringbundle-searchloadoptions");
            stringBundle.setAttribute("src","chrome://searchload/locale/searchbar.properties");
            bundleset.appendChild( stringBundle );
        }

        if( searchbar._popup && !window.document.getElementById("menuitem-searchloadoptions") )
        {
            let element = window.document.createElement("menuitem");
            element.setAttribute("class","open-engine-manager menuitem-iconic engine-icon");
            element.setAttribute("id","menuitem-searchloadoptions");
            element.setAttribute("label",stringBundle.getString("label.searchoptions"));
            element.setAttribute("image","chrome://searchload/skin/menuitem-icon.png");
            element.addEventListener('command', this.configure, true );
            searchbar._popup.appendChild(element);
        }

        if(!this.MOZhandleSearch)
        {
            this.MOZhandleSearch = searchbar.handleSearchCommand;

            searchbar.handleSearchCommand = function(aEvent){
                self.eventModifier = aEvent&&(aEvent.altKey||aEvent.ctrlKey||aEvent.shiftKey||aEvent.button==1);
                self.eventShift    = aEvent&&aEvent.shiftKey;
                self.MOZhandleSearch.apply(this,arguments);
                self.eventModifier = false;
                self.eventShift    = false;
            };
        }

        if(!this.MOZdoSearch)
        {
            this.MOZdoSearch = searchbar.doSearch;

            searchbar.doSearch = function(aData,aWhere){
                if( self.eventModifier )
                    switch( searchLoad_Preferences.pref.default_tab )
                    {
                        case 0:  aWhere=(self.eventShift)?"tabshifted":"tab"; break;
                        case 1:  aWhere=(self.eventShift)?"tabshifted":"current"; break;
                        case 2:  aWhere=(self.eventShift)?"tab":"current"; break;
                        default: aWhere="tab";
                    }
                else
                {
                    let currentURL = window.getWebNavigation().currentURI.spec;
                    let homeTabDetected = false;
                    if(searchLoad_Preferences.pref.detect_home_tab)
                    {
                        let homepages = window.gPrefService.getComplexValue("browser.startup.homepage",Ci.nsIPrefLocalizedString).data;
                            homepages = homepages.split("|");
                        currentURL = currentURL.replace(/(^\s+)|(\s+$)|(^https?:\/\/)|(\/$)/g,"").replace(/^www\./,"");
                        for(let i=0; i<homepages.length; i++)
                            if( currentURL==homepages[i].replace(/(^\s+)|(\s+$)|(^https?:\/\/)|(\/$)/g,"").replace(/^www\./,"") )
                            {
                                homeTabDetected = true;
                                break;
                            }
                    }
                    if( searchLoad_Preferences.pref.default_tab==0
                        || (
                           searchLoad_Preferences.pref.detect_new_tab_page && currentURL==window.gPrefService.getCharPref("browser.newtab.url")
                           || searchLoad_Preferences.pref.detect_blank_tab && currentURL=="about:blank"
                           || searchLoad_Preferences.pref.detect_home_tab && homeTabDetected
                        ) && !window.getWebNavigation().nsIWebProgress.isLoadingDocument
                      )
                        aWhere="current";
                    else switch( searchLoad_Preferences.pref.default_tab )
                    {
                        case 1: aWhere="tab"; break;
                        case 2: aWhere="tabshifted"; break;
                        default: aWhere="tab";
                    }
                }

                self.paused    = false;
                self.submitted = true;

                if( searchLoad_Preferences.pref.clear_on_submission )
                    self.clearSearchbar( searchLoad_Preferences.pref.clear_delay );

                self.MOZdoSearch.apply(this,arguments);

                if( searchLoad_Preferences.pref.reset_on_submission )
                    self.resetSearchEngine( searchLoad_Preferences.pref.reset_delay );
            }//doSearch
        }
    };//init

    this.restoreSearchbar = function(){
        if( !searchbar )
            return;

        self.removeSearchbarListeners();

        let menuitem = window.document.getElementById("menuitem-searchloadoptions");
        if( menuitem )
        {
            menuitem.removeEventListener('command', self.configure, true );
            menuitem.parentNode.removeChild( menuitem );
        }

        searchbar.doSearch = self.MOZdoSearch;
        searchbar.handleSearchCommand = self.MOZhandleSearch;
        self.MOZdoSearch = null;
        self.MOZhandleSearch = null;

        let stringBundle = window.document.getElementById("stringbundle-searchloadoptions");
        if( stringBundle )
            stringBundle.parentNode.removeChild(stringBundle);
    };

    this.shutdown = function(){
        window.gNavToolbox.removeEventListener('customizationstarting', self.tbListener, false );
        window.gNavToolbox.removeEventListener('customizationending'  , self.tbListener, false );
        self.restoreSearchbar();
    };
}

function loadIntoWindow(window)
{
    //Check for navigator:browser
    //
    if( !window.gNavToolbox )
        return;

    window.searchLoad_Options = new searchLoad_Options(window);
    window.searchLoad_Options.init();
}

function unloadFromWindow(window)
{
    //Check for navigator:browser
    //
    if( !window.gNavToolbox )
        return;

    window.searchLoad_Options.shutdown();
    window.searchLoad_Options = null;
}

var windowListener = {
    onOpenWindow: function(aWindow)
    {
        let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIDOMWindow);
        domWindow.addEventListener("load", function(){
            domWindow.removeEventListener("load", arguments.callee, false);
            domWindow.setTimeout( loadIntoWindow, 0, domWindow );
        }, false);
    },
    onCloseWindow: function(aWindow)
    {
        let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
        unloadFromWindow(domWindow);
    },
    onWindowTitleChange: function(aWindow, aTitle) {}
};

function startup(data, reason) {
    searchLoad_Preferences.prefObserver.register();

    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("clear_on_submission");}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.clear_on_submission", true );}
    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("clear_on_blur"      );}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.clear_on_blur"      , false);}
    try{searchLoad_Preferences.prefObserver.branch.getIntPref ("clear_delay"        );}catch(e){searchLoad_Preferences.prefObserver.branch.setIntPref ( "extensions.searchload.clear_delay"        , 5    );}
    try{searchLoad_Preferences.prefObserver.branch.getCharPref("defaultengine"      );}catch(e){searchLoad_Preferences.prefObserver.branch.setCharPref( "extensions.searchload.defaultengine"      , ""   );}
    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("reset_on_submission");}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.reset_on_submission", true );}
    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("reset_on_blur"      );}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.reset_on_blur"      , false);}
    try{searchLoad_Preferences.prefObserver.branch.getIntPref ("reset_delay"        );}catch(e){searchLoad_Preferences.prefObserver.branch.setIntPref ( "extensions.searchload.reset_delay"        , 5    );}
    try{searchLoad_Preferences.prefObserver.branch.getIntPref ("default_tab"        );}catch(e){searchLoad_Preferences.prefObserver.branch.setIntPref ( "extensions.searchload.default_tab"        , 1    );}
    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("detect_blank_tab"   );}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.detect_blank_tab"   , true );}
    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("detect_home_tab"    );}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.detect_home_tab"    , false);}
    try{searchLoad_Preferences.prefObserver.branch.getBoolPref("detect_new_tab_page");}catch(e){searchLoad_Preferences.prefObserver.branch.setBoolPref( "extensions.searchload.detect_new_tab_page", true );}

    searchLoad_Preferences.pref.clear_on_submission = searchLoad_Preferences.prefObserver.branch.getBoolPref( "clear_on_submission" );
    searchLoad_Preferences.pref.clear_on_blur       = searchLoad_Preferences.prefObserver.branch.getBoolPref( "clear_on_blur"       );
    searchLoad_Preferences.pref.clear_delay         = searchLoad_Preferences.prefObserver.branch.getIntPref ( "clear_delay"         );
    searchLoad_Preferences.pref.defaultengine       = searchLoad_Preferences.prefObserver.branch.getCharPref( "defaultengine"       );
    searchLoad_Preferences.pref.reset_on_submission = searchLoad_Preferences.prefObserver.branch.getBoolPref( "reset_on_submission" );
    searchLoad_Preferences.pref.reset_on_blur       = searchLoad_Preferences.prefObserver.branch.getBoolPref( "reset_on_blur"       );
    searchLoad_Preferences.pref.reset_delay         = searchLoad_Preferences.prefObserver.branch.getIntPref ( "reset_delay"         );
    searchLoad_Preferences.pref.default_tab         = searchLoad_Preferences.prefObserver.branch.getIntPref ( "default_tab"         );
    searchLoad_Preferences.pref.detect_blank_tab    = searchLoad_Preferences.prefObserver.branch.getBoolPref( "detect_blank_tab"    );
    searchLoad_Preferences.pref.detect_home_tab     = searchLoad_Preferences.prefObserver.branch.getBoolPref( "detect_home_tab"     );
    searchLoad_Preferences.pref.detect_new_tab_page = searchLoad_Preferences.prefObserver.branch.getBoolPref( "detect_new_tab_page" );

    searchLoad_Preferences.pref.clear_delay  *= 1000;
    searchLoad_Preferences.pref.reset_delay  *= 1000;
    searchLoad_Preferences.pref.defaultengine = decodeURIComponent( escape(searchLoad_Preferences.pref.defaultengine) );

    let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
    let enumerator = wm.getEnumerator("navigator:browser");

    while (enumerator.hasMoreElements())
    {
        let win = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);
        win.setTimeout( loadIntoWindow, 0, win );
    }

    wm.addListener(windowListener);
}

function shutdown(data, reason) {
    if (reason == APP_SHUTDOWN)
        return;

    searchLoad_Preferences.prefObserver.unregister();

    let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
    wm.removeListener(windowListener);
    let enumerator = wm.getEnumerator("navigator:browser");

    while (enumerator.hasMoreElements())
    {
        let win = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);
        unloadFromWindow(win);
    }

    searchLoad_Options = null;
}

function install(data, reason) {
    let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);

    try{prefs.getBoolPref( "extensions.searchload.clear_on_submission");}catch(e){prefs.setBoolPref( "extensions.searchload.clear_on_submission", true );}
    try{prefs.getBoolPref( "extensions.searchload.clear_on_blur"      );}catch(e){prefs.setBoolPref( "extensions.searchload.clear_on_blur"      , false);}
    try{prefs.getIntPref ( "extensions.searchload.clear_delay"        );}catch(e){prefs.setIntPref ( "extensions.searchload.clear_delay"        , 5    );}
    try{prefs.getCharPref( "extensions.searchload.defaultengine"      );}catch(e){prefs.setCharPref( "extensions.searchload.defaultengine"      , ""   );}
    try{prefs.getBoolPref( "extensions.searchload.reset_on_submission");}catch(e){prefs.setBoolPref( "extensions.searchload.reset_on_submission", true );}
    try{prefs.getBoolPref( "extensions.searchload.reset_on_blur"      );}catch(e){prefs.setBoolPref( "extensions.searchload.reset_on_blur"      , false);}
    try{prefs.getIntPref ( "extensions.searchload.reset_delay"        );}catch(e){prefs.setIntPref ( "extensions.searchload.reset_delay"        , 5    );}
    try{prefs.getIntPref ( "extensions.searchload.default_tab"        );}catch(e){prefs.setIntPref ( "extensions.searchload.default_tab"        , 1    );}
    try{prefs.getBoolPref( "extensions.searchload.detect_blank_tab"   );}catch(e){prefs.setBoolPref( "extensions.searchload.detect_blank_tab"   , true );}
    try{prefs.getBoolPref( "extensions.searchload.detect_home_tab"    );}catch(e){prefs.setBoolPref( "extensions.searchload.detect_home_tab"    , false);}
    try{prefs.getBoolPref( "extensions.searchload.detect_new_tab_page");}catch(e){prefs.setBoolPref( "extensions.searchload.detect_new_tab_page", true );}
}

function uninstall(data, reason) {
    if( reason == ADDON_UNINSTALL )
    {
        let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
        prefs.deleteBranch("extensions.searchload.");
    }
}
