/**
 * Class: carrerer
 * Creates an unic controller to add the logic of the
 *  * poblacioSuggest
 *  * carrererSuggest
 * in an unic control
 *
 */
function carrerer(options) {
    var defaults = {
        //provincia defautls
        /**
         * APIProperty: provinciaInputId
         * {<String>} Identifier of the selector of the "provincia"
         */
        provinciaInputId: "s_provincia",
        /**
         * APIProperty: provinciaIdSearch
         * {<Array>} Array of identifier defining the "provincias" with
         * AJAX search
         */
        provinciaIdSearch: ["9", "19", "29", "43" ],

        //poblacio defaults
        /**
         * APIProperty: poblacioInputId
         * {<String>} Identifier of the input of the "poblacio"
         */
        poblacioInputId: "s_poblacion",

        /**
         * APIProperty: poblacioResultsId
         * {<String>} Identifier of the div where the results of "poblacion"
         * are shown
         */
        poblacioResultsId: "s_poblacion_res",
        /**
         * APIProperty: poblacioUrl
         * {<String>} Url where the AJAX call is done.
         */
        poblacioUrl: "/carrerer/getPoblaciones",

        //carrerer defaults
        /**
         * APIProperty: carrererInputId
         * {<String>} Identifier of the input of the "carrer"
         */
        carrererInputId: "s_nombre_via",
        /**
         * APIProperty: carrererResultsId
         * {<String>} Identifier of the div where the results of "carrer"
         * are shown
         */
        carrererResultsId: "s_nombre_via_res",
        /**
         * APIProperty: carrererUrl
         * {<String>} Url where the AJAX call is done.
         */
        carrererUrl: "/carrerer/getCalles",


        /**
         * APIProperty: minCharsAjax
         * {<Integer>} Mininum number of characters that the input has to have
         * before the AJAX call is done.
         */
        minCharsAjax: 1,
        /**
         * APIProperty: waitKeyPressedTime
         * {<String>} Time, in miliseconds, between to calls could be done.
         */
        waitKeyPressedTime: "1000"

    }

    //extent the options
    this.options = $.extend(defaults, options);

    //create the poblacioSuggest
    this.pobSuggest = new poblacioSuggest(this.options);

    //create the carrererSuggest
    this.carSuggest = new carrererSuggest(this.options);

}


/**
 * Class: poblacioSuggest
 * Contains the logic to do the poblacio controller
 */
function poblacioSuggest(options) {

	//set defaults
	var defaults = {
            /**
             * APIProperty: provinciaInputId
             * {<String>} Identifier of the select of the "provincia"
             */
            provinciaInputId: "s_provincia",
            /**
             * APIProperty: poblacioInputId
             * {<String>} Identifier of the input of the "poblacio"
             */
            poblacioInputId: "s_poblacion",

            /**
             * APIProperty: poblacioResultsId
             * {<String>} Identifier of the div where the results are shown.
             */
            poblacioResultsId: "s_poblacion_res",

            /**
             * APIProperty: poblacioUrl
             * {<String>} Url where the AJAX call is done
             */
            poblacioUrl: "/carrerer/getPoblaciones",
            /**
             * APIProperty: minCharsAjax
             * {<Integer>} Mininum characters to done the AJAX call.
             */
            minCharsAjax: 1,
            /**
             * APIProperty: waitKeyPressedTime
             * {<String>} Identifier of the div where the results of "carrer"
             */
            waitKeyPressedTime: "1000",
            /**
             * APIProperty: provinciaIdSearch
             * {<Array>} Array of identifier defining the "provincias" with
             * AJAX search
             */
            provinciaIdSearch: ["9", "19", "29", "43" ]
	};

	this.freeze = 0;
	this.time;
        this.preAjax = "";

	//extend defaults
	this.options = $.extend(defaults, options);

        this.provincia = $("#"+this.options.provinciaInputId);
	this.input = $("#"+this.options.poblacioInputId);
	this.results = $("#"+this.options.poblacioResultsId);

        this.suggestList = new suggestList({inputId: this.options.poblacioInputId,listId:this.options.poblacioResultsId});

        /**
         * Event: keyup
         * Capture the keyup event. If the key pressed is not 13 (ENTER key),
         * check if the provinciia selected could make AJAX calls.
         * If th Ajax Call is done, it active the freeze option to prevent
         * multiple calls.
         *
         * Parameters:
         * caller - {<poblacioSuggest>} object
         * event - {<Event>} event that active the call
         */
	this.input.bind("keyup",{caller:this},function(event) {
            if (event.keyCode != 13) {

                if (jQuery.inArray(event.data.caller.provincia.val(),event.data.caller.options.provinciaIdSearch) != -1) {
                    if (event.data.caller.freeze == 0) {
                        var caller = event.data.caller;

                        clearTimeout(caller.time);
                        caller.time = setTimeout(function(){caller.keyPressed();},caller.waitKeyPressedTime);
                        caller.freeze = 1;
                    }
                }
            }

	});

        /**
         * Event: change
         * When the input value is change, it triggers the event clean,
         * for clean other values dependent of this input.
         *
         * Parameters:
         * caller - {<poblacioSuggest>} object
         * event - {<Event>} event that active the call
         */
	this.input.bind("change",{caller:this},function(event) {
            event.data.caller.preAjax = $(this).val();
            if (typeof(caller) != "undefined") {
                    caller.input.trigger("clean");
                    event.data.caller.preAjax = $(this).val();
            }
	});


        /**
         * Method: keyPressed
         * Makes the AJAX call with the needed params.
         * Before the AJAX call it checks if the values is different of the
         * last AJAX call and if the length of the values to send is greater
         * than the minCharsAjax defined.
         *
         * Parameters:
         */
	this.keyPressed = function() {
            //var caller = event.data.caller;


            if (this.preAjax != this.input.val()) {
                //if the content of the input is bigger than 2, make the AJAX call
                if (this.input.val().length >= this.options.minCharsAjax) {
                    ajaxCall(this.options.poblacioUrl,{"provincia":this.provincia.val(),"poblacio":this.input.val()},this.recieveAjaxResults,"json",this);
                    this.preAjax = this.input.val();

                }

            }
            this.freeze = 0;

	}
        /**
         * Method: recieveAjaxResults
         * Recieve the results from the AJAX call. And call the fill function
         * of the suggestList.
         *
         * Parameters:
         * pobs - {<Array>} Array of "poblacions" that are the results of the
         * AJAX call.
         * scope - {<Object>} caller of the AJAX functions
         * params - {<Object>} params passed to the AJAX call.
         */
	this.recieveAjaxResults = function(pobs,scope,params) {
            scope.suggestList.fill(pobs);
	}


};

