/**
 * @author ilazarte
 */

if (typeof NPR === 'undefined') 
{
    NPR = {};
} 

if (!NPR.reg)
{
    NPR.reg = {};
}

/**
 * A list of all the states and their lower cases.
 */
NPR.reg.STATES = ["alabama","al","alaska","ak","american samoa",
        "as","arizona","az","arkansas","ar","california","ca",
        "colorado","co","connecticut","ct","delaware","de",
        "district of columbia","dc","federated states of micronesia","fm",
        "florida","fl","georgia","ga","guam","gu","hawaii","hi","idaho",
        "id","illinois","il","indiana","in","iowa","ia","kansas","ks",
        "kentucky","ky","louisiana","la","maine","me","marshall islands","mh",
        "maryland","md","massachusetts","ma","michigan","mi","minnesota","mn",
        "mississippi","ms","missouri","mo","montana","mt","nebraska","ne",
        "nevada","nv","new hampshire","nh","new jersey","nj","new mexico","nm",
        "new york","ny","north carolina","nc","north dakota","nd","northern mariana islands",
        "mp","ohio","oh","oklahoma","ok","oregon","or","palau","pw","pennsylvania",
        "pa","puerto rico","pr","rhode island","ri","south carolina","sc","south dakota",
        "sd","tennessee","tn","texas","tx","utah","ut","vermont","vt","virgin islands",
        "vi","virginia","va","washington","wa","west virginia","wv","wisconsin","wi","wyoming","wy"];

/**
 * This is a static function to render a station autocomplete.
 * It doesn't have a default manner to trigger its own execute.
 * It exposes an execute method which external entities can bind to for that purpose.
 * 
 * The class will create a div called "stationsac" on the element once it's created
 * It will append all results to the div under a ul with the id "stationsul"
 * 
 * Css classes applied:
 * stationsacHighlight applied to text in the lis via a span if it matches a text input string.
 * stationsacSelected applied to the entire li when the user hovers.
 */
