var JSPControls = {

/*
 * Constants
 */

    /*
     * Request parameter, notifying component of being called asynchronously.
     */
    ajaxflag : "jspcontrols.ajax.xhtml=true",

/*
 * Properties
 */

    /*
     * Behavioral rules for Ajax mode. To read more about setting events
     * to DOM elements see Behaviour.js file.
     */
    ajaxRules : {
        /*
         * Command link
         */
        '.jspcCommand a' : function(el){
            el.onclick = function(){
                return JSPControls.loadComponent(this);
                //alert ("Hi: .jspcCommand a");
                return false;
            }
        },
        'a.jspcCommand' : function(el){
            el.onclick = function(){
                return JSPControls.loadComponent(this);
                // alert ("Hi: a.jspcCommand");
                return false;
            }
        },

        /*
         * HTML form
         */
        'form.jspcCommand' : function(el){
            el.onsubmit = function(){
                return JSPControls.loadComponent(this);
                // alert ("Hi: form.jspcCommand");
                return false;
            }
        },
        '.jspcCommand form' : function(el){
            el.onsubmit = function(){
                return JSPControls.loadComponent(this);
                // alert ("Hi: form.jspcCommand");
                return false;
            }
        },

        /*
         * Ensure that the name of activated submit button is collected
         */
        'input.jspcCommand' : function(el){
            el.onclick = function(){
                if (this.form && this.type.toLowerCase() == 'submit') {
                    this.form.submitButtonName=this.name;
                }
                return true;
            }
        },
        '.jspcCommand input' : function(el){
            el.onclick = function(){
                if (this.form && this.type.toLowerCase() == 'submit') {
                    this.form.submitButtonName=this.name;
                }
                return true;
            }
        },

        'a.tigristabs' : function(el){
            el.onclick = function(){
                return JSPControls.loadComponent(this);
                // alert ("Hi: a.jspcCommand");
                return false;
            }
        },
        'a.yahootabs' : function(el){
            el.onclick = function(){
                return JSPControls.loadComponent(this);
                // alert ("Hi: a.jspcCommand");
                return false;
            }
        }

    },

    /*
     * The associative array that stores names of components that depend
     * on some activated component. For example:
     *     {
     *         'loginComponent.jsp' : ['loginStatusComponent.jsp'],
     *         'localeComponent.jsp' : ['menuComponent.jsp', 'loginComponent.jsp', 'loginStatusComponent.jsp']
     *     }
     * The above means, that after login component is modified, the login status
     * component must be reloaded to display updated user's status.
     * Also, when locale component is modified, then menu, login and login status
     * component must be reloaded to reflect language change.
     *
     * The dependency array must be registered for every page that contains dependent
     * components. For registration use JSPControls.registerDependencies() function.
     */
    dependencies : new Array,

    /*
     * Dependencies realized for activated element, contains subset of all
     * available depencies from "dependencies" property.
     */
    currentDependencies: new Array,

/*
 * Methods
 */

    /*
     * Prints string to "ajaxdebug" element if it is defined in the document.
     */
    debug : function(str) {
        if (str) {
            var debugDiv = document.getElementById("ajaxdebug");
            if (debugDiv != null) {
                debugDiv.innerHTML += str;
            }
        }
    },

    /*
     * Extracts data from HTML form and serializes it into human-readable string
     * or into query string.
     *
     * This function accepts either form id or the form object itself
     * using "this" keyword. Original code sample used form id, but this
     * proved unreliable in Ajax environment when the form is replaced as
     * text, not as XML. Apparently, DOM content is not refreshed. Therefore,
     * form sends stale field content. Therefore, sending "this" is preferred.
     *
     * History:
     *   2000-04-22 - original code by Martin Honnen
     *                http://www.faqts.com/knowledge_base/view.phtml/aid/2292
     *   2005-12-07 - Data from hidden and submit elements is collected as well.
     *   2005-12-22 - Only the submit element that was activated is collected.
     *   2006-03-10 - Renamed to avoid name clash with other libraries.
     *
     * @frm the form the data is extracted from. Accepts either form's id
     *      or the form object itself using "this" keyword.
     */
    formData : function (form) {
        /*
         * Encodes URL
         */
        this.urlEncode = function (string) {
            string = string.replace(/ /g, '+');
            return escape(string);
        };

        /*
         * Returns human-readable content of HTML form.
         */
        this.toString = function() {
            var r = '';
            for (var field in this.fields)
                r += field + ': ' + this.fields[field] + '\n';
            return r;
        };

        /*
         * Returns content of HTML form serialized into request query string.
         */
        this.toQueryString = function() {
            var r = '';
            for (var field in this.fields)
                if (typeof this.fields[field] != 'string')
                    for (var i = 0; i < this.fields[field].length; i++)
                        r += this.urlEncode(field) + '=' + this.urlEncode(this.fields[field][i]) + '&';
                    else
                        r += this.urlEncode(field) + '=' + this.urlEncode(this.fields[field]) + '&';
                    r = r.substring(0, r.length - 1);
            return r;
        }

        var fields = this.fields = new Object();
        var submitButtonProcessed = false;
        if (form.submitButtonName) {
            fields[form.submitButtonName] = "true";
            submitButtonProcessed = true;
        }
        for (var e = 0; e < form.elements.length; e++) {
            var field = form.elements[e];
            if (field.name) {
                if ((field.type.toLowerCase() == 'text'
                    || field.type.toLowerCase() == 'textarea'
                    || field.type.toLowerCase() == 'password'
                    || field.type.toLowerCase() == 'hidden'
                    || field.type.toLowerCase() == 'file')
                    && field.value)
                    fields[field.name] = field.value;
                else if ((field.type.toLowerCase() == 'checkbox'
                    || field.type.toLowerCase() == 'radio')
                    && field.checked)
                    fields[field.name] = field.value;
                else if (field.type.toLowerCase() == 'select-one'
                    && field.selectedIndex != -1)
                    fields[field.name] = field.options[field.selectedIndex].value;
                else if (field.type.toLowerCase() == 'select-multiple'
                    && field.selectedIndex != -1) {
                    fields[field.name] = new Array();
                    for (var i = 0; i < field.options.length; i++)
                        if (field.options[i].selected)
                            fields[field.name][fields[field.name].length] = field.options[i].value;
                        } else if (!submitButtonProcessed && field.type.toLowerCase() == 'submit' && field.name) {
                            fields[field.name] = "1";
                            submitButtonProcessed = true;
                }
            }
        }
    },


    /*
     * Initializes XMLHTTPRequest object.
     */
    getXMLHTTPRequest : function() {
        var xmlReq = null;
        if (window.XMLHttpRequest) xmlReq = new XMLHttpRequest();
        if (xmlReq == null && window.ActiveXObject) {
            xmlReq = new ActiveXObject("Msxml2.XMLHTTP");
            if (xmlReq == null) xmlReq = new ActiveXObject("Microsoft.XMLHTTP");
        }
        return xmlReq;
    },


    /*
     * Thread-safe asynchronous XMLHTTPRequest call
     * Original code by brockweaver, http://www.xml.com/cs/user/view/cs_msg/2815
     */
    sendrequest : function (target, params, callback, method){

        // Using Javascript inner functions allows local variables to retain
        // their values after the outer function has returned. This is useful
        // for thread safety, so reassigning the onreadystatechange
        // function doesn't stomp over earlier requests.
        function ajaxBindCallback(){
            if (ajaxRequest.readyState == 4) {
                if (ajaxRequest.status == 200) {
                    if (ajaxCallback){
                        ajaxCallback(ajaxRequest);
                    } else {
                        alert('no callback defined');
                    }
                } else {
                    alert("There was a problem retrieving the xml data:\n" +
                    ajaxRequest.status + ":\t" +
                    ajaxRequest.statusText + "\n" + ajaxRequest.responseText);
                }
            }
        }

        // Use local variables to hold request and callback
        // until the inner function is called
        var ajaxRequest = null;
        var ajaxCallback = callback;

        // Initialize Ajax request
        ajaxRequest = JSPControls.getXMLHTTPRequest();

        // If async request is not possible return true, so browser could
        // submit form synchronously.
        if (ajaxRequest == null) return true;

        if (params) {
            params += "&" + JSPControls.ajaxflag;
        } else {
            params = JSPControls.ajaxflag;
        }

        if (method == "get") {
            target += (target.indexOf("?") < 0 ? "?" : "&") + params;
            params = null;
        }

        // Prepare async request
        ajaxRequest.onreadystatechange = ajaxBindCallback;
        ajaxRequest.open(method, target, true);
        if (method == "post") {
            ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        }
        ajaxRequest.send(params);

        // Show full request that will be sent to component
        JSPControls.debug("Ajax request sent to: " + target + "<br/>");

        // On success return false to prevent submitting form in regular fashion.
        return false;
    },

    /*
     * Callback function that handles asynchronous response. If response contains
     * SPAN element with ID attribute defined, element's content is placed
     * inside a DIV with the same ID.
     *
     * Response is initially read as XML to be able to analyze it structure,
     * then it is insterted into page as plain HTML.
     *
     * Make sure that response has its MIME type set to "text/xml" otherwise
     * XMLHttpRequest.responseXML will return no data. Also make sure that
     * response content is valid XML: close all tags, URLEncode all URLs and
     * hide Javascript inside HTML comments.
     *
     * 2006-03-10 - Renamed to avoid name clash with other libraries.
     */
    jspcHandleResponse : function (req) {
        JSPControls.debug("Ajax response received" + "<br/>");

        // Get response as XML
        var doc = req.responseXML;

        // Obtain the outermost DIV element in the returned component view,
        // find an element with the same ID and replace with response data.
        var source = doc.getElementsByTagName( "span" )[0];
        var id  = source.getAttribute( "id" );
        var defPos = id.indexOf("_def", 0);
        if (defPos > 0) {
            id = id.substring(0, defPos);
        }

        // Update component fragment in-place
        var target = document.getElementById(id);
        if( target != null ) {
            JSPControls.debug("Target for id " + id + " found" + "<br/>");
            target.innerHTML = req.responseText;
            Behaviour.apply();
        }

        var nextCall = JSPControls.currentDependencies.pop();
        if (nextCall != null && nextCall != undefined) {
            JSPControls.debug("Next in queue: " + nextCall + "<br/>");
            JSPControls.sendrequest (nextCall, null, JSPControls.jspcHandleResponse, "get");
        }
    },







    /*
     * Registers component dependencies for every page that contains dependent
     * components. For details see "dependencies" property.
     */
    registerDependencies : function(ch) {
        JSPControls.dependencies = ch;
    },

    /*
     * Sends aynchronous request using GET method; the response will be returned
     * to jspcHandleResponse() function
     *
     * @url address along with query parameters where send the request to
     */
    loadComponent : function (el) {
        JSPControls.debug("<br/>");

        var url = null;
        var params = null;
        var method = 'post';

        if (el.href) {
            url = el.href;
        } else if (el.action) {
            if (el.method) method = el.method;
            url = el.action;
            var fd = new this.formData(el);
            if (fd) {
                params = fd.toQueryString();
            }
        } else {
            return false;
        }

        if (JSPControls.dependencies) {
            JSPControls.debug("There are dependants <br/>");
            for (selector in JSPControls.dependencies) {
                JSPControls.debug("Dependant: " + JSPControls.dependencies[selector] + " from " + selector + "<br/>");
                if (url.indexOf(selector) > -1) {
                    JSPControls.debug("Dependant found: " + JSPControls.dependencies[selector] + " <br/>");
                    JSPControls.currentDependencies = new Array();
                    var depArray = JSPControls.dependencies[selector];
                    if (depArray && depArray.length > 0) {
                        JSPControls.currentDependencies = new Array();
                        for (loop = 0; loop < depArray.length; loop++) {
                            JSPControls.currentDependencies[loop] = depArray[loop];
                        }
                    }
                }
            }
        }
        return JSPControls.sendrequest (url, params, JSPControls.jspcHandleResponse, method);
    },

    /*
     * Sets up behavioral rules for Ajax mode.
     */
    start : function() {
        // alert ("Hi: registered");
        Behaviour.register(JSPControls.ajaxRules);
    }
};


JSPControls.start();