/**
 * Class: carrererSuggest
 * Contains the logic to do the carrerer controller
 */
function carrererSuggest(options) {

	//set defaults
	var defaults = {
            /**
             * APIProperty: provinciaInputId
             * {<String>} Identifier of the select of the "provincia"
             */
            provinciaInputId: "s_provincia",
            /**
             * APIProperty: poblacioInputId
             * {<String>} Identifier of the input of the "poblacio"
             */
            poblacioInputId: "s_poblacion",
            /**
             * APIProperty: carrererInputId
             * {<String>} Identifier of the input of the "carrerer"
             */
            carrererInputId: "s_nombre_via",
            /**
             * APIProperty: carrererResultsId
             * {<String>} Identifier of the div where the results are shown
             */
            carrererResultsId: "s_nombre_via_res",
            /**
             * APIProperty: carrererUrl
             * {<String>} Url where the AJAX call is done.
             */
            carrererUrl: "/carrerer/getCalles",
            /**
             * APIProperty: minCharsAjax
             * {<Integer>} Mininum characters to done the AJAX call.
             */
            minCharsAjax: 1,
            /**
             * APIProperty: waitKeyPressedTime
             * {<String>} Identifier of the div where the results of "carrer"
             */
            waitKeyPressedTime: "1000",
            /**
             * APIProperty: provinciaIdSearch
             * {<Array>} Array of identifier defining the "provincias" with
             * AJAX search
             */
            provinciaIdSearch: ["9", "19", "29", "43" ]

	};

	this.freeze = 0;
	this.time;

        this.preAjax = "";


	//extend defaults
	this.options = $.extend(defaults, options);

        this.provincia = $("#"+this.options.provinciaInputId);
	this.pobInput = $("#"+this.options.poblacioInputId);
	this.input = $("#"+this.options.carrererInputId);
	this.results = $("#"+this.options.carrererResultsId);

        this.suggestList = new suggestList({inputId: this.options.carrererInputId,listId:this.options.carrererResultsId});


	//add the clean event
	this.pobInput.bind("clean",{caller:this},function(event) {
		//event.handler.data.caller.clearData();
		//event.handler.data.caller.hideResults();
	});

        /**
         * Event: keyup
         * Capture the keyup event. If the key pressed is not 13 (ENTER key),
         * check if the provinciia selected could make AJAX calls.
         * If th Ajax Call is done, it active the freeze option to prevent
         * multiple calls.
         *
         * Parameters:
         * caller - {<poblacioSuggest>} object
         * event - {<Event>} event that active the call
         */
	this.input.bind("keyup",{caller:this},function(event) {
            if (event.keyCode != 13) {

                if (jQuery.inArray(event.data.caller.provincia.val(),event.data.caller.options.provinciaIdSearch) != -1) {
                            if (event.data.caller.freeze == 0) {
                                    var caller = event.data.caller;

                                    clearTimeout(caller.time);
                                    caller.time = setTimeout(function(){caller.keyPressed();},caller.waitKeyPressedTime);
                                    caller.freeze = 1;
                            }
                }
            }



	});

        /**
         * Method: keyPressed
         * Makes the AJAX call with the needed params.
         * Before the AJAX call it checks if the values is different of the
         * last AJAX call and if the length of the values to send is greater
         * than the minCharsAjax defined.
         *
         * Parameters:
         */
	this.keyPressed = function() {

            if (this.input.val() != this.preAjax) {
                //if the content of the input is bigger than 2, make the AJAX call
                if (this.input.val().length >= this.options.minCharsAjax) {
                    ajaxCall(this.options.carrererUrl,{"via":this.input.val(),"poblacio":this.pobInput.val()},this.recieveAjaxResults,"json",this);
                    this.preAjax = this.input.val();
                }

            }
            this.freeze = 0;
	}

        /**
         * Event: change
         * When the input value is change, it triggers the event clean,
         * for clean other values dependent of this input.
         *
         * Parameters:
         * caller - {<poblacioSuggest>} object
         * event - {<Event>} event that active the call
         */
	this.input.bind("change",{caller:this},function(event) {
            event.data.caller.preAjax = $(this).val();
            if (typeof(caller) != "undefined") {
                    caller.input.trigger("clean");
                    event.data.caller.preAjax = $(this).val();
            }
	});

        /**
         * Method: recieveAjaxResults
         * Recieve the results from the AJAX call. And call the fill function
         * of the suggestList.
         *
         * Parameters:
         * pobs - {<Array>} Array of "poblacions" that are the results of the
         * AJAX call.
         * scope - {<Object>} caller of the AJAX functions
         * params - {<Object>} params passed to the AJAX call.
         */
	this.recieveAjaxResults = function(vies,scope,params) {
            scope.suggestList.fill(vies);

	};



}


