/******************************************************************************
Search Module Singleton
******************************************************************************/


PBS.tvschedules.search = function () {


    /* Private attributes and methods. */


    /* Public Object */
    var obj = {
        zip: '',
        transport: '',
        //navigation_transport: '',
        headend_id: '',
        tvdata_names: [],
        show_options: '',
        keywords: '',
        previously: '',
        lineup: '',
        filter: '',

        // The defaults for the module implementation customizations.
        // These can be overridden by the query string to the module JS include.
        config: {
            'localization': '',
            'provider': 'enabled',
            'favorites': 'enabled',
            'shop': 'enabled',
            'two_page': false,
            'two_page_destination': false
        },

        // These are empty strings because we need it to evaluate to false AND
        // be safe to send over GET without converting to a true value like
        // the strings 'false' or 'undefined'.
        localization_headend_id: '',
        provider_finder: '',
        disable_favorites: '',
        disable_shop: '',

        // We will be instantiating a search_lib object at init time and hanging
        // it on the search_lib attribute here.
        // search_lib_config provides the search_lib constructor with the
        // info it needs to support this particular application.
        search_lib: '', // stub
        search_lib_config: {
            'search_lib': this.search_lib, 
            'search_lib_str': 'PBS.tvschedules.search.search_lib', 
            'form_id': 'pbs_tvschedules_modules-search-search_form',
            'results_container_id': 'pbs_tvschedules_modules-search-results_global_container',
            'identifier': 'search'
        },


        /* Initialization event chain. */

        init: function () {
            PBS.tvschedules.search.initChain.go();
        },

        // This event chain initializes the Search module.
        // It manages default module configuration, implementation customizations, and reacts appropriately to user state. 
        // If we don't have what we need in terms of localization, we pre-empt module initialization with a stationfinder entry point.
        // We also detect if we are part of a two page search module implementation or not.
        initChain: function () {

            var obj = {
                script_id: 'PBS.tvschedules.search.script',
                script_dom_node: '',
                from_two_page: false,
                
                // The defaults for the module implementation customizations.
                // These can be overridden by the query string to the module JS include.
                //config: {
                    //'localization': '',
                    //'two_page': false,
                    //'two_page_destination': false
                //},
                //localization_headend_id: '',

                page_params: {},
                
                go: function () {
                    this.customizations();
                },

                customizations: function () {

                    // Grab the implementation customizations from the module query 
                    // string (the query string of the module JS include, not 
                    // the including page).
                    this.script_dom_node = YAHOO.util.Dom.get(this.script_id);
                    var module_params = PBS.tvschedules.parseURL(this.script_dom_node.src);
                    for (key in module_params) {
                        value = module_params[key];
                        PBS.tvschedules.search.config[key] = value;
                    }
                    if (
                        (PBS.tvschedules.search.config['provider'] != 'disabled') &&
                        (PBS.tvschedules.search.config['localization'])
                    ) {
                        PBS.tvschedules.search.provider_finder = true;
                    }
                    if (PBS.tvschedules.search.config['favorites'] != 'enabled') {
                        PBS.tvschedules.search.disable_favorites = true;
                    }
                    if (PBS.tvschedules.search.config['shop'] != 'enabled') {
                        PBS.tvschedules.search.disable_shop = true;
                    }

                    // Grab the overrides from the query string of the including page.
                    var url = document.location.toString();
                    this.page_params = PBS.tvschedules.parseURL(url);
                    PBS.tvschedules.user.page_params = this.page_params;

                    // Auto-localization.
                    if (
                        PBS.tvschedules.search.config['localization'] &&
                        !PBS.tvschedules.user.cookies['pbsol.station']
                    ) {
                        //alert('autolocalize!');
                        PBS.tvschedules.cookie.setCookieValue(
                            'pbsol.station',
                            PBS.tvschedules.search.config['localization'],
                            'PBS.tvschedules.search.initChain.autolocalizeCallback'
                        );
                    // Stationfinder localization.
                    } else if (
                        (PBS.tvschedules.user.cookies['pbsol.station'] == '') &&
                        (PBS.tvschedules.search.config['localization'] == '') &&
                        !this.page_params['pbs_tvsm_sf_station']
                    ) {
                        // If we don't have a station value from the cookie, module 
                        // query string, or page query string, we'd better render 
                        // the stationfinder in-page zip entry.
                        this.stationFinder();
                    } else {
                        // Fire up the Search module.
                        this.initHTML();
                    }

                },

                autolocalizeCallback: function (args) {
                    PBS.tvschedules.search.initChain.initHTML();
                },

                stationFinder: function () {
                    var URL = PBS.tvschedules.config.base + '/py-publisher/modules/dtv/stationfinder/' + PBS.tvschedules.config.version + '/views/zipInPage';
                    var callback = 'PBS.tvschedules.search.initChain.stationFinderCallback';
                    PBS.tvschedules.data.get(URL, callback, {});
                },

                stationFinderCallback: function (args) {
                    var markup = args['markup'];
                    var div = document.createElement('div');
                    div.id = 'pbs_tvschedules_modules-search-zip_in_page_fab';
                    div.style.display = 'none';
                    div.innerHTML = markup;
                    PBS.tvschedules.stationfinder.zip_in_page_dom_ids.push(div.id);
                    this.script_dom_node.parentNode.insertBefore(div, this.script_dom_node);
                    div.style.display = 'block';
                    var zip_entry = document.getElementById('pbs_tvschedules_modules-sf-zipcode_input');
                    zip_entry.onkeydown = PBS.tvschedules.stationfinder.submitZip;

                },

                // Use the data utility to get the initial UI from the server.
                initHTML: function () {

                    // Extract query string arguments to support browsers that can't set cookies across domains.
                    // If there are no query string arguments, then this data
                    // will be extracted by the server component from the cookie
                    // data in the request headers.
                    var query_params = PBS.tvschedules.parseURL(document.location.toString());
                    PBS.tvschedules.search.getParams();

                    var zip = '';
                    if (query_params['pbs_tvsm_sf_zip']) {
                        zip = query_params['pbs_tvsm_sf_zip'];
                    }

                    var headend_id = '';
                    if (query_params['pbs_tvsm_sf_headend_id']) {
                        headend_id = query_params['pbs_tvsm_sf_headend_id'];
                    }

                    var transport = PBS.tvschedules.search.transport;
                    if (query_params['pbs_tvsm_sf_transport']) {
                        transport = query_params['pbs_tvsm_sf_transport'];
                    }

                    var tvdata_names = '';
                    if (query_params['pbs_tvsm_sf_tvdata_names']) {
                        tvdata_names = query_params['pbs_tvsm_sf_tvdata_names'];
                    }

                    var URL = PBS.tvschedules.config.base + '/py-publisher/modules/dtv/search/' + PBS.tvschedules.config.version + '/views/search';
                    var callback = 'PBS.tvschedules.search.initChain.initCallback';

                    /*
                    alert(
                        'Search Module initHTML()' + '\n' +
                        'URL: ' + URL + '\n' +
                        'pbs_tvsm_sf_zip: ' + zip + '\n' +
                        'pbs_tvsm_sf_headend_id: ' + headend_id + '\n' + 
                        'pbs_tvsm_sf_tvdata_names: ' + tvdata_names + '\n' +
                        'pbs_tvsm_localization_tvdata_name: ' + PBS.tvschedules.search.config['localization'] + '\n' +
                        'pbs_tvsm_provider_finder: ' + PBS.tvschedules.search.provider_finder + '\n' +
                        'pbs_tvsm_disable_favorites: ' + PBS.tvschedules.search.disable_favorites + '\n' +
                        'pbs_tvsm_disable_shop: ' + PBS.tvschedules.search.disable_shop + '\n'
                    );
                    */

                    // Send the arguments to the search view as overrides.
                    // TODO Explore making preferences/user utility gather these values from the cookie/query string at framework init.
                    PBS.tvschedules.data.get( 
                        URL, 
                        callback, 
                        { 
                            'pbs_tvsm_sf_zip': zip,
                            'pbs_tvsm_sf_headend_id': headend_id,
                            'pbs_tvsm_sf_tvdata_names': tvdata_names,
                            'pbs_tvsm_localization_tvdata_name': PBS.tvschedules.search.config['localization'],
                            'pbs_tvsm_provider_finder': PBS.tvschedules.search.provider_finder,
                            'pbs_tvsm_disable_favorites': PBS.tvschedules.search.disable_favorites,
                            'pbs_tvsm_disable_shop': PBS.tvschedules.search.disable_shop
                        } 
                    );
        
                },

                twoPageTest: function () {
                    // In the two page model, there are two pages involved in a
                    // search module implementation. The first page acts as a
                    // search form, and the second acts as a search results
                    // page. Both pages implement the same module code, but pass
                    // it different cusomtization parameters. The search form
                    // page sends search paramaters to the results page via the
                    // query string. The results page displays the results of
                    // the first search and from then on ignores the search
                    // parameters on the results page query string. This is
                    // because all subsequent searches are performed
                    // asyncronously.

                    // Here we determine if a search has been sent to this page
                    // via the query string. If it has, we extract the search
                    // parameters from the page query string and set a flag
                    // making the rest of the system aware. Because a second
                    // search should not re-extract the first search parameters
                    // from the page query string, we check the flag first. 
                    if (!this.from_two_page) {
                        var keywords = this.page_params['pbs_tvsm_s_keywords'];
                        if (keywords) {
                            PBS.tvschedules.search.keywords = keywords;
                            var previously = this.page_params['pbs_tvsm_s_previously'];
                            if (previously) {
                                PBS.tvschedules.search.previously = previously;
                            }
                            var lineup = this.page_params['pbs_tvsm_s_lineup'];
                            if (lineup) {
                                PBS.tvschedules.search.lineup = lineup;
                            }
                            var filter = this.page_params['pbs_tvsm_s_filter'];
                            if (filter) {
                                PBS.tvschedules.search.filter = filter;
                            }
                            var show_options = this.page_params['pbs_tvsm_s_show_options'];

                            // TODO factor this into manageNavigationTransport
                            //if (PBS.tvschedules.search.lineup == 'provider') {
                                //PBS.tvschedules.search.navigation_transport = 'c';
                            //} else if (PBS.tvschedules.search.lineup == 'ota') {
                                //PBS.tvschedules.search.navigation_transport = 'b';
                            //}

                            // Make the search parameters sticky.
                            var form_id = PBS.tvschedules.search.search_lib_config['form_id'];
                            var form = document.getElementById(form_id);
                            form.keywords.value = keywords.replace('+', ' ');
                            if (previously) {
                                form.previously.checked = previously;
                            }
                            form.lineup.value = lineup;
                            form.filter.value = filter;
                            if (show_options) {
                                PBS.tvschedules.search.showSearchOptions();
                            }

                            // Set a flag so the module knows we're in two page mode.
                            this.from_two_page = true;

                            // Perform the initial search from the page parameters.
                            PBS.tvschedules.search.twoPageGo();

                        }
                    }

                },

                /* 
                All callbacks that have to be reached by external utilities have 
                to be public members of module and chain objects so that they can 
                be reached by external callers such as the PBS.tvschedules.data utility.  
                */
                initCallback: function (args) {

                    // Grab the shell markup.
                    var markup = args['markup'];
                    PBS.tvschedules.search.localization_headend_id = args['localization_headend_id'];
                    //PBS.tvschedules.search.navigation_transport = args['navigation_transport'];

                    PBS.tvschedules.search.search_lib_config['localization_tvdata_name'] = PBS.tvschedules.search.config['localization'];
                    if (!PBS.tvschedules.search.search_lib) {
                        PBS.tvschedules.search.search_lib = new PBS.tvschedules.search_lib(PBS.tvschedules.search.search_lib_config);
                    }

                    // Get station specific cookie value.
                    // In forced localization scenarios, we get the station
                    // specific cookie value (conveniently read by this
                    // module's server components during module init) and store
                    // it on the user utility.
                    if (PBS.tvschedules.search.config['localization']) {
                        var cookie_name = 'pbsol.' + PBS.tvschedules.search.config['localization'];
                        var cookie = args['station_specific_cookie']; // Comes back as an object.
                        PBS.tvschedules.user.cookies[cookie_name] = cookie;
                    }

                    // The module might be initialized from an external system
                    // (e.g. preferences when a new provider is selected.)
                    // Because of this, we should check for the pre-existence
                    // of the module dom node and remove it.
                    try {
                        var fab = document.getElementById('pbs_tvschedules_modules-search-module_fab');
                        this.script_dom_node.parentNode.removeChild(fab);
                    } catch(e) {
                    }

                    var div = document.createElement('div');
                    div.id = 'pbs_tvschedules_modules-search-module_fab';
                    div.style.display = 'none';
                    div.style.width = '';
                    div.innerHTML = markup;

                    this.script_dom_node.parentNode.insertBefore(div, this.script_dom_node);

                    /* Initial load actions here. */
                    // Wipe the search parameters and matrix clean.
                    // This is useful for when an external system like
                    // preferences re-initializes the module. In that case we do
                    // not want any dom ids in the matrix for methods like
                    // applyFilter to act upon during the automatic
                    // initPreferences that occurs at module init.
                    PBS.tvschedules.search.search_lib.resetSearch();

                    // Determine if the search module has been implemented in
                    // a one page model or a two page model.
                    this.twoPageTest();

                    // Register a key binding handler for the keywords field.
                    var keywords_entry = document.getElementById('pbs_tvschedules_modules-search-keywords_input');
                    keywords_entry.onkeydown = PBS.tvschedules.search.submitSearch;

                    /* Implementation customizations enacted here.  */
                    // No current implementation customization for Search module.

                    // Show the markup! Booyah!!
                    div.style.display = 'block';

                    PBS.tvschedules.search.initPreferences();
                    PBS.tvschedules.preferences.module_init_preferences.push(
                        PBS.tvschedules.search.initPreferences);

                }

            };

            return obj;

        }(),
        


        /*********************** utility **********************/

        // TODO move this to util.js?
        getParams: function () {

            var cookie_value = PBS.tvschedules.user.cookies['pbsol.sta_extended'];
            var cookie_params = PBS.tvschedules.user.parseStaExtendedCookieValue(cookie_value);
            var query_params = PBS.tvschedules.parseURL(document.location.toString());

            // We're going to look for values in the cookie first, and
            // on the query string as an override.
            this.zip = '';
            if (cookie_params['z']) {
                this.zip = cookie_params['z'];
            }
            if (query_params['pbs_tvsm_sf_zip']) {
                this.zip = query_params['pbs_tvsm_sf_zip'];
            }

            this.transport = ''
            if (cookie_params['t']) {
                this.transport = cookie_params['t'];
            }
            if (query_params['pbs_tvsm_sf_transport']) {
                this.transport = query_params['pbs_tvsm_sf_transport'];
            }
            // This sets navigation_transport the first time getParams
            // is called. We need to do this because there are user
            // actions that rely on navigation_transport having a value.
            // navigation_transport's default value is the value from
            // the cookie or query string, which can't be statically
            // set. So we set it here.
            //if (this.navigation_transport == '') {
                //this.navigation_transport = this.transport;
            //}

            this.headend_id = ''
            if (cookie_params['p']) {
                this.headend_id = cookie_params['p'];
            }
            if (query_params['pbs_tvsm_sf_headend_id']) {
                this.headend_id = query_params['pbs_tvsm_sf_headend_id'];
            }

            this.tvdata_names = ''
            if (cookie_params['s']) {
                this.tvdata_names = cookie_params['s'].join('|');
            }
            if (query_params['pbs_tvsm_sf_tvdata_names']) {
                this.tvdata_names = query_params['pbs_tvsm_sf_tvdata_names'];
            }

        },


        initPreferences: function () {

            /* Cookie-enabled specific initializations. */
            if (PBS.tvschedules.user.cookie_settable) {
                // The call to initPreferences here is longform so that when
                // this is being executed by preferences, the scope is not an
                // issue.
                PBS.tvschedules.search.search_lib.initPreferences(); 
                PBS.tvschedules.search.manageReminders();
            } else { /* Non-cookie-enabled specific initializations. */
                // Disable preferences management.
                document.getElementById('pbs_tvschedules_modules-search-filter_select').style.display = 'none';
                document.getElementById('pbs_tvschedules_modules-search-preferencesheader_links').style.display = 'none';
                // TODO Use the matrix to set all of the favorite stars to a no cookie class.
            }

        },


        // Activate any airdate reminder tabs that correspond to
        // airdate reminders. Deactivate any that don't.
        // Populate forms with remembered email addresses appropriate.
        manageReminders: function () {
            var email_reminders = PBS.tvschedules.user.getEmailReminders(
                this.config['localization']
            );
            var airdate_reminders = email_reminders['airdate_reminders'];
            var airdate_infos = PBS.tvschedules.search.search_lib.matrix['airdate_infos'];
            for (var k in airdate_infos) {
                var info = airdate_infos[k];
                var tab_id = info['tab_id'];
                var r_id = info['r_id'];
                PBS.tvschedules.search.search_lib.airdate_reminders.deactivateAirdateReminder(tab_id);
                for (var j in airdate_reminders) {
                    var airdate_reminder = airdate_reminders[j];
                    var reminder_id = airdate_reminder['reminder_id'];
                    var program_id = airdate_reminder['program_id'];
                    if (reminder_id == r_id) {
                        PBS.tvschedules.search.search_lib.airdate_reminders.activateAirdateReminder(tab_id, reminder_id);
                    }
                }
            }

            // Populate email inputs if appropriate.$
            if ('email_address' in email_reminders) {
                var email = email_reminders['email_address'];
                if (email) {
                    for (var i in airdate_infos) {
                        var info = airdate_infos[i];
                        var input_id = info['email_input_id'];
                        var input = document.getElementById(input_id);
                        var confirm_id = info['email_confirm_id'];
                        var confirm = document.getElementById(confirm_id);
                        var checkbox_id = info['checkbox_id'];
                        var checkbox = document.getElementById(checkbox_id);
                        input.value = email;
                        confirm.value = email;
                        checkbox.checked = true;
                    }
                }
            } else {
                for (var i in airdate_infos) {
                    var info = airdate_infos[i];
                    var input_id = info['email_input_id'];
                    var input = document.getElementById(input_id);
                    var confirm_id = info['email_confirm_id'];
                    var confirm = document.getElementById(confirm_id);
                    var checkbox_id = info['checkbox_id'];
                    var checkbox = document.getElementById(checkbox_id);
                    input.value = '';
                    confirm.value = '';
                    checkbox.checked = false;
                }
            }
        },


        //help: function () {
            //var help_container_id = 'pbs_tvschedules_modules-search-search_help_container';
            //var help_container = document.getElementById(help_container_id);
            //if (help_container.style.display == 'none') {
                //help_container.style.display = '';
            //} else {
                //help_container.style.display = 'none';
            //}
        //},


        help: function () {

            var obj = {

                help_markup_container_id: 'pbs_tvschedules_modules-search-help_markup_container',

                open: function () {
                    var help_markup_container = document.getElementById(this.help_markup_container_id);
                    var help_markup = help_markup_container.innerHTML
                    PBS.tvschedules.overlay.setBody(help_markup);
                    PBS.tvschedules.overlay.show();
                },

                close: function () {
                    PBS.tvschedules.overlay.hide();
                }
            }

            return obj;

        }(),


        showSearchOptions: function () {
            var id = 'pbs_tvschedules_modules-search-search_form_advanced_options';
            if (!(document.getElementById(id).style.display == 'block')) {
                document.getElementById(id).style.display = 'block';
                document.getElementById('pbs_tvschedules_modules-search-search_form_advanced_options_toggle').innerHTML = '[ <a href="#" onclick="PBS.tvschedules.search.showSearchOptions(); return false;">hide options<\/a> ]';
                PBS.tvschedules.search.show_options = true;
            } else {
                document.getElementById(id).style.display = 'none';
                document.getElementById('pbs_tvschedules_modules-search-search_form_advanced_options_toggle').innerHTML = '[ <a href="#" onclick="PBS.tvschedules.search.showSearchOptions(); return false;">show options<\/a> ]';
                PBS.tvschedules.search.show_options = '';
            }
        },


        submitSearch: function (evt) {
            evt = evt || window.event;
            var keyCode = evt.keyCode ? evt.keyCode :
                evt.charCode ? evt.charCode : evt.which;
            if (keyCode == '13') {
                PBS.tvschedules.search.go();
                return false;
            }
        },


        go: function () {

            var form_id = this.search_lib_config['form_id'];
            var form = document.getElementById(form_id);

            var keywords = form.keywords.value;
            var previously = ''
            if (form.previously.checked) {
                previously = form.previously.checked;
            }
            var lineup = form.lineup.value;
            var filter = form.filter.value;

            // If this is a two page search page then we need to GET the
            // search params to the results page.
            if (PBS.tvschedules.search.config['two_page'] == 'form') {
                var info = {
                    'base': PBS.tvschedules.search.config['two_page_destination'],
                    'args': [
                        {'name': 'pbs_tvsm_s_keywords', 'value': keywords},
                        {'name': 'pbs_tvsm_s_previously', 'value': previously},
                        {'name': 'pbs_tvsm_s_lineup', 'value': lineup},
                        {'name': 'pbs_tvsm_s_filter', 'value': filter},
                        {'name': 'pbs_tvsm_s_show_options', 'value': PBS.tvschedules.search.show_options}
                    ]
                };
                url = PBS.tvschedules.buildStatefulURI(info);
                document.location = url;
                return false;
            }

            this.keywords = keywords;
            this.previously = previously;
            this.lineup = lineup;
            this.filter = filter;

            var finalize = function () {

                var results_container_id = PBS.tvschedules.search.search_lib_config['results_container_id'];
                var preferences_links_container_id = 'pbs_tvschedules_modules-search-preferencesheader_links';

                var results_container = document.getElementById(results_container_id);
                var preferences_links_container = document.getElementById(preferences_links_container_id);

                results_container.style.display = '';
                preferences_links_container.style.display = '';

            }

            /*
            alert(
                'this.zip: ' + this.zip + '\n' +
                'this.headend_id: ' + this.headend_id + '\n' +
                'this.tvdata_names: ' + this.tvdata_names + '\n' +
                'this.keywords: ' + this.keywords + '\n' +
                'this.previously: ' + this.previously + '\n' +
                'this.lineup: ' + this.lineup + '\n' +
                'this.filter: ' + this.filter + '\n' +
                "this.config['localization']: " + this.config['localization'] + '\n' +
                'this.localization_headend_id: ' + this.localization_headend_id + '\n' +
                'this.provider_finder: ' + this.provider_finder + '\n'
            );
            */

            this.search_lib.getSearchResults(
                this.zip,
                this.headend_id,
                this.tvdata_names,
                this.keywords,
                this.previously,
                this.lineup,
                this.filter,
                this.config['localization'],
                this.localization_headend_id,
                this.provider_finder,
                this.disable_favorites,
                this.disable_shop,
                finalize,
                PBS.tvschedules.search
            );

        },

        twoPageGo: function () {
            var finalize = function () {
                var results_container_id = PBS.tvschedules.search.search_lib_config['results_container_id'];
                document.getElementById(results_container_id).style.display = '';
            }

            /*
            alert(
                'this.zip: ' + this.zip + '\n' +
                'this.headend_id: ' + this.headend_id + '\n' +
                'this.tvdata_names: ' + this.tvdata_names + '\n' +
                'this.keywords: ' + this.keywords + '\n' +
                'this.previously: ' + this.previously + '\n' +
                'this.lineup: ' + this.lineup + '\n' +
                'this.filter: ' + this.filter + '\n' +
                "this.config['localization']: " + this.config['localization'] + '\n' +
                'this.localization_headend_id: ' + this.localization_headend_id + '\n' +
                'this.provider_finder: ' + this.provider_finder + '\n'
            );
            */

            this.search_lib.getSearchResults(
                this.zip,
                this.headend_id,
                this.tvdata_names,
                this.keywords,
                this.previously,
                this.lineup,
                this.filter,
                this.config['localization'],
                this.localization_headend_id,
                this.provider_finder,
                this.disable_favorites,
                this.disable_shop,
                finalize,
                PBS.tvschedules.search
            );
        }

    };

    return obj;

}(); // The parens here cause the anonymous function to execute and return.
PBS.tvschedules.module_inits.push({method: 'PBS.tvschedules.search.init', data: 'PBS.tvschedules.search', scope: true});
