/**
* New City Selector
* Plugin for selecting cities for the www.CopaAir.com site
* Developed by Ramy Deeb <me@ramydeeb.com>
*/


var listObject = function() 
{
    this.fromTextBoxJsonData;
    this.toTextBoxJsonData;
}

//Let's define the cityList Model
function cityList(element, options) {
    this.$element = $(element);
    this.options = options;
    this.defaultList = '';
    this.jsonData = null;
    this.selectedCity = '';
    this.isActive = false;
    this.parent = null;
    this.parentCity = '';
    this.viewAll = false;
};

//The model functions
cityList.prototype = {
    //Show the main list
    show: function(action) {
        var $list = this.list();
        $list.removeClass('error');
        $list.removeClass('info');
        if (this.parent != null) {
            this.parent.$element.removeClass('textBoxError');
        }
        switch (action) {
            case 'search':
                $list.html(this.doSearch());
                this.viewAll = false;
                break;
            case 'full-list':
                $list.html(this.defaultList);
                this.viewAll = true;
                break;
            case 'error':
                $list.html(this.errorScreen());
                this.viewAll = false;
                break;
            case 'no-results':
                $list.html(this.noCoincidenceScreen());
                this.viewAll = false;
                break;
            default:
                $list.html(this.searchScreen());
                this.viewAll = false;
                break;
        };
        var offset = this.$element.offset();
        $list.css('left', offset.left);
        $list.css('top', offset.top + 21);
        $list.show();
        this.lastTimestamp = (new Date()).getTime();
        log('LIST: Shown');
        this.isActive = true;
        if (this.options.dependant != null && this.options.dependant.isActive) {
            this.options.dependant.hide();
        } else if (this.dependant != null && this.dependant.isActive) {
            this.dependant.hide();
        }
    },

    //Hides the list Object
    hide: function() {
        if (this.$list) {
            this.$list.hide();
        }
        log('LIST: Hidden');
        this.isActive = false;
    },

    //Renders the error screen when an object is dependant of a parent and the parent doesn't have a value
    errorScreen: function() {
        var $list = this.list();
        var container = $('<div></div>').addClass('messageContainer');
        $list.addClass('error');
        //Implement parent connection object.parent.textBox.addClass('textBoxError');
        log('SCREEN: Error screen builded');
        container.html('<p class="error">' + this.options.selectFromText + '</p>');
        return container;
    },

    //Renders the search screen
    searchScreen: function() {
        var self = this;
        var $list = this.list();
        var container = $('<div></div>').addClass('messageContainer');
        var link = $('<a href="javascript:void(0)" class="viewAllLink">' + this.options.viewMoreText + '</a>');
        link.click(function(e) {
            e.stopPropagation();
            self.$element.focus();
            self.show('full-list');
        });
        var linkContainer = $('<div></div>').addClass('linkContainer');
        linkContainer.append(link);
        container.html('<p>' + this.options.introMessage + '</p>');
        container.append(linkContainer);
        log('SCREEN: Search screen builded');
        return container;
    },

    //Renders the screen when no coincidenc is encountered
    noCoincidenceScreen: function() {
        this.list().addClass('info');
        this.selectedCity = '';
        log('SCREEN: No coincidence screen builded');
        return $('<div><p class="info">' + this.options.errorMessage + '</p></div>').addClass('messageContainer');
    },

    //Creates or returns the list object
    list: function() {
        if (!this.$list) {
            this.$list = $('<div class="' + this.options.container + '"></div>');
            $('body').append(this.$list);
            log('LIST: Created');
        }
        return this.$list;
    },

    getCurrentStoreFront: function() {
        var currentStoreFront = "GS";
        if (GetCookie != undefined) {
            var currentPos = GetCookie("currentPos");
            if (currentPos != null && currentPos.length > 0) {
                currentStoreFront = currentPos.substring(2);
            }
        }
        return currentStoreFront;
    },

    processCitiesData: function(data) {

        if (data != null) {
            this.jsonData = JSON.parse(data);
            this.defaultList = this.buildList(this.jsonData);

            if (!this.currentCityIsValid()) {
                this.selectedCity = '';

                this.$element.val('');
            }
            else {
                if (this.options.dependant != null) {
                    this.options.dependant.parentCity = this.selectedCity
                }
            }

            if (this.options.dependant != null) {
                myObject.fromTextBoxJsonData = this.jsonData;
            }
            else {
                myObject.toTextBoxJsonData = this.jsonData;
            }

        }


    },

    currentCityIsValid: function() {
        return this.isValidCode(this.selectedCity)
    },

    getElementByCode: function(code) {
        for (var i = 0; i < this.jsonData.routes.length; i++) {
            var tmpCode = this.jsonData.routes[i].code;
            if (tmpCode.toLowerCase() == code.toLowerCase()) {
                return this.jsonData.routes[i];
            }
        }
        return false;
    },

    searchThesaraus: function(val) {
        val = val.toLowerCase();
        var data = { routes: {}, coincidences: false };
        for (var i = 0; i < this.jsonData.routes.length; i++) {
            var tmpCode = this.jsonData.routes[i].code.toLowerCase();
            var tmpName = this.jsonData.routes[i].name.toLowerCase();
            var tmpTesauro = this.jsonData.routes[i].tesauro.toLowerCase();
            if (tmpCode == val || tmpName.indexOf(val) == 0) {
                data.routes[i] = this.jsonData.routes[i];
                data.coincidences = true;
            }
            if (tmpTesauro.indexOf(val) != -1) {
                var st = tmpTesauro.split('|');
                for (var j = 0; j < st.length; j++) {
                    if (st[j].indexOf(val) == 0) {
                        data.routes[i] = this.jsonData.routes[i];
                        data.coincidences = true;
                    }
                }
            }
        }
        return data;
    },

    doSearch: function() {
        var val = this.$element.val();
        if (val.length >= 3) {
            var data = this.searchThesaraus(val);
            if (data.coincidences == true) {
                return this.buildList(data);
            } else {
                return this.noCoincidenceScreen();
            }
        } else {
            return this.searchScreen();
        }
    },

    navigateList: function(e) {
        var $list = this.list();
        var selected = $list.find('li a.itemCity.selected');
        var currentLi = selected.parent();
        var currentUl = currentLi.parent();
        var currentLiList = selected.parents('ul').find('li');
        var currentUlList = selected.parents('span').find('ul');
        var selectedIndex = currentLiList.index(currentLi);
        var ulIndex = currentUlList.index(currentUl);
        switch (e.keyCode) {
            case 13:
                this.selectCity();
                break;
            case 27:
                this.selectCity();
                break;
            case 37:
                if (ulIndex > 0) {
                    var nextElement = currentUlList.eq(ulIndex - 1).find('a.itemCity').eq(selectedIndex);
                    if (nextElement.length != 0) {
                        nextElement.addClass('selected');
                        selected.removeClass('selected');
                    }
                }
                break;
            case 38:
                if (selectedIndex - 1 >= 0) {
                    var nextElement = currentLiList.eq(selectedIndex - 1).find('a.itemCity');
                    if (nextElement.length != 0) {
                        nextElement.addClass('selected');
                        selected.removeClass('selected');
                    }
                } else {
                    if (ulIndex - 1 >= 0) {
                        var nextElement = currentUlList.eq(ulIndex - 1).find('a.itemCity:last');
                        if (nextElement.length != 0) {
                            nextElement.addClass('selected');
                            selected.removeClass('selected');
                        }
                    }
                }
                break;
            case 39:
                if (ulIndex < currentUlList.length) {
                    var nextElement = currentUlList.eq(ulIndex + 1).find('a.itemCity').eq(selectedIndex);
                    if (nextElement.length != 0) {
                        nextElement.addClass('selected');
                        selected.removeClass('selected');
                    }
                }
                break;
            case 40:
                if (selectedIndex + 1 < currentLiList.length) {
                    var nextElement = currentLiList.eq(selectedIndex + 1).find('a.itemCity');
                    if (nextElement.length != 0) {
                        nextElement.addClass('selected');
                        selected.removeClass('selected');
                    }
                } else {
                    if (ulIndex + 1 < currentUlList.length) {
                        var nextElement = currentUlList.eq(ulIndex + 1).find('a.itemCity:first');
                        if (nextElement.length != 0) {
                            nextElement.addClass('selected');
                            selected.removeClass('selected');
                        }
                    }
                }
                break;
        }
    },

    isValidCode: function(code) {
        for (var i = 0; i < this.jsonData.routes.length; i++) {
            var tmpCode = this.jsonData.routes[i].code;
            if (tmpCode.toLowerCase() == code.toLowerCase()) {
                return true;
            }
        }
        return false;
    },

    buildList: function(data) {
        var j = 0;
        var tmpList = $('<span></span>');
        var innerList = $('<ul></ul>');
        var self = this;
        $.each(data.routes, function(i, item) {
            if (j == self.options.rowsPerColumn) {
                tmpList.append(innerList);
                innerList = $('<ul></ul>');
                j = 0;
            }
            innerList.append(self.buildLink(item.code, item.name, i));
            j += 1;
        });
        tmpList.append(innerList);
        var selected = tmpList.find('.itemCity.selected');
        if (selected.length == 0) {
            tmpList.find('.itemCity').eq(0).addClass('selected');
        }
        return tmpList;
    },

    selectCity: function() {
        var $list = this.list();
        var selected = $list.find('a.itemCity.selected');
        var oldCity = this.selectedCity;
        this.hide();
        if (selected.length > 0) {
            this.selectedCity = selected.attr('rel');
            var city = this.getElementByCode(this.selectedCity);
            this.$element.val(city.name + ' ' + city.code);
            log('CORE: Selecting By Click');
            if (this.options.dependant != null) {
                this.options.dependant.parentCity = this.selectedCity;
                this.options.dependant.loadData(this.selectedCity);
            }
        } else {
            log('CORE: Selecting By Text');
            var val = this.$element.val();
            if (val != '') {
                if (val.length == 3 && this.isValidCode(val)) {
                    var city = this.getElementByCode(val);
                    this.selectedCity = city.code;
                    this.$element.val(city.name + ' ' + city.code);
                } else if (val.length > 3) {
                    var last3 = val.substring(val.length - 3);
                    if (this.isValidCode(last3)) {
                        var city = this.getElementByCode(last3);
                        this.selectedCity = city.code;
                        this.$element.val(city.name + ' ' + city.code);
                    } else {
                        this.$element.val('');
                        this.selectedCity = '';
                    }
                } else {
                    this.$element.val('');
                    this.selectedCity = '';
                }
            } else {
                this.selectedCity = '';
            }
            if (this.options.dependant != null) {
                this.options.dependant.parentCity = this.selectedCity;
                this.options.dependant.loadData(this.selectedCity);
            }
        }
        log('CORE: Set city ' + this.selectedCity);
        this.defaultList = this.buildList(this.jsonData);
        if (oldCity.toLowerCase() != this.selectedCity.toLowerCase()) {
            if (this.options.dependant != null && this.selectedCity != '') {
                this.options.dependant.$element.focus();
            } else if ((this.options.nextTabElement != null && this.parent != null && this.parent.isActive) || this.options.nextTabElement != null) {
                this.options.nextTabElement.focus();
                this.options.nextTabElement.click();
            }
        }
    },

    buildLink: function(code, name, i) {
        var self = this;
        var li = $('<li></li>');
        var a = $('<a id="' + i + '" href="javascript:void(0)" class="itemCity" rel="' + code + '">' + name + '<span class="code">' + code + '</span></a>');
        if (this.selectedCity == code) {
            a.addClass('selected');
        }
        a.unbind();
        a.bind("click", function(e) {
            e.preventDefault();
            e.stopPropagation();
            self.$list.find('a.itemCity').removeClass('selected');
            $(this).addClass('selected');
            self.selectCity();
        });
        li.append(a);
        return li;
    },

    loadData: function(airportCode, callback) {
        var temp_url = window.location.href;
        var temp_lang = temp_url.split("/")[5];
        var storeFront = this.getCurrentStoreFront();
        var myUrl = this.options.url + '?lang=' + temp_lang + "&currentPos=" + storeFront;
        var self = this;
        if (airportCode && airportCode != '') {
            myUrl = this.options.url + '?originCode=' + airportCode + '&lang=' + temp_lang + "&currentPos=" + storeFront;
        }
        log('CORE: Loading data with airport code: ' + airportCode);
        $.ajax({
            type: "GET",
            url: myUrl,
            success: function(data) {
                self.processCitiesData(data);
                if (callback != undefined) {
                    callback();
                }
            }
        });
    },

    setRedBox: function() {
        this.parent.$element.addClass('textBoxError');
    },

    setFirtsCity: function() {
        var val = this.$element.val();

        if (val.length > 3) {
            var last3 = val.substring(val.length - 3);
            this.selectedCity = last3;
        }

    }


};