/**
 * Class: suggestList
 * Contains the logic to do the suggest List
 */
function suggestList(options) {

    //define the keys to listen
    var KEY = {
        UP: 38,
        DOWN: 40,
        DEL: 46,
        TAB: 9,
        RETURN: 13,
        ESC: 27,
        COMMA: 188,
        PAGEUP: 33,
        PAGEDOWN: 34,
        BACKSPACE: 8
    };

    //set defaults
    var defaults = {
        /**
         * APIProperty: inputId
         * {<String>} Identifier of the input where the user write the values
         * which uses the AJAX call.
         */
        inputId: "s_provincia",
        /**
         * APIProperty: listId
         * {<String>} Identifier of the list where the results are shown
         */
        listId: "s_poblacio_res"
    };

    //extend defaults
    this.options = $.extend(defaults, options);

    var hasFocus = 0;
    var blockSubmit;
    var pos = 0;

    //get the DOM object for the inputId
    this.input = $("#"+this.options.inputId);

    //Create the elements of the suggestList
    //Create the div where the list of results is shown.
    this.input.parent().createAppend(
        'div',{'id':this.options.listId+"_div",'class':'suggestDiv'},''
    );
    this.listDiv = $("#"+this.options.listId+"_div");

    //Create the list where the results are shown.
    this.listDiv.createAppend(
        'ul',{'id':this.options.listId},''
    );
    this.list = $("#"+this.options.listId);

    this.focus = false;

    // prevent form submit in opera when selecting with return key
    $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
        return false;
    });


    /**
     * Method: select
     * Select the element of the list given in the param and add the className
     * to the DOM Object. Also update the value of the variable which contains
     * the value of the element selected.
     *
     * Parameters:
     * pos - {<Integer>} Position of the object that has to be selected
     */
    this.select = function(pos) {
        var selectLi = $("#"+this.options.listId+" li:eq("+pos+")")
        selectLi.addClass("select");
        this.pos = pos;
    };

    /**
     * Method: prev
     * If there are previous items in the list, modify the value of the position
     * of the selected item on the list, and call the function <select> to apply
     * its logic
     *
     * Parameters:
     */
    this.prev = function()  {
        var selectLi = $("#"+this.options.listId+" li:eq("+this.pos+")")
        selectLi.removeClass("select");

        if (this.pos > 0) this.pos--;
        this.select(this.pos);
    };

    /**
     * Method: next
     * If there are more items in the list, modify the value of the position
     * of the selected item on the list, and call the function <select> to apply
     * its logic
     *
     * Parameters:
     */
    this.next = function()  {
        var selectLi = $("#"+this.options.listId+" li:eq("+this.pos+")")
        selectLi.removeClass("select");

        var posTmp = this.pos+1;
        if ($("#"+this.options.listId+" li:eq("+posTmp+")").length > 0) {
            this.pos = posTmp;
        }
        this.select(this.pos);

    };

    /**
     * Method: visible
     * Makes the div that contains the list visible. It put the element just
     * under the input element.
     *
     * Parameters:
     */
    this.visible = function()  {
        this.listDiv.css("display","inline");
        this.listDiv.css("top",5+parseInt(this.input.position().top)+parseInt(this.input.outerHeight()));
        this.listDiv.css("left",parseInt(this.input.position().left));
        this.listDiv.css("width",parseInt(this.input.innerWidth()));
    };

    /**
     * Method: isVisible
     * Check if the div containin the result list is visible or not.
     *
     * Parameters:
     *
     * Returns:
     * {<Boolean>} True if the element if visible, else false.
     */
    this.isVisible = function() {
        return (this.listDiv.css("display") == "inline");
    }


    /**
     * Method: returnParent
     * Put the value of the selected item in the list in the input
     *
     */
    this.returnParent = function() {
        var selectLi = $("#"+this.options.listId+" li.select");
        if (selectLi.length > 0) {
            this.input.val(selectLi.html());
        }
        //this.hide();
    }

    /**
     * Method: hide
     * Hides the list of results
     */
    this.hide = function() {
        this.listDiv.css("display","none");
    };

    /**
     * Method: fills
     * Put the results of the AJAX call in the list creating the objects on
     * the fly.
     * Also adds the mouseover event foreach of the items in the list.
     * This event add the class select where the mouse is over and update the
     * value of the global position of the list.
     *
     * Parameters:
     *
     * Returns:
     * {<Boolean>} True if the element if visible, else false.
     */
    this.fill = function(objs) {
        if ($("#"+this.options.listId).length == 0) {
            return false;
        }


        this.list.empty();
        var cN = "odd";
        for (var i = 0; i < objs.length; i++) {
            if ( (i % 2) == 0) { cN = "even" } else { cN = "odd"};
            this.list.createAppend(
                'li',{'id':i,'class':cN},objs[i]
            );
        }

        //add the hover event
        $("#"+this.options.listId+" li").bind("mouseover", {caller:this},function(event){
            var children = $("#"+event.data.caller.options.listId+" li");
            children.removeClass("select");
            $(this).addClass("select");
            event.data.caller.pos = $(this).attr("id");
        });


        //this.list.trigger("focus");
        //this.list.focus();
        this.select(0);
        this.visible();

    }



    /**
     * Event: keydown
     * Capture the keydown event.
     * Depending on the key pressed, the event makes differnt logic.
     * The keys supported are: UP, DOWN, RETURN, TAB, ESC
     * In Opera the event has to be declared as keypress
     *
     * Parameters:
     * caller - {<suggestList>} object
     * event - {<Event>} event that active the call
     */
    // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
    this.input.bind(($.browser.opera ? "keypress" : "keydown"), {caller:this},function(event) {
        // a keypress means the input has focus
        // avoids issue where input had focus before the autocomplete was applied

        var caller = event.data.caller;
        caller.focus = true;
        // track last key pressed
        lastKeyPressCode = event.keyCode;
        switch(event.keyCode) {
            case KEY.UP:
                    event.preventDefault();
                    if ( caller.isVisible() ) {
                        caller.prev();
                    } else {
                        caller.select(0);
                    }
                    break;

            case KEY.DOWN:
                    event.preventDefault();
                    if ( caller.isVisible() ) {
                            caller.next();
                    } else {
                            caller.select(0);
                    }
                    break;

            case KEY.RETURN:
                event.preventDefault();
                caller.returnParent();
                return false;
                break;

            case KEY.TAB:
                caller.returnParent();
                return true;
                break;
            case KEY.ESC:
                caller.hide();
                break;

            default:
                break;
        }
    });

    /**
     * Event: blur
     * When the input lost its focus, the event make that the input get the
     * selected value of the list and hide the list.
     *
     * Parameters:
     * caller - {<suggestList>} object
     * event - {<Event>} event that active the call
     */
    this.input.bind("blur",{caller:this},function(event) {
        var caller = event.data.caller;
        caller.returnParent();
        caller.focus = false;
        caller.hide();
    });





}