NPR.reg.stationfinder = function() {
    
    var STATES = NPR.reg.STATES;
    
    var DELAY = 500;
    
    var TIMEOUT = 3000;
    
    var TIMEOUT_ERR_MSG = 'System problem - please try again later.';
    
    var DEFAULT_ERR_MSG = 'No matching station was found.';
    
    var INITIAL_MSG = 'Type a zip code, city and state, or call letters.';
    
    var NO_OP = function() {};

    /**
     * A reference to the ul node.
     */
    var stationsUl;
    
    var errMsg = '';
    
    /**
     * Render that little helper box under the input tag.
     * This is used to begin the initial process.
     */
    function suggest(error) {
        try {

            var input = $('#station_selector').get(0);
            if (typeof input == 'undefined' || input === null) {
                return;
            }

            var parent = $(input).parent('li');
            var offset = $(parent).offset();
            var height = $(parent).height();

            var position = {
                left : offset.left,
                top : offset.top + height
            };

            $('#stationsac').remove(); // try to avoid multiple items
            $('<div></div>')
                .attr('id', 'stationsac')
                .click(function() {
                    $('#stationsac').remove();                 
                })
                .html('<ul id="stationsul"></ul>')
                .css('display', 'none')
                .appendTo(document.body);

            if (error) {
                errMsg = error;
            }

            if (errMsg) {
                $('<li></li>').addClass('stationsfail').css('cursor', 'default').text(errMsg).appendTo('#stationsul');
            } else {
                $('<li></li>').addClass('stationsfail').css('cursor', 'default').html(INITIAL_MSG).appendTo('#stationsul');            
            }

            $('#stationsac')
                .css('left', position.left)
                .css('top', position.top)
                .css('position', 'absolute')
                .css('display', 'block');   
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, suggest', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }

    /**
     * Select the element visually 
     * @param {Object} el
     */
    function highlight(el) {
        try {
            $(el)
                .addClass('stationsacSelected')
                .siblings()
                .removeClass('stationsacSelected');
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, highlight', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }

    /**
     * Destroy the current dropdown.
     * This is invoked after every key since the ac is constantly redrawing itself.
     * @param {Object} message
     */    
    function destroy(message) {
        try {
            $('#stationsac').remove();
            errMsg = '';
            if (!message) {
                message = INITIAL_MSG;    
            }
            suggest(message);
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, destroy', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }
    
    /**
     * Kill function which doesn't render a new tooltip.
     */
    function kill() {
        try {
            $('#stationsac').remove();
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, kill', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }
    
    /**
     * Selects the currently selected item which is found via selected .stationsacSelected.
     */
    function select() {
        try {
            var el = $('.stationsacSelected').get(0);
            if (el === null || typeof el === 'undefined') {
                return;
            }

            var orgId = $(el).data('orgId');
            var nameId = $(el).data('nameId');
            
            /* Don't allow duplicate orgIds.
             * http://bugzilla.npr.org/show_bug.cgi?id=8191
             */
            var exists = false;
            $('input[name="public_user_stations[]"]').each(function() {
                if (this.value === orgId) { 
                   $(this).parent('.stationselected').fadeOut('fast').fadeIn('slow');
                   exists = true; 
                } 
            });

            if (exists) {
                destroy(); 
                return; 
            }

            var currLi = $("#stationinputs > li:last").get(0);
            var currInput = $(currLi).find("input").get(0);
            var width = currInput.offsetWidth;
            var height = currInput.offsetHeight;

            var clone = $(currLi).clone();

            $('<div></div>')
                .addClass('stationselected')
                .width(width)
                .html('<div class="stationstext">' + nameId +
                    '</div><input type="hidden" name="public_user_stations[]" value="' + orgId + '" />' + 
                    '<div class="btn_minus" style="font-family:Verdana; color:#FFFFFF; vertical-align:middle;">&nbsp;<b>x</b>&nbsp;</div>')
                .prependTo(currLi);

            var btnWidth = $(currLi).find('.btn_minus').width();
            $(currLi).find('.stationselected').width(width + btnWidth);
            $(currLi).find('.stationstext')
                .width(width)
                .height(height);

            $(currLi).find('input[type="text"]').remove();

            $(currLi).find('.btn_minus')
                .css('cursor', 'default')
                .click(function() {
                    $(currLi).remove();
                    destroy();
                });

            $(clone).insertAfter(currLi);
            $(clone).find('input')
                .delay({
                    delay: DELAY,
                    event: 'keypress',
                    fn: NPR.reg.stationfinder.multiexecute
                })
                .attr('value', '')
                .focus(function() { destroy(); })
                .blur(function () { }) // see note below
                .focus();

            destroy();

            // if this is the overlay registration, resize the frame to handle the longer list
            if (window.parent != undefined  && window.parent !== window)
            {
                NPR.resizeParentIframe(window.parent.NPR.community.overlayIframeId, '.overlay', 90);
            }
        
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, select', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }

    /**
     * Handle the control keys: up down enter esc.
     * @see http://www.ryancooper.com/resources/keycode.asp
     */
    function handleKey(event) {
        try {
            var update = function(el) {
                if (el === null && el === 'undefined') {
                    $(stationsUl).find('li:first').addClass('stationsacSelected');
                } else {
                    highlight(el);
                }
            };

            switch (event.keyCode) {
                case 13: // enter
                    select();
                    event.preventDefault();
                break;                
                case 27: // escape
                    kill();
                    event.preventDefault();
                break;
                case 38: // up
                    update($('.stationsacSelected').prev());
                break;
                case 40: // down
                    update($('.stationsacSelected').next());
                break;
            }
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, handleKey', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }

    /**
     * Return the first value found via the regex and specifying additional limits.
     * @param {Object} regex
     * @param {Object} value
     * @param {Object} less
     * @param {Object} max (optional)
     */
    function findFirst(regex, value, less, max) {
        try {
            var ret = null;
            var arr = value.match(regex);
            if (!arr) {
                return null;
            } 
            for (var i = 0; i < arr.length; i++) {
                var val = arr[i];
                if (max) {
                    if (val.length > max) {
                        continue;
                    }
                }
                if (val.length < less) {
                    continue;
                }
                ret = val;
                break;
            }
            return ret;
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, findFirst', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }
    
    /**
     * Look through the string to find a state.
     * @param {Object} value
     * @return A location object with parameters city and state.
     */
    function parseLocation(value) {
        try {
            if (!value) {
                return null;
            }
            var city = null;

            for (var i = 0; i < STATES.length; i++) {
                var state = STATES[i];
                var regex = new RegExp("\\b" + state + "\\b", "ig");
                var idx = value.search(regex);
                if (idx !== -1 && idx !== 0) {
                    city = value.substring(0, idx);
                    city = city.replace(/^[\d\s\W]+|[\d\s\W]+$/g, "");
                    break;
                }
            }

            if (!city) {
                return null;
            }

            var location = {
                state : state,
                city : city
            };

            return location;
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, parseLocation', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }
    
    /**
     * Gather the info to be passed into the ajax invocation.
     * @param {Object} value
     */
    function toRequestData(value) {
        try {
            var station = findFirst(/\b(k|w)[\w-]*/ig, value, 3, 6);
            var zipcode = findFirst(/\d+/g, value, 5);
            var location = parseLocation(value);

            var qvalue = null;
            var searchType = null;

            /* Setup the preference order of the search types... */
            if (zipcode) {
                searchType = 'zip';
                qvalue = zipcode;
            } else if(location) {
                searchType = 'location';
                qvalue = location;
            } else if(station) {
                qvalue = station;
                searchType = 'station';
            }

            if (qvalue === null) {
                return null;
            }

            var data = {
                refUrl: escape(document.location.href),
                displayType: 'xml'
            };

            /* Populate the rest of the data now that we've chosen the search */
            if (searchType === 'zip' || searchType === 'station') {
                data.sForm = 'zip';
                data.searchType = 'zipcall';
                data.txtSearchValue = qvalue;
            } else {
                data.sForm = 'city';
                data.searchType = 'city';
                data.txtSearchCity = qvalue.city;
                data.selSearchState = qvalue.state;
            }

			data.stationStatus = 'nonmembers';
            return data; 
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, toRequestData', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }   

    /**
     * Generate the autocomplete.
     * 
     * @param {Object} cfg Container object to be rendered.
     *     Has the following properties:
     *     - requestData, The data used in the request.
     *     - json, The response data
     *     - inputEl, The input element which triggered the execution.
     *     - position, The position.left and position.top for the new div.
     */
    function render(cfg) {
        try {
            var data = cfg.json;
            if (typeof data === 'undefined' || !data) {
                destroy(DEFAULT_ERR_MSG);
                return;
            }
            $('#stationsac').remove();

            var requestData = cfg.requestData;
            var inputEl = cfg.inputEl;
            var position = cfg.position;
            var isMulti = cfg.isMulti;

            $('<div></div>')
                .attr('id', 'stationsac')
                .css('display', 'none')
                .html('<ul id="stationsul"></ul>')
                .appendTo(document.body);

            $('#stationsac')
                .css('left', position.left)
                .css('top', position.top)
                .css('position', 'absolute');                                 

            var ulEl = $('#stationsul').get(0);
            stationsUl = ulEl;

            /* xml2json annoyance:
             * since we aren't sure we will have an array or a single element,
             * we have to choose an appropriate data element to "iterate" on.
             * if length property, treat it as an array otherwise as single element.
             */
            var iterable = data.stationSearch.station;
            if (!iterable.length) {
                iterable = data.stationSearch;
            }

            $.each(iterable, function(i, station) {

                var orgId = station['@attributes'].orgId;
                var band = station.band;
                var cltr = station.callLetters;
                var freq = station.frequency;
                var statusId = station['@attributes'].statusId;
                
                // don't include translators
                if (statusId === "18") {
                	return;
                }

                /* the tagline may be an array, or not exist.
                 * pick the most specific tagline.
                 */
                var taglines = station.tagline;
                var tagline = '';
                if (tagline.length) {
                    tagline = tagline[1];
                } else if(typeof taglines === 'undefined') {
                    tagline = '&nbsp;';
                } else {
                    tagline = taglines;
                }

                var text = '<div style="width:100px;float:left;">' + cltr + '</div> ' + 
                     freq + ' ' + band + '<br />' + tagline;

                var nameId = freq + ': ' + cltr + '-' + band;

                var regex = null;
                if (requestData.txtSearchValue) {
                    regex = new RegExp(requestData.txtSearchValue, "ig");
                    text = text.replace(regex, "<span class='stationsacHighlight'>" + requestData.txtSearchValue + "</span>");    
                } else {
                    regex = new RegExp(requestData.txtSearchCity, "ig");
                    text = text.replace(regex, "<span class='stationsacHighlight'>" + requestData.txtSearchCity + "</span>");
                    regex = new RegExp(requestData.selSearchState, "ig");
                    text = text.replace(regex, "<span class='stationsacHighlight'>" + requestData.selSearchState + "</span>");
                }                                     

                var hoverHighlight = function() {
                    highlight(this);
                };

                $('<li></li>')
                    .css('cursor', 'default')
                    .html(text)
                    .data('orgId', orgId)
                    .data('nameId', nameId)
                    .hover(hoverHighlight, NO_OP)
                    .click(function() {
                        if (isMulti) {
                            select();
                        } else{
                            destroy(); // not really handling non-multi situation yet.                                
                        }
                    })
                    .appendTo(ulEl);
            });

            highlight($(ulEl).find('li:first'));

            $('#stationsac').css('display', 'block');

            // if this is the overlay registration, resize the frame to handle the longer list
            if (window.parent != undefined  && window.parent !== window)
            {
                NPR.resizeParentIframe(window.parent.NPR.community.overlayIframeId, '.overlay', $('#stationsac')[0].scrollHeight);
            }
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, render', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }

    /**
     * Respond to the event which will start the autocomplete process.
     * The hardcoded parentage here is an "li" dependency.  Ideally
     * It could choose the nearest block tag.
     */
    function execute(isMulti, inputEl) {
        try {
            $(document.body).unbind('keyup', handleKey);
            $(document.body).keyup(handleKey);
            var parent = $(inputEl).parent('li');
            var offset = $(parent).offset();
            var height = $(parent).height();

            var position = {
                left : offset.left,
                top : offset.top + height
            };

            var requestData = toRequestData(inputEl.value);
            if (requestData === null) {
                if (inputEl.value.length < 3) {
                    destroy();
                } else {
                    destroy(DEFAULT_ERR_MSG);
                }

                if (window.parent != undefined && window.parent !== window)
                {
                    NPR.resizeParentIframe(window.parent.NPR.community.overlayIframeId, '.overlay', 90);
                }            
                return;
            }

            var errorTimeout = setTimeout(function() { destroy(DEFAULT_ERR_MSG); }, TIMEOUT);

            $.getJSON('/templates/reg/jsonStationSelector.php?callback=?', requestData,
                function(data) {
                    clearTimeout(errorTimeout);
                    render({
                        requestData : requestData,
                        json: data,
                        inputEl: inputEl,
                        position: position,
                        isMulti: isMulti
                    }); 
                });
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.stationfinder, execute', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }
    
    return {
        /**
         * Expose only the execute method.
         */
        execute : function() {
            execute(false, this);
        },
        multiexecute : function() {
            execute(true, this);
        },
        kill : function() {
            kill();            
        },
        destroy : function() {
            destroy();            
        },
        handleKey : handleKey,
        DELAY : DELAY
    };
}();

/**
 * Nifty logger.  Gotta love JS.
 * Dumps the output to a ul named "log".
 * Style the lis based on debug, info, error, warn.
 */
NPR.reg.log = function() {
    
    function _log(level, msg) {
        try {
        
            var date = new Date();
            var els = $("#log > li").get();
            if (els !== null && els.length > 25) {
                 $(els[0]).remove();   
            }

            $('<li></li>')
                .addClass(level)
                .html(date.toUTCString() + " [" + level.toUpperCase() + "] : " + msg)
                .appendTo('#log');
        }
        catch (e) {
            NPR.messaging.exception(e, 'reg.js', 'NPR.reg.log, _log', NPR.messaging.constants.REG_JS_ERROR);
        }           
    }
    
    return {
        debug : function(msg) { _log('debug', msg); },
        warn : function(msg) { _log('warn', msg); },
        error : function(msg) { _log('error', msg); },
        info : function(msg) { _log('info', msg); }
    };
}();

/**
 * Execute initializations on pages we know have station selectors.
 */
$(document).ready(function() {
    try {
        $('.nl_view_sample_link').click(function() {
            window.open(this.href, "sampleNewsletter", "width=580,height=716,scrollbars=yes,status=no");
            return false;        
        });

        $('.stationfinder').delay({
            delay: NPR.reg.stationfinder.DELAY,
            event: 'keypress',
            fn: NPR.reg.stationfinder.multiexecute
        });

        /*
         * fix for IE7 google toolbar issues.
         */
        $('form').find('input[type=text]').focus(function() {
             if (this.value.indexOf('google') > -1) {
                 this.value = '';
             }   
        });

        var currInput = $('#station_selector').get(0);
        if (typeof currInput == 'undefined' || currInput === null)
        {
            return;
        }

        $(document.body).keyup(NPR.reg.stationfinder.handleKey);

        currInput.setAttribute("autocomplete", "off");

        var width = currInput.offsetWidth;
        var height = currInput.offsetHeight;

        var divbutton = $('.stationselected').find('.btn_minus').get(0);
        var btnwidth = $(divbutton).width();

        $('.stationselected').width(width + btnwidth);

        $('.stationselected')
            .find('.stationstext')
            .width(width)
            .height(height);

        $('.stationselected')
            .find('.btn_minus')
            .click(function() {
               $(this).parents('li').remove();
               NPR.reg.stationfinder.destroy();
            });

        $('#station_selector').focus(function() {
            NPR.reg.stationfinder.destroy();
        });

        /*
         * The blur handler is removed again.
         * cannot figure out a way to queue events which 
         * will not kill the stationfinder before a selection has taken place.
         * instead, you can click on the tooltip or press Esc to clear it now.
         * Leaving it in here as a warning.
         */
        $('#station_selector').blur(function() {
        });


        // Bug 7998: Remove user prompt from station selector when user clicks on another input or select element 
        $('input').focus(function(e) {
            if ((e.target && e.target.id != 'station_selector') || (e.srcElement && e.srcElement.id != 'station_selector'))
            {
                 $('#stationsac').remove();
                 $('#station_selector').val('');
            }
        });

        $('select').focus(function(e) {
            if ((e.target && e.target.id != 'station_selector') || (e.srcElement && e.srcElement.id != 'station_selector'))
            {
                 $('#stationsac').remove();
                 $('#station_selector').val('');
            }
        });    

        $(window).resize(function() {
            // if this is the overlay registration, we may have resized the iframe
            // to handle the longer stations list
            // so, don't kill the stationfinder
            if (window.parent === window)
            {
                NPR.reg.stationfinder.kill();
            }
        });
    }
    catch (e) {
        NPR.messaging.exception(e, 'reg.js', ' document.ready', NPR.messaging.constants.REG_JS_ERROR);
    }           
});
