/*
 * Lightcast - A Complete MVC/PHP/XSLT based Framework
 * Copyright (C) 2005-2008 Nimasystems Ltd
 *
 * This program is NOT free software; you cannot redistribute and/or modify
 * it's sources under any circumstances without the explicit knowledge and
 * agreement of the rightful owner of the software - Nimasystems Ltd.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the LICENSE.txt file for more information.
 *
 * You should have received a copy of LICENSE.txt file along with this
 * program; if not, write to:
 * NIMASYSTEMS LTD
 * Plovdiv, Bulgaria
 * ZIP Code: 4000
 * Address: 17 "Tcanko Diustabanov" Str., 2nd Floor
 * General E-Mail: info@nimasystems.com
 */

/*
 * AJAX RPC Communicator
 * @package plugins
 * @subpackage ajax_rpc
 * @author Nimasystems Ltd <support@nimasystems.com>
 * @version $Revision: 1 $
 */

/*
 * Parser Object
 */
if (typeof DOMParser == "undefined") {
    DOMParser = function() {}
    DOMParser.prototype.parseFromString = function(str, contentType) {
        if (typeof(ActiveXObject) != 'undefined') {

            var xmldata = new ActiveXObject('MSXML2.DomDocument');
            xmldata.async = false;
            xmldata.loadXML(str);
            return xmldata;
        } else if (typeof(XMLHttpRequest) != 'undefined') {
            var xmldata = new XMLHttpRequest;
            if (!contentType) {
                contentType = 'application/xml';
            }
            xmldata.open('GET', 'data:' + contentType + ';charset=utf-8,' + encodeURIComponent(str), false);
            if (xmldata.overrideMimeType) {
                xmldata.overrideMimeType(contentType);
            }
            xmldata.send(null);
            return xmldata.responseXML;
        }
    }
}

/*
 * Communication Utilities
 */
var Utils = {

    fillSelect: function(items, html_obj) {
        $e(html_obj).length = 0;

        if (items.length > 0) {
            for (i = 0; i < items.length; i++) {

                var elem = items[i];
                var id = elem.attributes.getNamedItem("id").nodeValue;
                var name = elem.childNodes[0].nodeValue;

                $e(html_obj)[i] = new Option(name, id, (i == 0 ? true: false));

            }
        }

    }

}

/*
 * AJAX Communicator / Validator
 */
