/*
    Public searcher object, performing ajax searches on a page.
    Rendered customfields should can fire it's search method, their inputs
    will sent if they're placed inside the searchers options.form object.

    They can also register callbacks to be called after the search is done.
*/



/* FIXME: depracated! remove when all code is converted to use search callbacks! */
var Search = {
    last_result: null,
    query_string_dict: null
};

(function($){
 $.searcher = (function() {
    /* internal functions */
    var S = {
        // curtains indicating search in progress (called on results_target)
        loader: null,
        loader_done: null,

        options: {},
        // holds extra params set by ajax links
        extra: {},

        // holds an object of callbacks for each widgetid
        callbacks: {},
        before_search: new Array(),

        init_from_hash: function(){
            if(window.location.hash !== ""){
                inputs = window.location.hash.split('?');
                if (typeof(inputs) !== 'undefined' && inputs.length > 1){
                    inputs = inputs[1].split('&');
                    for(var i=0; i < inputs.length; ++i){
                        inp = inputs[i].split('=');
                        val = inp[1];
                        inp = inp[0];
                        $("input[name='"+inp+"']").each(function(){
                            if ((val === 'true' || val === 'on') && $(this).attr('type') === 'checkbox'){
                                $(this).attr('checked', 'checked');
                            } else {
                                $(this).val(val);
                            }
                        });
                    }
                }
            }
        },

        // Connects click events for all ajax links to fire a search with their parameter,
        //FIXME: turning off extra values! all ajax links cause a get with their url.
        //       we need some way of marking the extra param calls
        enable_ajax_links: function(target) {
            $(S.options.links_selector, target).click(function() {
                S.ajax_search("", $(this).attr('href'));
                return false;
            });
        },

        // Ads an extra hidden input to the search form
        setextra: function(fieldname, value) {
             // FIXME: remove this after persistent ajax options are correctly handled
            if (fieldname=='page') return;

            var f = S.extra[fieldname];
            if (!f) f = S.extra[fieldname] = S.form.find('input[name='+fieldname+']');
            if (!f.length) {
                f = S.extra[fieldname] = $('<input type="hidden" name="'+fieldname+'"/>').appendTo(S.form);
            }
            f.val(value);
        },

        // Proxies the actual search. if the persistent param is set the value will
        // be added to the form as hidden inputs so it's kept between calls.
        // this should only be used for weird exceptions (like layout setting on onet).
        // Real search params should be encoded in links generated in the results!
        search_extra: function(extra, persistent) {
            if ((typeof(extra)=='string')&& persistent) {
                S.setextra(extra.split('=')[0], extra.split('=')[1]);
            }
            S.ajax_search(extra);
        },

        // The main callback after the seach is done.
        callback: function(data) {
            var cbs;
            var widget;
            var feed_url = '';
            if (S._current_url != window.location.pathname) {
                window.location.hash = 'search-url:'+S._current_url;
                feed_url = '/feeds/search/' + S._current_url.substr(S._current_url.indexOf("?"));
            } else {
                window.location.hash = ''; // first page case
            }
            for (widget in S.callbacks) {
                cbs = S.callbacks[widget];
                // if anyone knows why the very same callback (probably) is executed at cbs.before
                // and 10 lines later at cbs.after, please leave message explaining why for future 
                // generation of web developers

                if (cbs.checker!==true && !cbs.checker.length) {//widget is not persistant and dont have any nodes
                    // no longer with us!
                    // if anyone knows what is this, please leave message for future generation of developers
                    delete S.callbacks[widget];
                } else {
                    cbs.before && cbs.before(data, {}, S.options.results_target);
                }
            }

           // insert results into correct places
            S.options.results_target.html(data.results);
            $('#searchClusters').html(data.search_clusters);
            S.last_result = data;

            S.enable_ajax_links(S.options.results_target);
            S.loader_done && S.loader_done(S.indicator);
            S.indicator = null;

            // CALLBACKS!

            for (widget in S.callbacks) {
                cbs = S.callbacks[widget];
                cbs.after && cbs.after(data, {}, S.options.results_target);
            }

            // FIXME: callback set by some session plugin?
            $('#sessionMessages').html(data.session_messages);

            // FIXME: hack until we convert everything using this to use callbacks
            // please leave message what's the idea of this hack, for future
            Search.last_result = S.last_result;

            if (feed_url != '') {
                $('a.rss_link').each(function(index, link) {
                        link.href = feed_url;
                });
            }
        },

        generate_current_url: function(extra) {
            var url;
            url = S.options.url + S.form.find(":input:not(.nosubmit)").serialize()
            if (typeof(extra) == 'object' &&
                typeof(extra.currentTarget) == 'object' &&
                typeof(extra.currentTarget.radius) != 'undefined') {
                    url += '&' + extra.currentTarget.radius.name + '=' + extra.currentTarget.radius.value;
            } else if (typeof(extra) != 'object') {
                    url += '&'+ extra;
            }
            return url;
        },

        // Performs the actual search.
        // Call all registered callbacks when the results are back.
        ajax_search: function(extra, fullurl) {
            var result;
            
            //pre-validation
            for (var i =0;i<S.before_search.length;i++) {
                result = S.before_search[i]();
                if(!result) { break;}
            }
            if (!result) {return false;}
            // FIXME: hack, will get rid of it later
            if (window.sensimap&&sensimap.geocoding) { return false; }

            if (S.indicator) { return false; }
            S.indicator = S.loader && S.loader(S.options.results_target, true);
            var url;
            if (fullurl) {
                url = fullurl;
            } else {
                //url = S.options.url+S.form.serialize();
                //clean urls from some sheet
                url = S.generate_current_url(extra);
            }

            // FIXME: possibly add as a callback? results data['search_path'] holds
            // the complete and seo friendly url, maybe it's better?
            if(typeof(pageTracker) != 'undefined')
            {
                // pageTracker is not in this file, so probably it's sometimes created by some other scripts,
                // but sometimes does not mean always, thus i've added typeof checking if it's actually created
                pageTracker._trackPageview(url)
            }
            S._current_url = url;
            // ensure response is JSON and not a HTML cached by browser
            url += ((url.indexOf('?') == -1) ? '?' : '&') + 'no_b=' + Math.random();
            // add backlink to url
            if (S.options.backlinks) {
                var href = window.location.href;
                if (href.indexOf("#") != -1) {
                    href = href.substring(0, href.indexOf("#"));
                }
                url += "&backlink=" + escape(escape(href))
                if (S._current_url) {
                    url += escape(escape("#search-url:" + S._current_url));
                }
            }

            $.getJSON(url, function (response) {
                S.callback(response);
            });
            return false;
        }
    };

    return {
        init: function (options) {
            S.options = $.extend({
                // Default options to be overridden at initialization.
                url: '/search/advanced/?',
                form: $('#searchAdvancedForm'),
                results_target: $('.adverts_list'),
                links_selector: '.searchnav a',
                backlinks: false
                }, options);

            S.form = S.options.form; // shortcut
            S.indicator = null;
            S.options.form.submit(S.ajax_search); // init searcher only ONCE because of that!
            S.enable_ajax_links(); // for ALL links on the page
            S.init_from_hash();
            //FIXME: this should be removed once we agree that's something we need for
            //every page and it will always be included, like popup code
            if (!window.loader) {
                S.loader = function(t) { return 1; };
                S.loader_done = function(l) {};
                }
                else S.loader = window.loader
            // FIXME: DEPRECATED: category change functionality, can be implemented outside of search!
            var category_select = $('#searchAdvancedForm #search_select_category');
            var advanced_form = $('#advanced_search_ajax_form_id');
            category_select.change(function() {
                $.get( "/search/form/" + category_select.val() + "/", { 'output' : 'inner_html' },
                    function(data) { advanced_form.html(data); });
                }).change();

            // Correct RSS link in case of simple query search
            current_url = S.generate_current_url("");
            feed_url = '/feeds/search/' + current_url.substr(current_url.indexOf("?"));
            $('a.rss_link').each(function(index, link) {
                link.href = feed_url;
            });
        },

        /** Add a set of callbacks coresponding to a given field.
         * callbacks are hold under field keys so they can be replace (if a searchable customfield
         * widget reloads after category change it will override old callbacks)
         *
         * @param: {Object} callbacks:
         * @param: {Function} callbacks.after - called after search is done and results are injected to DOM.
         *      Arguments passed:
         *          results_data - the result object returned by the app
         *          cluster_counts - counts extracted for the given field_name
         *          results_target - for convenience (it is returned by add callback, so it can be stored)
         * @param {Function} callbacks.before - called after search is done but before results are injected to DOM
         * @param {Bool} [dontCheck] - if true wigdet is persistant, default undefined (false)
         */
        addcallbacks: function(widgetid, callbacks, dontCheck) {
            var widget = {}
            if(!dontCheck) {//if widget is checkable
                var classname = widgetid+'_cls';
                $('#'+widgetid).addClass(classname);
                widget.checker = $('.'+classname);
            } else {
                widget.checker = true;
            }
            widget.after  = callbacks.after;
            widget.before = callbacks.before;

            S.callbacks[widgetid] = widget;
            return S.options.results_target;
        },
        
        addBeforeSearch: function(func) {
            S.before_search[S.before_search.length] = func;
        },

        // FIXME: i don't know how to handle this... we should remove callbacks for widget's that are gone
        // (after category change for example).
        // for now after each search call the list of callbacks is checked if the objects actually exists
//        removecallbacks: function(widgetid) {
//            delete S.callbacks[widgetid];
//        },

        get_params: function() {
            return S.form.serialize();
        },

        // Public search interface
        run: function() {
            S.ajax_search.apply(this, arguments);
        },

        get_current_url: function() {
            return S._current_url;
        },

        _debug: function() { console.log(S); } // you can look at the internal state, but don't
    };


    })();
})(jQuery);

