/**
 * Get city and regions by entered postcode
 * @version:  01.01.01 Alpha
 * @modified: 2009-10-15 17:18:00
 */
var city_regions = newObject({
    // Form elements
    id_postcode : null, // Hidden field for id_postcode
    input  : null, // Field for input postcode

    // Select city elements
    loader_city : null, // load city data
    container_city : null, // containing element
    select_city : null, // ????

    // Select PC elements
    loader_pc : null, // loader of postcode data
    container_pc : null, // containing element
    sel_region1_pc : null,  // select element, containing list of regions1
    sel_region2_pc : null,  // select element, containing list of regions2
    sel_city_pc : null,     // select element, containing list of cities
    sel_postcode_pc : null, // select element, containing list oа postcodes
    row_postcode_pc : null, // ??? where post code is being selected
    selected_pc     : '',   //curently selected postcode flag

    // common properties
    postcode_cache : null, //cache of returned postcodes
    current_pc     : '',   //curently typed postcode
    current_city_id   : null, // gets previously selected id of city
    current_city_name : null, // gets selected previously name of city

    setCity : false, // flag that allows to show list of postcodes, default doesn't

    isEnabled : true,


    // Main event parsing functions

    //  -----Function pressPcKey----------\\
    //
    // This function is being called by onKeyUp event on input field where postcode is being entered
    // This function has several checks:
    // 1) compares postcodes entered beore and after requests
    // 2) checks flag selected_pc
    // 3) then checks is defined postcode_cache, and it's property pc
    // 4) and finally  checks if poscode cache is null
    // if 2,3,4 conditions return true, the field where city name is shown will be cleared
    //

    //-------Function onclickCity----------\\
    /*
     * This function is being called when user clicks on field where city name is shown
     * This function has several checks:
     * 1) It checks if poscode is entered
     * 2) checks postcode cache and it's property pc
     * if currently entered postcode is equal to previously entered postcode it calls function showCity()
     * else calls function requestCity()
     */

    //--------Function onblurPc------------//
    /*
     * This function checks if flag setCity is set if it isn't it calls function that sends request (requestCity)
     *
     */

    //-------Function onChangeSelect--------//
    /*
     * Calls when one of selects in select postcode by city name form is changed
     * Args: evtWR, addSel
     * evtWr - gets wrapper of element on which event has occur
     * addSel - gets and inserts type of field on which event has occur.
     * For example:
     * addSel[0] = postcode
     * this._setOptions(this['sel_' + addSel[i] + '_pc']); => this._setOptions(this.'sel_postcode_pc');
     *
     *
     */

    init : function (form_id, validator_name, cityOffsetX, pcOffsetX)
    {
        this.postcode_cache = {};

        this.loader_city = this.getLoadWrapper(this.config.city.loader, "post", false);
        this.loader_city.addListener(this, "ondataload", "onCityLoad");

        this.loader_pc = this.getLoadWrapper(this.config.pc.loader, "post", false);
        this.loader_pc.addListener(this, "ondataload", "onPcLoad");

        this.loader_city.addListener(this, "ondataerror", "onLoadError");

        this.$w0.createStyle('.selected_city', 'display: block;');
        this.$w0.createStyle('#show_select_city', 'display: block;');

        this.foms_id = isDefined(form_id) ? form_id : this.config.form;
        this.cityOffsetX = isDefined(cityOffsetX) ? - cityOffsetX : this.config.city.offsetX;
        this.pcOffsetX = isDefined(pcOffsetX) ? - pcOffsetX : this.config.pc.offsetX;

        this.validators_name = isDefined(validator_name) ? validator_name : this.config.validator_name;

    },

    onready : function ()
    {
        var conf, dlr;
        conf = this.config;

        // Set common elements
        this.form = this.$(this.foms_id);
        
        if (!this.form || this.form.elm.nodeName.toLowerCase() != 'form') {
            this.isEnabled = false;
            return;
        }
        
        this.form.addListener(this, 'onsubmit', 'checkHidden');
        if (this.config.form && !isDefined(this.$w0.win, this.validators_name)) {
            this.validators_name = 'validation_registration_form';
        }
        this.$w0.win[this.validators_name].addListener(this, 'isNotValid', 'onFormError');
       
        //validation_registration.addListener(this, 'isValid', 'onFormValid');
        this.postcode_input = this.$(conf.postcode_input);
        this.id_postcode    = this.$(conf.id_postcode);
        this.city_name      = this.$(conf.city.city_name);

        // Set city elements
        this.container_city = this.$(conf.city.container_city);
        this.container_city.addListener(this, 'onclick', 'stopBubbling');

        this.$(conf.city.show_select_city).addListener(this, 'onclick', 'showSelectPc');

        this.select_city = this.$(conf.city.container_city + ' select');
        this.select_city.addListener(this, "onchange", "onChangeCity");

        this.city_name.addListener(this, 'onclick', 'onclickCity', true);

        dlr = this.getDelayer(this.config.pc.delay, 'onTimer')
        dlr.addStart(this.postcode_input, 'onkeyUp');
        dlr.setStartMethod('pressPcKey');
        this.postcode_input.addListener(this, "onblur", "onblurPc");

        // Set pc elements
        this.container_pc = this.$(conf.pc.container_pc);
        this.container_pc.addListener(this, 'onclick', 'stopBubbling');

        this.sel_region1_pc  = this.$(conf.pc.sel_region1);
        this.sel_region2_pc  = this.$(conf.pc.sel_region2);
        this.sel_city_pc     = this.$(conf.pc.sel_city);
        this.sel_postcode_pc = this.$(conf.pc.sel_postcode);
        this.row_postcode_pc = this.sel_postcode_pc.getParent();
        this.row_postcode_pc.hide();

        this.sel_region1_pc.addListener(this, 'onchange', 'onChangeSelect', ['region2', 'city', 'postcode']);
        this.sel_region2_pc.addListener(this, 'onchange', 'onChangeSelect', ['city', 'postcode']);
        this.sel_city_pc.addListener(this, 'onchange', 'onChangeSelect', ['postcode']);

        this.sel_postcode_pc.addListener(this, 'onchange', 'onPcSelect');
        this.sel_region1_pc.elm.selectedIndex = -1;

    },

    onload : function ()
    {
        if (this.isEnabled) {
            this.requestCity(false);
        }
    },

    // ======== Main event parsers ======= \\
    onFormError : function(err_array)
    {
        //propA(err_array);
    },

    pressPcKey : function(evtWr)
    {
        var pc = this._getPc();
        if (this.current_pc != pc || this.selected_pc == '' && (!isDefined(this.postcode_cache, pc) || this.postcode_cache[pc] == null)) {
            this._clearCity();
            this.selected_pc = '';
        }
    },

    onclickCity : function(evtWr, isSelect)
    {
        var pc = this._getPc();
        if(pc) {
            if (isDefined(this.postcode_cache, pc) && (this.postcode_cache[pc] == null || this._getDataLength(this.postcode_cache[pc]) < 2)) {
                return;
            }
            if (this.current_pc == pc) {
                this.showCity();
            } else {
                this.requestCity(true);
            }
        } else {
            this.showPc();
        }
    },

    onblurPc : function()
    {
        if (!this.setCity) {
            this.requestCity(true);
        }
    },

    onTimer : function()
    {
        this.requestCity(true);
    },

    onChangeCity : function()
    {
        var option = this._getCurOption('select_city');
        this._writeCity(option.text);
        this._setHiddenIdPc(option.value);
        this.setCity = true;
    },

    onChangeSelect : function(evtWr, addSel)
    {
        var id_city, i;
        for (i in addSel) {
            this._setOptions(this['sel_' + addSel[i] + '_pc']);
        }
        this.loader_pc.send({'type' : addSel[0], 'value' : evtWr.elmWr.elm.value});
        if (addSel[0] == 'postcode') {
            id_city = this._getCurOption('sel_city_pc').value;
            this.current_city_name = this._getCurOption('sel_city_pc').text;
            if (id_city != this.current_city_id) {
                this.current_city_id = id_city;
                this.city_name.write('');
            }
            this._writeCity(this.current_city_name);
        } else {
            this.row_postcode_pc.hide();
        }
    },

    onPcSelect : function(evtWr)
    {
        var option = this._getCurOption('sel_postcode_pc');
        this._setHiddenIdPc(option.value, option.text);
        this.current_pc = '';
        this.selected_pc = this._getCurOption('sel_postcode_pc').textContent;
        this.requestCity(false);
        this._writeCity(this.current_city_name);
        this.postcode_input.elm.focus();
    },

    showSelectPc : function(evtWr)
    {
        evtWr.stopBubbling();
        evtWr.eventDrop();
        this.showPc();
    },

    stopBubbling : function(evtWr)
    {
        evtWr.stopBubbling();
    },

    hideContainers : function()
    {
        //this.waiter_img.hide();
        this.container_city.hide();
        this.container_pc.hide();
        this.$w0.removeListener(this, 'onclick', 'hideContainers');
    },

    setBodyClick : function()
    {
        this.$w0.addListener(this, 'onclick', 'hideContainers');
    },

    checkHidden : function(evtWr)
    {
        var pc = this._getPc();
        if (this.id_postcode.elm.value == '' && pc != '' && this.postcode_cache[pc]) {
            evtWr.eventDrop();
            this._setCities(this.postcode_cache[pc]);
        }
        this.$(this.config.js_enabled).elm.value = 1;
    },



    // ======== Loader event parsers ======= \\
    onCityLoad : function(json, dom, txt)
    {
        this.postcode_cache[json.pc] = json.cities;
        this._setCities(json.cities);
    },

    onPcLoad : function(json, dom, txt)
    {
        if (json.type == 'postcode') {
            this.row_postcode_pc.setDisplay(this._getDataLength(json.data) > 1);
        }
        if (json.type != 'postcode' || this._getDataLength(json.data) > 1) {
            this._setOptions(this['sel_' + json.type + '_pc'], json.data);
        } else {
            var k = this._getFirstKey(json.data)
            this._setHiddenIdPc(k, json.data[k]);
            this.current_pc = '';
            this.selected_pc = json.data[k];
            this.requestCity(false);
        }
    },


    // ======== Global methods ======= \\
    showCity : function()
    {
        this.hideContainers();
        this.container_city.setAbsLeft(this.postcode_input.getAbsLeft() + this.cityOffsetX);
        this.container_city.setAbsTop(this.postcode_input.getAbsTop() + this.postcode_input.getHeight() + this.config.city.offsetY);
        this.container_city.show();
        //this.select_city.elm.focus(); // ?????
        this.setTimeout(500, this, "setBodyClick")
    },

    showPc : function()
    {
        this.hideContainers();
        this.container_pc.setAbsLeft(this.postcode_input.getAbsLeft() + this.pcOffsetX);
        this.container_pc.setAbsTop(this.postcode_input.getAbsTop() + this.config.pc.offsetY);
        //this.row_postcode_pc.setDisplay(this.setCity);
        this.container_pc.show();
        this.setTimeout(0, this, "setBodyClick")
    },

    /**
     * Request to server for list of cities
     */
    requestCity : function(clearPrev)
    {
        var pc = this._getPc();
        if (this.current_pc != pc) {
            if (clearPrev) {
                this._clearCity();
                this._setHiddenIdPc('');
            }
            this.current_pc = pc;
            if (pc != '') {
                if (!isDefined(this.postcode_cache, pc)) {
                    this.postcode_cache[pc] = null;
                    this.loader_city.send({'postal_code' : pc});
                } else if (this.postcode_cache[pc]){
                    this._setCities(this.postcode_cache[pc]);
                }
            }
        }
    },

    // ======== Internal methods ======== \\

    _setHiddenIdPc : function(pc_id, pc_val)
    {
        this.id_postcode.elm.value = pc_id;
        if (isDefined(pc_val)) {
            this.postcode_input.elm.value =  pc_val;
        }
        this.hideContainers();
    },

    _setCities : function(data)
    {
        var idPc = this.id_postcode.elm.value;
        if (data) {
            if (isDefined(data, idPc)) {
                this._setOptions(this.select_city, data, idPc);
                this._writeCity(data[idPc]);
            } else if (this._getDataLength(data) > 1) {
                this._setOptions(this.select_city, data);
                this.showCity();
            } else {
                idPc = this._getFirstKey(data);
                this._setHiddenIdPc(idPc);
                this._writeCity(data[idPc]);
            }
        } else if (idPc) {
            this._setHiddenIdPc('');
        }
    },

    _setOptions : function(selWr, data, selVal)
    {
        var select, attr, i;
        select = selWr.elm
        while (select.childNodes.length > 0) {
            select.removeChild(select.firstChild);
        }
        if (isDefined(data)) {
            for (i in data) {
                attr = {'value' : i};
                if (isDefined(selVal) && i == selVal) {
                    attr['selected'] = 'selected';
                }
                select.appendChild(this.$w0.makeElement('option', attr, data[i], false));
            }
            if (!isDefined(selVal)) {
                select.selectedIndex = -1;
            }
        }
    },

    _getPc : function()
    {
        if (this.postcode_input.elm.value == '') {
            return '';
        }
        var res = (new RegExp(this.config.reg_exp, "i")).exec(this.postcode_input.elm.value);
        return res ? res[1] : '';
    },

    _getDataLength : function(data)
    {
        if (!isObject(data)) {
            return null;
        }
        var k, i;
        k = 0;
        for (i in data) {
             k++;
        }
        return k;
    },

    _getFirstKey : function(data)
    {
        for (var k in data) {
            return k;
        }
        return null;
    },

    _getCurOption : function(name)
    {
        return this[name].elm.options[this[name].elm.selectedIndex];
    },

    _writeCity : function(name)
    {
        this.city_name.write (name);
        this.setCity = true;
    },

    _clearCity : function()
    {
        this.city_name.write('');
        this.setCity = false;
        this.current_city_id = null;
    },

    // ======== Config ======= \\
    config : {
        "form"           : "#registration",
        "validator_name" : "validation_registration",
        "reg_exp"        : "^\s*([A-Z]{1,2}[0-9R][0-9A-Z]?)(?:\W*(?:\d[ABD-HJLNP-UW-Z]{2}|.*))?\s*$", // "^\s*([A-Z]{1,2}[0-9R][0-9A-Z]?)(?:\W*\d[ABD-HJLNP-UW-Z]{2})?\s*$"

        "postcode_input" : "#postal_code",
        "id_postcode"    : "#id_postcode",
        "js_enabled"     : "#js_enabled",
        "city" : {
            "loader" : "/select_pc/get_regions.php",
            "show_select_city" : "#show_select_city",
            "container_city"   : "#container_city",
            "city_name"        : "#city_name",
            "offsetX"          : -114,
            "offsetY"          : 0
        },
        "pc" : {
            "loader" : "/select_pc/get_pc_data.php",
            "delay"          : 900,
            "container_pc"   : "#container_pc",
            "sel_region1"    : "#select_pc_region1",
            "sel_region2"    : "#select_pc_region2",
            "sel_city"       : "#select_pc_city",
            "sel_postcode"   : "#select_pc_postcode",
            "offsetX"          : -114,
            "offsetY"          : 0
        }
    }
});
