/**
 * 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: 2,
        /**
         * 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: 2,
        /**
         * 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: 2,
        /**
         * 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();
    });

}