//The main Controller
function bindCityList(selector, options) {
    //Define the default options for the model
    var defaults = {
        url: '/_layouts/GetONDList.ashx',
        introMessage: 'Escriba mas de tres letras del nombre de la <strong>Ciudad</strong>, <strong>Pa&iacute;s</strong> o <strong>C&oacute;digo del aeropuerto</strong> para iniciar la busqueda.',
        errorMessage: 'No hemos encontrado coincidencias',
        viewMoreText: 'Vea todos los destinos &raquo;',
        selectFromText: 'Ingrese primero la ciudad de origen',
        dependant: null,
        selectedCity: null,
        container: 'citiesPopup',
        rowsPerColumn: 15,
        nextTabElement: null
    };

    //Extends the options
    var options = $.extend(defaults, options);
    //Instanciate the main object
    var cs = new cityList(selector, options);

    if (options.dependant != null) {

        options.dependant.parent = cs;
    }
    else {
        //Objecto utilizado en JScript.js, método IsValidErrorText
        myObject = new listObject();
    }

    cs.setFirtsCity();

    //Load the first set of data
    cs.loadData(cs.options.parentCity);

    //Bind the click & focus functions
    cs.$element.click(function(e) {
        this.select();
        e.stopPropagation();
        if ((cs.parent != null && cs.parentCity != '') || cs.parent == null) {
            cs.$element.removeClass('textBoxError');

            if (cs.jsonData != null) {
                cs.show();
            }

        } else if (cs.parent != null && cs.parentCity == '') {
            cs.show('error');
            cs.setRedBox();

        }
        log('EVENTS: Text Box clicked');
    });

    //To fix a Safari/Chrome Bug
    cs.$element.mouseup(function(e) {
        e.preventDefault();
    });

    cs.$element.focusin(function(e) {
        if (!cs.viewAll) {
            cs.$element.click();
        }
    });

    cs.$element.focus(function(e) {
        this.select();
    });

    cs.$element.parent('.city').find('.viewAll').click(function(e) {
        e.preventDefault();
        e.stopPropagation();
        log('EVENTS: View All Image Clicked');

        if (cs.jsonData != null) {
            if (cs.parent == null) {
                cs.show('full-list');
                cs.$element.focus();
            }
            else if (cs.parent != null && cs.parent.selectedCity != "" && cs.parent.selectedCity != null) {
                cs.show('full-list');
                cs.$element.focus();
            }
            if (cs.parent != null && (cs.parent.selectedCity == "" || cs.parent.selectedCity == null)) {
                cs.show('error');
                cs.setRedBox();
            }
        }


    });

    //Bind the Keypress Functions
    cs.$element.keyup(function(e) {

        if (cs.parent == null && cs.$element.val() == "") {
            cs.options.dependant.$element.val('');
            cs.options.dependant.parentCity = '';
            cs.options.dependant.selectedCity = ''
            cs.selectedCity = '';
        }

        if (cs.parent == null || (cs.parent != null && cs.parentCity != '')) {
            if (e.keyCode != 13 && e.keyCode != 27 && e.keyCode != 37 && e.keyCode != 38 && e.keyCode != 39 && e.keyCode != 40) {
                cs.show('search');
            }
        } else if (cs.parent != null && cs.parentCity == '') {
            cs.show('error');
        }
    });

    cs.$element.keydown(function(e) {
        if (cs.parent != null && cs.parentCity == '') {
            e.preventDefault();
        }
    });

    $('body').keyup(function(e) {
        if (cs.isActive) {
            e.preventDefault();
            if (e.keyCode == 13 || e.keyCode == 27 || e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40) {
                cs.navigateList(e);
            }
        }
    });

    //Bind the Blur and Hide functions
    $('body input').not(cs.$element).focusin(function(e) {
        if (cs.isActive) {
            log('EVENTS: Lost Focus');
            cs.selectCity();
        }
    });

    $('body').click(function(e) {
        if ($.browser.msie) {
            if (e.originalEvent != undefined && e.originalEvent.srcElement.className != 'viewAll' && cs.isActive) {
                log('EVENTS: Body clicked');
                cs.selectCity();
            }
        } else if (cs.isActive) {
            e.preventDefault();
            log('EVENTS: Body clicked');
            cs.selectCity();
        }
    });

    return cs;
}