var ajaxRPC = {
    __form_object: new Object,
    __forms_data: new Array(),
    __loading_message: '<span class="loading">loading....</span>',
    __message_timeout: 2000,
    __message_fadeopacity: 90,
    __message_hideform: 0,
    __redirect: 1,
    __ajaxRPCLoaded: 0,
    handler_uri: '',

    /*
     * Encode special characters
     */
    htmlspecialchars: function(encodedHtml) {
        encodedHtml = escape(encodedHtml);
        encodedHtml = encodedHtml.replace(/\//g, "%2F");
        encodedHtml = encodedHtml.replace(/\?/g, "%3F");
        encodedHtml = encodedHtml.replace(/=/g, "%3D");
        encodedHtml = encodedHtml.replace(/&/g, "%26");
        encodedHtml = encodedHtml.replace(/@/g, "%40");

        return encodedHtml;
    },

    /*
     * Submit a form
     */

    formSubmit: function(name) {
    	var obj = eval("document."+name);

    	var onsubmit = obj.onsubmit();
        if (onsubmit) {
    		obj.submit();
    	}
    },

    /*
     * Find elements by their tag name
     */
    getElementsByTagNames: function(list, obj) {
        if (!obj) var obj = document;
        var tagNames = list.split(',');
        var resultArray = new Array();
        for (var i = 0; i < tagNames.length; i++) {
            var tags = obj.getElementsByTagName(tagNames[i]);
            for (var j = 0; j < tags.length; j++) {
                resultArray.push(tags[j]);
            }
        }
        var testNode = resultArray[0];
        if (testNode.sourceIndex) {
            resultArray.sort(function(a, b) {
                return a.sourceIndex - b.sourceIndex;
            });
        } else if (testNode.compareDocumentPosition) {
            resultArray.sort(function(a, b) {
                return 3 - (a.compareDocumentPosition(b) & 6);
            });
        }
        return resultArray;
    },

    /*
     * Obtain an array keys
     */
    array_keys: function(input, search_value, strict) {
        var tmp_arr = new Array(),
        strict = !!strict,
        include = true,
        cnt = 0;

        for (key in input) {
            include = true;
            if (search_value != undefined) {
                if (strict && input[key] !== search_value) {
                    include = false;
                } else if (input[key] != search_value) {
                    include = false;
                }
            }

            if (include) {
                tmp_arr[cnt] = key;
                cnt++;
            }
        }

        return tmp_arr;
    },

    /*
     * Search for value in array
     */
    inArray: function(needle, haystack, strict) {

        var found = false,
        key,
        strict = !!strict;

        for (key in haystack) {
            if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle)) {
                found = true;
                break;
            }
        }

        return found;
    },

    /*
     * Display a fading image
     */
    eventMessageFade: function(message_id, opac, dont_remove) {
        var passed = parseInt(opac);
        var newOpac = parseInt(passed + 10);
        if (newOpac < ajaxRPC.__message_fadeopacity) {
            $e(message_id).style.opacity = '.' + newOpac;
            $e(message_id).style.filter = "alpha(opacity:" + newOpac + ")";
            opacityID = window.setTimeout("ajaxRPC.eventMessageFade('" + message_id + "', '" + newOpac + "')", 20);
        } else {
            if ($e(message_id) != undefined) {
                if (!parseInt(ajaxRPC.__message_hideform)) {

                    removeID = window.setTimeout("ajaxRPC.eventMessageRemove('" + message_id + "', " + ajaxRPC.__message_fadeopacity + ")", ajaxRPC.__message_timeout);
                } else {
                    $e(message_id).nextSibling.style.visibility = 'hidden';
                }
            }
        }
    },

    /*
     * Remove the fading image
     */
    eventMessageRemove: function(message_id, opac) {
        var passed = parseInt(opac);
        var newOpac = parseInt(passed - 10);
        if (newOpac > 0) {
            $e(message_id).style.opacity = '.' + newOpac;
            $e(message_id).style.filter = "alpha(opacity:" + newOpac + ")";
            opacityID = window.setTimeout("ajaxRPC.eventMessageRemove('" + message_id + "', '" + newOpac + "')", 20);
        } else {
            $e(message_id).parentNode.removeChild($e(message_id));
            ajaxRPC.__redirect = 1;
        }
    },

    /*
     * JS Evaluation
     */
    execScript: function(script) {
        if (script) {
            // alert(script);
            var execute = function() {
                eval(script);
            }
            execute.onerror = alert;
            execute();

        }
    },

    /*
     * Browser redirect
     */
    redirectURL: function(url) {

        if (!ajaxRPC.__redirect) {
            setTimeout("ajaxRPC.redirectURL('" + url + "')", 10);
            return false;
        }
        if (url) {
            location.href = url;
        }
    },

    /*
     * Form validation event message
     */
    showEventMessage: function(form_obj, formMessage, dont_remove) {
        if (form_obj != undefined && formMessage.length) {
            var message_id = "eventmsg_" + form_obj.getAttribute('name');
            if ($e(message_id) == undefined) {

                var msgObject = document.createElement('div');
                msgObject.innerHTML = formMessage;
                msgObject.className = 'eventFormRequired';
                msgObject.style.position = 'absolute';
                msgObject.style.width = form_obj.offsetWidth + "px";
                msgObject.style.height = form_obj.offsetHeight + "px";
                msgObject.style.backgroundColor = '#ffffff';
                msgObject.style.opacity = '.0';
                msgObject.style.filter = "alpha(opacity:0)";
                msgObject.style.zIndex = 999;
                msgObject.setAttribute("id", message_id);
                form_obj.parentNode.insertBefore(msgObject, form_obj);
                ajaxRPC.eventMessageFade(message_id, 10, dont_remove);
            }
        }
    },

    /*
     * Get DOM representation of an object
     */
    getElementDomObj: function(obj, element_id, field) {
        if (obj[element_id] != undefined) {

            if (obj[element_id].getElementsByTagName(field)[0].childNodes.length) {
                return obj[element_id].getElementsByTagName(field)[0].firstChild.nodeValue;
            }
        }
    },

    /*
     * Form processing
     * Field validation
     */
    validateFields: function(form_obj, xmlDoc) {

        formname = form_obj.getAttribute('name');

        var globalError = 0;

        var interator = (new DOMParser()).parseFromString(xmlDoc, "text/xml");

        // GET METADATA
        var metadata = interator.getElementsByTagName('metadata');
        if (this.getElementDomObj(metadata, 0, 'globalmessage')) var globalMessage = this.getElementDomObj(metadata, 0, 'globalmessage');
        else var globalMessage = "";
        if (this.getElementDomObj(metadata, 0, 'result')) var globalResult = parseInt(this.getElementDomObj(metadata, 0, 'result'));
        else var globalResult = "";
        if (this.getElementDomObj(metadata, 0, 'javascriptfunc')) var globalScript = this.getElementDomObj(metadata, 0, 'javascriptfunc');
        else var globalScript = "";
        if (this.getElementDomObj(metadata, 0, 'redirecturl')) var globalRedirect = this.getElementDomObj(metadata, 0, 'redirecturl');
        else var globalRedirect = "";
        if (this.getElementDomObj(metadata, 0, 'exectimeout')) var globalTimeout = this.getElementDomObj(metadata, 0, 'exectimeout');
        else var globalTimeout = "";
        if (this.getElementDomObj(metadata, 0, 'fadeopacity')) var globalFadeOpacity = this.getElementDomObj(metadata, 0, 'fadeopacity');
        else var globalFadeOpacity = "";
        if (this.getElementDomObj(metadata, 0, 'hideform')) var globalHideForm = this.getElementDomObj(metadata, 0, 'hideform');
        else var globalHideForm = "";

        if (globalTimeout.length) ajaxRPC.__message_timeout = globalTimeout * 1000;
        if (globalFadeOpacity.length) ajaxRPC.__message_fadeopacity = globalFadeOpacity
        if (globalHideForm.length) ajaxRPC.__message_hideform = globalHideForm

        // GET FIELDS
        var elements = new Array();

        var fields_root = interator.getElementsByTagName('field');
        if ((!fields_root.length) && (!globalScript) && (!globalRedirect)) {
            globalError++;
        }
        for (i = 0; i < fields_root.length; i++) {
            var field_name = fields_root[i].getElementsByTagName("name")[0].firstChild.nodeValue;
            if (this.getElementDomObj(fields_root, i, 'msg')) var field_msg = this.getElementDomObj(fields_root, i, 'msg');
            else var field_msg = '';
            if (this.getElementDomObj(fields_root, i, 'value')) var field_value = this.getElementDomObj(fields_root, i, 'value');
            else var field_value = '';

            elements[field_name] = new Array();
            elements[field_name][0] = field_msg;
            elements[field_name][1] = field_value;
        }

        // SHOW ERROR LOG IF HAVE ERROR
        if (globalError) {
            ajaxRPC.__message_hideform = 1;
            ajaxRPC.showEventMessage(form_obj, (xmlDoc));
            return false;
        }
        var elementsNames = ajaxRPC.array_keys(elements);
        var inputs = ajaxRPC.getElementsByTagNames('input,select,textarea', form_obj);

        var error = 0;
        for (i = 0; i < inputs.length; i++) {

            var input_name = inputs[i].getAttribute('name');
            if (ajaxRPC.inArray(input_name, elementsNames)) {
                // set field value
                inputs[i].value = elements[input_name][1];

                var requiredMsg_id = "req_" + input_name + "_" + formname + "_" + i
                if (elements[input_name][0].length) {
                    inputs[i].style.backgroundColor = "#f0f0f0";
                    if ($e(requiredMsg_id) == undefined) {
                        var requiredMsg = document.createElement('div');
                        requiredMsg.innerHTML = elements[input_name][0];
                        requiredMsg.setAttribute("id", requiredMsg_id);
                        requiredMsg.className = "requiredMsg";
                        inputs[i].parentNode.insertBefore(requiredMsg, inputs[i].nextSibling);
                    } else {
                        $e(requiredMsg_id).innerHTML = elements[input_name][0];
                    }
                    error++;

                } else {
                    inputs[i].style.backgroundColor = "";
                    if ($e(requiredMsg_id) != undefined) {
                        inputs[i].parentNode.removeChild($e(requiredMsg_id));
                    }
                }

            }
            // enable submit buttons
            if (inputs[i].getAttribute('type') == 'submit') inputs[i].disabled = false;
        }

        if (globalResult) {
            if (globalMessage.length) {
                ajaxRPC.showEventMessage(form_obj, globalMessage);
            }
            if (globalScript.length) {
                ajaxRPC.execScript(globalScript);
            }
        } else {
            if (globalMessage.length) {
                ajaxRPC.__redirect = 0;
                ajaxRPC.showEventMessage(form_obj, globalMessage);
            }
            if (globalScript.length) {
                ajaxRPC.execScript(globalScript);
            }
            if (globalRedirect.length) {
                ajaxRPC.redirectURL(globalRedirect);
                globalResult = 1;
            }
        }

        if (globalResult || error) {
            return false;
        } else {
            ajaxRPC.showEventMessage(form_obj, new Array(ajaxRPC.__loading_message));
            form_obj.submit();
        }

    },

    /*
     * XMLHTTPREQUEST Initialization
     */
    createAjaxObject: function() {
        var http_request = false;

        try {
            http_request = new XMLHttpRequest;
            if (http_request.overrideMimeType) {
                http_request.overrideMimeType('text/xml');
            }

        } catch(e) {
            var msxml = ['MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
            for (var i = 0, len = msxml.length; i < len; ++i) {
                try {
                    http_request = new ActiveXObject(msxml[i]);

                    break;
                } catch(e) {}
            }
        }

        if (!http_request) {
            return false;
        }
        return http_request;
    },

    /*
     * Display a form overlay mask
     */
    showOverlay: function() {
        if ($e('overlay') == undefined) {
            var overlay = document.createElement('div');
            overlay.setAttribute('id', 'overlay');
            overlay.className = 'overlay';
            document.body.appendChild(overlay);
        }

    },

    /*
     * Hide the form overlay mask
     */
    hideOverlay: function() {
        if ($e('overlay') != undefined) {
            $e('overlay').parentNode.removeChild(document.getElementById('overlay'))
        }

    },

    /*
     * Capsulate a request form (for rpc and validation)
     */
    formRequest: function(form_obj) {
        this.showOverlay();
        var parameters = ajaxRPC.getFormParams(form_obj);

        var http_request = ajaxRPC.createAjaxObject();

        ajaxRPC.__form_object = form_obj;

        http_request.onreadystatechange = function() {
            if (http_request.readyState == 4) {
                if (http_request.status == 200) {

                    result = http_request.responseText;

                    debugmessage = (new DOMParser()).parseFromString(result, "text/xml");
                    debugmessage1 = debugmessage.getElementsByTagName('metadata');
                    debugmessage2 = ajaxRPC.getElementDomObj(debugmessage1, 0, 'debug');

                    if (debugmessage2) {
                        $e('debug').innerHTML = '<br /><div style="border: 1px solid gray; padding: 3px;">' + debugmessage2 + '</div>';
                    }

                    // ################
                    var browser = navigator.appName.toLowerCase();
                    var rawresult = debugmessage.getElementsByTagName('rawresult');

                    if (rawresult.length == 1) {
                        if (browser == 'microsoft internet explorer') {
                            var raw_dom_obj = rawresult[0].firstChild;
                        } else {
                            var raw_dom_obj = rawresult[0].childNodes[1];
                        }

                        var func = raw_dom_obj.nodeName;
                        var html_obj = raw_dom_obj.attributes.getNamedItem("id").nodeValue;

                        switch (func) {
                        case 'fillSelect':

                            var items = (raw_dom_obj.getElementsByTagName('item'));

                            Utils.fillSelect(items, html_obj);

                            break;
                        default:

                            break;

                        }

                    }

                    ajaxRPC.validateFields(ajaxRPC.__form_object, result);
                    ajaxRPC.hideOverlay();
                } else {
                    ajaxRPC.hideOverlay();
                    if ($e('showdebug')) alert('There was a problem with the request.');
                    else return;
                }

            }
        }

        http_request.open('POST', this.handler_uri, true);
        http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        http_request.setRequestHeader("Content-Length", parameters.length);
        http_request.setRequestHeader("Connection", "close");
        http_request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        http_request.setRequestHeader("CacheControl", "no-cache");
        http_request.setRequestHeader("Pragma", "no-cache");
        http_request.setRequestHeader("Expires", -1);
        http_request.send(parameters);
        return false;
    },

    /*
     * Initialize communicator hidden form
     */
    init: function(handler_uri, current_controller) {
        ajaxRPC.__form_object = new Object();

        ajaxRPC.handler_uri = handler_uri;

        var html_forms = document.getElementsByTagName('form');

        for (f = 0; f < html_forms.length; f++) {
            var class_name = html_forms[f].className;
            if (class_name != undefined) {
                if (class_name.indexOf("req") != -1) {

                    html_forms[f].onsubmit = function() {
                        ajaxRPC.formRequest(this);
                    }
                }
            }
        }

        // write rpc form
        ajaxRPC.__initAJAXRPC_Form();

        // write flash layer
        document.write('<div id="flash_message"></div>');
    },

    /*
     * Initialize form fields
     */
    setFormFieldName: function(form_name, field, value) {

        if (ajaxRPC.__forms_data[form_name] == undefined) {
            ajaxRPC.__forms_data[form_name] = new Array();
        }
        ajaxRPC.__forms_data[form_name][field] = value;
    },

    /*
     * Find out objects in a form
     */
    getFormParams: function(obj) {
        var formname = obj.getAttribute('name');
        var inputs = ajaxRPC.getElementsByTagNames('input,select,textarea', obj);

        var params = new Array();
        var params_strings = new Array();
        for (i = 0; i < inputs.length; i++) {

            if (inputs[i].getAttribute('type') == 'checkbox') {
                if (!inputs[i].checked) // inputs[i].value = 0; else
                // inputs[i].value=1;
                {
                    continue;
                }
            }
            if (inputs[i].getAttribute('type') == 'radio') {
                if (!inputs[i].checked) continue;
            }

            param_key = inputs[i].getAttribute('name');

            if (inputs[i].nodeName.toLowerCase() == 'select') {

                if (inputs[i].multiple) {
                    var tmp_val = new Array();
                    for (k = 0; k < inputs[i].options.length; k++) {
                        if (inputs[i].options[k].selected == true) {
                            tmp_val[tmp_val.length] = inputs[i].options[k].value
                        }
                    }
                    param_val = tmp_val.join(',');

                } else {
                    if (inputs[i].selectedIndex != -1) {
                        field_value = inputs[i].options[inputs[i].selectedIndex].value;
                    }
                    param_val = field_value;
                }
            } else {
                param_val = inputs[i].value;
            }

            param_val = param_val.replace(/\+/gi, '%2B');
            param_val = param_val.replace(/&/gi, '%26');

            params[param_key] = param_val;
            params_strings[i] = param_key + "=" + param_val;

            // set form field info

            // disable submit buttons
            if (inputs[i].getAttribute('type') == 'submit') inputs[i].disabled = true;

        }

        ret = params_strings.join("&") + "&__ajaxrpc_formname__=" + formname + "&__ajaxrpc_url__=" + escape(location.href);

        return ret;
    },

    /*
     * Flash a message onscreen
     */
    ajaxFlash: function(message, timeout) {
        f1 = document.getElementById('flash_message');

        f1.innerHTML = message;
        f1.style.display = 'block';

        window.setTimeout("ajaxRPC.hideFlash()", timeout);
    },

    /*
     * Hide the flash message
     */
    hideFlash: function() {
        f1 = document.getElementById('flash_message');
        f1.style.display = 'none';
    },

    /*
     * Create a new input field
     */
    createInputField: function(type, name, value) {
        var field = document.createElement('input');

        field.setAttribute('type', type);
        field.setAttribute('name', name);
        field.setAttribute('value', value);

        return field;
    },

    __initAJAXRPC_Form: function() {
        document.write('<form id="__ajaxrpc_form__" name="__ajaxrpc_form__" action="/" class="req" method="post">' + '<input type="hidden" name="__ajaxrpc_type__" value="" />' + '<input type="hidden" name="__ajaxrpc_route__" value="" />' + '<input type="hidden" name="__ajaxrpc_params__" value="" />' + '<input type="hidden" name="__ajaxrpc_callback_func__" value="" />' + '</form>');

        var f = document.__ajaxrpc_form__;
        f.onsubmit = function() {
            ajaxRPC.formRequest(f)
        };
        ajaxRPC.__ajaxRPCLoaded = 1;
    },

    __internalCall: function(route, calltype, params, callback_func) {

        if (ajaxRPC.__ajaxRPCLoaded != 1) {
            ajaxRPC.__initAJAXRPC_Form();

        }

        var f = eval('document.__ajaxrpc_form__');

        f.__ajaxrpc_route__.value = route;
        f.__ajaxrpc_params__.value = params;
        f.__ajaxrpc_type__.value = calltype;
        f.__ajaxrpc_callback_func__.value = callback_func;

        this.formSubmit('__ajaxrpc_form__');
    },

    /*
     * Make a new RPC Request
     */
    call: function(route, calltype, params, callback_func) {
        ajaxRPC.__internalCall(route, 'rpc', new Array(), '');
    },

    /*
     * Make a new RPC Request
     */
    rpc: function(route) {
        ajaxRPC.__internalCall(route, 'rpc', new Array(), '');
    },

    /*
     * Validate a form
     */
    validate: function(form_name) {
        var obj = eval("document." + form_name);

        obj.appendChild(ajaxRPC.createInputField('hidden', '__ajaxrpc_type__', 'form_validator'));
        obj.appendChild(ajaxRPC.createInputField('hidden', '__ajaxrpc_route__', obj.action));
        obj.appendChild(ajaxRPC.createInputField('hidden', '__ajaxrpc_params__', new Array(form_name)));
        obj.appendChild(ajaxRPC.createInputField('hidden', '__ajaxrpc_callback_func__', ''));

        this.formSubmit(form_name);
    }
}

/*
 * Load automatic key press events (Enter)
 */
var EventCache = function() {
    var listEvents = [];
    return {
        listEvents: listEvents,
        add: function(node, sEventName, fHandler) {
            listEvents.push(arguments);
        },
        flush: function() {
            var i,
            item;
            for (i = listEvents.length - 1; i >= 0; i = i - 1) {
                item = listEvents[i];
                if (item[0].removeEventListener) {
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };
                if (item[1].substring(0, 2) != "on") {
                    item[1] = "on" + item[1];
                };
                if (item[0].detachEvent) {
                    item[0].detachEvent(item[1], item[2]);
                };
                item[0][item[1]] = null;
            };
        }
    };
} ();

function addEvent(obj, type, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    } else if (obj.attachEvent) {
        obj["e" + type + fn] = fn;
        obj[type + fn] = function() {
            obj["e" + type + fn](window.event);
        }
        obj.attachEvent("on" + type, obj[type + fn]);
        EventCache.add(obj, type, fn);
    } else {
        obj["on" + type] = obj["e" + type + fn];
    }
}