function log(message) {
    if (window.console != undefined) {
        window.console.log(message);
    }
}

//JSON parser implementation by json.org
if (!this.JSON) {
    JSON = {};
}
(function() {
    function f(n) {
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function(key) {

            return this.getUTCFullYear() + '-' +
      f(this.getUTCMonth() + 1) + '-' +
      f(this.getUTCDate()) + 'T' +
      f(this.getUTCHours()) + ':' +
      f(this.getUTCMinutes()) + ':' +
      f(this.getUTCSeconds()) + 'Z';
        };
        String.prototype.toJSON =
    Number.prototype.toJSON =
    Boolean.prototype.toJSON = function(key) {
        return this.valueOf();
    };
    }
    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  gap,
  indent,
  meta = {
      '\b': '\\b',
      '\t': '\\t',
      '\n': '\\n',
      '\f': '\\f',
      '\r': '\\r',
      '"': '\\"',
      '\\': '\\\\'
  },
  rep;
    function quote(string) {

        escapable.lastIndex = 0;
        return escapable.test(string) ?
    '"' + string.replace(escapable, function(a) {
        var c = meta[a];
        return typeof c === 'string' ? c :
      '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
    }) + '"' :
    '"' + string + '"';
    }

    function str(key, holder) {
        var i,
    k,
    v,
    length,
    mind = gap,
    partial,
    value = holder[key];
        if (value && typeof value === 'object' &&
    typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }
        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }
        switch (typeof value) {
            case 'string':
                return quote(value);
            case 'number':
                return isFinite(value) ? String(value) : 'null';
            case 'boolean':
            case 'null':
                return String(value);
            case 'object':
                if (!value) {
                    return 'null';
                }
                gap += indent;
                partial = [];
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }
                    v = partial.length === 0 ? '[]' :
          gap ? '[\n' + gap +
          partial.join(',\n' + gap) + '\n' +
          mind + ']' :
          '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }
                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        k = rep[i];
                        if (typeof k === 'string') {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }
                v = partial.length === 0 ? '{}' :
        gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
        mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
        }
    }

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function(value, replacer, space) {
            var i;
            gap = '';
            indent = '';
            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }
            } else if (typeof space === 'string') {
                indent = space;
            }
            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
      (typeof replacer !== 'object' ||
      typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }
            return str('', {
                '': value
            });
        };
    }
    if (typeof JSON.parse !== 'function') {
        JSON.parse = function(text, reviver) {
            var j;
            function walk(holder, key) {
                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }

            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function(a) {
                    return '\\u' +
          ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }
            if (/^[\],:{}\s]*$/.
      test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
      replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
      replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                j = eval('(' + text + ')');
                return typeof reviver === 'function' ?
        walk({
            '': j
        }, '') : j;
            }
            throw new SyntaxError('JSON.parse');
        };
    }
} ());
