var Class = {
    create: function() {
        return function() {
            this.initialize.apply(this, arguments);
        }
    }
}
 
Object.extend = function(destination, source) {
    for (var property in source) {
        destination[property] = source[property];
    }
    return destination;
}
var $A =  function(iterable) {
    if (!iterable) return [];
    if (iterable.toArray) {
        return iterable.toArray();
    } else {
        var results = [];
        for (var i = 0; i < iterable.length; i++)
            results.push(iterable[i]);
        return results;
    }
}
Function.prototype.bind = function() {
    var __method = this, args = $A(arguments), object = args.shift();
    return function() {
        return __method.apply(object, args.concat($A(arguments)));
    }
}
var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
    initialize: function(callback, frequency) {
        this.callback = callback;
        this.frequency = frequency;
        this.currentlyExecuting = false;

        this.registerCallback();
    },

    registerCallback: function() {
        this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    },

    stop: function() {
        if (!this.timer) return;
        clearInterval(this.timer);
        this.timer = null;
    },

    onTimerEvent: function() {
        if (!this.currentlyExecuting) {
            try {
                this.currentlyExecuting = true;
                this.callback(this);
            } finally {
                this.currentlyExecuting = false;
            }
        }
    }
}

/*======================================================*/
var Buffalo = Class.create();
Buffalo.BOCLASS = "_BUFFALO_OBJECT_CLASS_";
Buffalo.VERSION = "2.0";

Buffalo.prototype = {
    initialize: function(gateway, async, events, options) {
        this.gateway = gateway;
        this.transport = null;
        if (typeof(async) == 'undefined') {
            this.async = true;
        } else {
            this.async = async;
        }
        this.currentCallback = new Function();
        this.setEvents(events);
        this.queue = [];
        this.requesting = false;
        this.options = {timeout:30000};
        Object.extend(this.options, options || {});
    },

    getGateway : function() {
        return this.gateway;
    },

    setEvents: function(events) {
        this.events = {
            onLoading: Buffalo.Default.showLoading,
            onFinish: new Function(),
            onException: Buffalo.Default.showException,
            onError: Buffalo.Default.showError,
            onTimeout: new Function()
        };
        Object.extend(this.events, events || {});
    },

_remoteCall: function(url, buffaloCall, callback) {

    this.requesting = true;
        this.transport = XmlHttp.create();
        try {
            this.transport.open("POST", url, this.async);
            this.transport.setRequestHeader("X-Buffalo-Version", Buffalo.VERSION);
            this.transport.send(buffaloCall.xml());
        } catch (e) {
            this.events.onError(this.transport);
            this.events["onLoading"](false);
            return;
        }
        this.requestTime = new Date();
        this.timeoutHandle = new PeriodicalExecuter(this._timeoutChecker.bind(this), 0.5);
        this.currentCallback = callback;
        if (this.async) {
            this.transport.onreadystatechange = this.onStateChange.bind(this);
            this.events["onLoading"](true);
        } else {
            this.response();
        }
    },

    _timeoutChecker: function() {
        if ((new Date() - this.requestTime) > this.options.timeout) {
            this.events["onTimeout"]();
            this.timeoutHandle.stop();
        }
    },

    nextRemoteCall : function() {
        if (this.queue.length <= 0) return;

        var command = this.queue.shift();

        this._remoteCall(command.url, command.call, command.callback);
    },

    remoteCall: function(service, params, callback) {
        var serviceMethodPair = this._splitServiceMethod(service);
        var newUrl = this.gateway + "/buffalo/" + serviceMethodPair[0];
        var call = new Buffalo.Call(serviceMethodPair[1]);
        for (var i = 0; i < params.length; i++) {
            call.addParameter(params[i]);
        }

        this.queue.push({url:newUrl, call: call, callback: callback});

        if (!this.requesting) {
            this.nextRemoteCall();
        }
    },

    _splitServiceMethod: function(service) {
        var idx = service.lastIndexOf(".");

        var serviceId = service.substring(0, idx);
        var method = service.substring(idx + 1, service.length);

        return [serviceId, method];
    },

    onStateChange: function() {
        if (this.transport.readyState == 4) {
            this.response();
        }
    },

    response : function() {
        this.timeoutHandle.stop();
        this.events["onLoading"](false);
        if (this.transport.responseText && this.transport.status == '200') {
            var reply = new Buffalo.Reply(this.transport);
            if (reply.isFault()) {
                this.events["onException"](reply.getResult());
            }
            this.currentCallback(reply);
            this.events["onFinish"](reply);
            this.requesting = false;
            this.nextRemoteCall();
        } else {
            this.events["onError"](this.transport);
            this.requesting = false;
        }
    }
}

Buffalo.Default = {
    loadingPane: null,
    errorPane: null,
    exceptionPane: null,

    showLoading : function(state) {
        //		this.loadingPane = document.getElementById("buffalo_loading");
        //		if (this.loadingPane == null) {
        //			var el = document.createElement('DIV');
        //			el.setAttribute("id","buffalo_loading");
        //			el.style.cssText="display:none;font-family:Verdana;font-size:11px;border:1px solid #00CC00;background-color:#A4FFA4;padding:1px;position:absolute; right:1px; top:1px; width:110px; height:14px; z-index:10000";
        //			el.innerHTML="buffalo loading... ";
        //			document.body.appendChild(el);
        //			this.loadingPane = el;
        //		}
        //		if (state) {
        //			this.loadingPane.style.display="block";
        //			this.loadingPane.style.top = document.body.scrollTop+1;
        //		} else {
        //			this.loadingPane.style.display="none";
        //		}
    },

    showError: function(transport) {
        //		this.errorPane = document.getElementById("buffalo_error");
        //		if (this.errorPane == null) {
        //			var el = document.createElement('DIV');
        //			el.setAttribute("id","buffalo_error");
        //            el.style.cssText="font-size:11px;border:4px solid #FF3333;background-color:#fff;padding:4px;position:absolute;overflow:auto; right:10px; top:10px; width:500px; height:300px; z-index:1";
        //			el.innerHTML="<h2>Error: " + transport.status+" - "+transport.statusText+"</h2>";
        //			el.innerHTML+="<textarea style='width:96%;height:80%'>"+transport.responseText.stripTags()+"</textarea>";
        //      		el.onclick=function(){ el.style.display="none"; }
        //			document.body.appendChild(el);
        //			this.errorPane = el;
        //		} else {
        //			this.errorPane.style.display = "block";
        //		}
    },

    showException: function(faultObj) {
        //		this.exceptionPane = document.getElementById("buffalo_exception");
        //		if (this.exceptionPane == null) {
        //			var el = document.createElement('DIV');
        //			el.setAttribute("id","buffalo_exception");
        //			el.style.cssText="font-size:11px;border:4px solid #FFFF33;background-color:#fff;padding:4px;position:absolute;overflow:auto; right:10px; top:10px; width:300px; height:100px; z-index:1";
        //			el.innerHTML ="<h2>Exception: " + faultObj.code+"</h2>";
        //			el.innerHTML += "Code: "+faultObj.code+"<br/>";
        //			el.innerHTML += "Message: "+faultObj.message+"<br/>";
        //			el.innerHTML += "Detail: " + faultObj.detail;
        //      		el.onclick=function(){ el.style.display="none"; }
        //			document.body.appendChild(el);
        //			this.exceptionPane = el;
        //		} else {
        //			this.exceptionPane.style.display = "block";
        //		}
    },

    showTimeout: function() {
        alert("timeout!");
    }
}

function getDomDocumentPrefix() {
    if (getDomDocumentPrefix.prefix)
        return getDomDocumentPrefix.prefix;

    var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
    var o;
    for (var i = 0; i < prefixes.length; i++) {
        try {
            // try to create the objects
            o = new ActiveXObject(prefixes[i] + ".DomDocument");
            return getDomDocumentPrefix.prefix = prefixes[i];
        }
        catch (ex) {
        }
        ;
    }

    throw new Error("Could not find an installed XML parser");
}

function getXmlHttpPrefix() {
    if (getXmlHttpPrefix.prefix)
        return getXmlHttpPrefix.prefix;

    var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
    var o;
    for (var i = 0; i < prefixes.length; i++) {
        try {
            o = new ActiveXObject(prefixes[i] + ".XmlHttp");
            return getXmlHttpPrefix.prefix = prefixes[i];
        }
        catch (ex) {
        }
        ;
    }

    throw new Error("Could not find an installed XMLHttp object");
}

function XmlHttp() {
}

XmlHttp.create = function () {
    try {
        if (window.XMLHttpRequest) {
            var req = new XMLHttpRequest();
            if (req.readyState == null) {
                req.readyState = 1;
                req.addEventListener("load", function () {
                    req.readyState = 4;
                    if (typeof req.onreadystatechange == "function")
                        req.onreadystatechange();
                }, false);
            }

            return req;
        }
        if (window.ActiveXObject) {
            return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
        }
    }
    catch (ex) {
    }
    throw new Error("Your browser does not support XmlHttp objects");
};

function XmlDocument() {
}
XmlDocument.create = function () {
    try {
        if (document.implementation && document.implementation.createDocument) {
            var doc = document.implementation.createDocument("", "", null);
            if (doc.readyState == null) {
                doc.readyState = 1;
                doc.addEventListener("load", function () {
                    doc.readyState = 4;
                    if (typeof doc.onreadystatechange == "function")
                        doc.onreadystatechange();
                }, false);
            }

            return doc;
        }
        if (window.ActiveXObject)
            return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
    }
    catch (ex) {
    }
    throw new Error("Your browser does not support XmlDocument objects");
};

if (window.DOMParser &&
    window.XMLSerializer &&
    window.Node && Node.prototype && Node.prototype.__defineGetter__) {

    Document.prototype.loadXML = function (s) {

        var doc2 = (new DOMParser()).parseFromString(s, "text/xml");

        while (this.hasChildNodes())
            this.removeChild(this.lastChild);
        for (var i = 0; i < doc2.childNodes.length; i++) {
            this.appendChild(this.importNode(doc2.childNodes[i], true));
        }
    };

    Document.prototype.__defineGetter__("xml", function () {
        return (new XMLSerializer()).serializeToString(this);
    });
}
Buffalo.Call = Class.create();
Buffalo.Call.prototype = {
    initialize: function(methodname) {
        this.method = methodname;
        this.params = [];
    },

    addParameter: function(data) {
        if (typeof(data) == 'undefined') return;
        this.params[this.params.length] = data;
    },

    xml: function() {
        var xmlstr = "<buffalo-call>\n";
        xmlstr += "<method>" + this.method + "</method>\n";
        for (var i = 0; i < this.params.length; i++) {
            var data = this.params[i];
            xmlstr += this.getParamXML(this.dataTypeOf(data), data) + "\n";
        }
        xmlstr += "</buffalo-call>";
        return xmlstr;
    },

/* Guess the type of an javascript object */
    dataTypeOf: function (o) {
        if (o == null) {
            return "null";
        }
        var type = typeof(o);
        type = type.toLowerCase();
        switch (type) {
            case "number":
                if (Math.round(o) == o) type = "int";
                else type = "double";
                break;
            case "object":
                var con = o.constructor;
                if (con == Date) type = "date";
                else if (con == Array) type = "list";
                else type = "map";
                break;
        }
        return type;
    },

    doValueXML: function(type, data) {
        var xml, str = data;
        if (typeof(data) == "string") {
            str = str.replace(/&/g, "&amp;");
            str = str.replace(/</g, "&lt;");
            str = str.replace(/>/g, "&gt;");
            xml = "<" + type + ">" + str + "</" + type + ">";
        } else {
            xml = "<" + type + ">" + data + "</" + type + ">";
        }

        return xml;
    },

    doBooleanXML:function(data) {
        var value = (data == true) ? 1 : 0;
        var xml = "<boolean>" + value + "</boolean>";
        return xml;
    },

    doDateXML: function(data) {
        var xml = "<date>";
        xml += dateToISO8609(data);
        xml += "</date>";
        return xml;
    },

    doArrayXML : function(data) {
        var xml = "<list>\n";
        var boClass = data[Buffalo.BOCLASS];
        var boType = boClass ? boClass : this.arrayType(data);
        xml += "<type>" + boType + "</type>\n";
        xml += "<length>" + data.length + "</length>\n";
        for (var i = 0; i < data.length; i++) {
            xml += this.getParamXML(this.dataTypeOf(data[i]), data[i]) + "\n";
        }
        xml += "</list>\n";
        return xml;
    },

    arrayType: function(arr) {
        if (arr.length == 0) return "";
        var type = "";
        var obj = arr;
        while (this.isArray(obj)) {
            var canBeArray = true;
            for (var i = 0; i < obj.length; i++) {
                if (typeof(obj[i]) != typeof(obj[0])) {
                    canBeArray = false;
                    break;
                } else {
                    if (typeof(obj[i]) == 'object') {
                        if (obj[0][Buffalo.BOCLASS] != obj[i][Buffalo.BOCLASS]) {
                            canBeArray = false;
                            break;
                        }
                    }
                }
            }
            if (canBeArray) {
                type += "[";
                obj = obj[0];
            } else {
                break;
            }
        }
        if (type.indexOf("[") == -1) return "";
        var componentType = obj[Buffalo.BOCLASS] || typeof(obj);
        if (componentType == 'object') return "";
        return type + componentType;
    },

    isArray: function(obj) {
        return typeof(obj) == 'object' && obj.constructor == Array;
    },

    doStructXML : function(data) {
        var boType = data[Buffalo.BOCLASS] || "java.util.HashMap";
        var xml = "<map>\n";
        xml += "<type>" + boType + "</type>\n";

        for (var i in data) {
            if (data[i] != boType) {
                if (typeof(data[i]) == "function") continue;
                /* the function shouldn't transfered. */
                xml += this.getParamXML(this.dataTypeOf(i), i) + "\n";
                xml += this.getParamXML(this.dataTypeOf(data[i]), data[i]) + "\n";
            }
        }
        xml += "</map>\n";
        return xml;
    },

    doNullXML : function() {
        return "<null></null>";
    },

    getParamXML: function(type, data) {
        var xml;
        switch (type) {
            case "date": xml = this.doDateXML(data); break;
            case "list": xml = this.doArrayXML(data); break;
            case "map": xml = this.doStructXML(data); break;
            case "boolean": xml = this.doBooleanXML(data); break;
            case "null": xml = this.doNullXML(); break;
            default: xml = this.doValueXML(type, data); break;
        }
        return xml;
    }
}

function dateToISO8609(date) {
    var year = date.getYear();
    /* Fix for Y2K */
    if (year < 2000) {
        year += 1900;
    }
    var month = leadingZero(new String(date.getMonth() + 1));
    var day = leadingZero(new String(date.getDate()));
    var time = leadingZero(new String(date.getHours())) + leadingZero(new String(date.getMinutes())) + leadingZero(new String(date.getSeconds()));

    var converted = year + month + day + "T" + time + "Z";
    return converted;
}

function leadingZero(n) {
    if (n.length == 1) n = "0" + n;
    return n;
}
Buffalo.Reply = Class.create();
Buffalo.Reply.prototype = {
    initialize: function(xhr) {
        this._isFault = false;
        this._type = "null";
        this._objects = [];
        this._objectNodes = [];
        this._source = xhr.responseText;

        var root = xhr.responseXML ? xhr.responseXML.documentElement :
                   this.constructNodeFromXmlStringInIEOrFF(this._source);

        this.dataNode = root.firstChild;
        this._type = this._getType(this.dataNode);
    },

    constructNodeFromXmlStringInIEOrFF: function(xmlString) {
        var xmldoc = XmlDocument.create();
        xmldoc.async = false;
        xmldoc.loadXML(xmlString);
        return xmldoc.documentElement;
    },

    getType: function() {
        return this._type;
    },

    getResult : function() {
        return this.deserialize(this.dataNode);
    },

    isFault : function() {
        return (this._type == "fault");
    },

    isNull: function() {
        return (this._type == "null");
    },

    getSource : function() {
        return this._source;
    },

    deserialize: function(dataNode) {
        var ret;
        var type = this._getType(dataNode);
        switch (type) {
            case "boolean": ret = this.doBoolean(dataNode); break;
            case "date": ret = this.doDate(dataNode); break;
            case "double": ret = this.doDouble(dataNode); break;
            case "int":
            case "long":
                ret = this.doInt(dataNode);
                break;
            case "list": ret = this.doList(dataNode); break;
            case "map": ret = this.doMap(dataNode); break;
            case "null": ret = this.doNull(dataNode); break;
            case "ref": ret = this.doRef(dataNode); break;
            case "string": ret = this.doString(dataNode);break;
            case "xml": ret = this.doXML(dataNode); break;
            case "fault": ret = this.doFault(dataNode); break;
            default: ;
        }

        return ret;
    },

    _getType : function(dataNode) {
        return dataNode.tagName.toLowerCase();
    },

    getNodeText :function(dataNode) {
        if (dataNode && dataNode.hasChildNodes()) {
            var s = "";
            for (var i = 0; i < dataNode.childNodes.length; i++) {
                s += new String(dataNode.childNodes.item(i).nodeValue);
            }
            return s;
        } else {
            return null;
        }
    },

    doBoolean : function (dataNode) {
        var value = this.getNodeText(dataNode);
        return (value == "1");
    },

    doDate : function (dataNode) {

        var dateStr = this.getNodeText(dataNode);
        var year = parseInt(dateStr.substring(0, 4), "10");
        var month = parseInt(dateStr.substring(4, 6), "10") - 1;
        var day = parseInt(dateStr.substring(6, 8), "10");
        var hour = parseInt(dateStr.substring(9, 11), "10");
        var minute = parseInt(dateStr.substring(11, 13), "10");
        var second = parseInt(dateStr.substring(13, 15), "10");

        var d = new Date(year, month, day, hour, minute, second);
        return d;
    },

    doDouble : function (dataNode) {
        var value = this.getNodeText(dataNode);
        return parseFloat(value);
    },

    doInt: function (dataNode) {
        var value = this.getNodeText(dataNode);
        return parseInt(value);
    },

    doList: function (dataNode) {
        var arr = new Array();
        this._objects[this._objects.length] = arr;

        var children = dataNode.childNodes;
        arr[Buffalo.BOCLASS] = this.getNodeText(children[0]);
        for (var i = 2; i < children.length; i++) {
            arr[arr.length] = this.deserialize(children[i]);
        }

        return arr;
    },

    doMap: function (dataNode) {

        var obj = new Object();
        this._objects[this._objects.length] = obj;

        var attrs = dataNode.childNodes;
        obj[Buffalo.BOCLASS] = this.getNodeText(attrs[0]);
        for (var i = 1; i < attrs.length; i += 2) {
            if (attrs[i + 1].hasChildNodes()) {
                obj[this.getNodeText(attrs[i])] = this.deserialize(attrs[i + 1]);
            } else {
                obj[this.getNodeText(attrs[i])] = attrs[i + 1].text;
            }
        }

        return obj;
    },

    doNull: function (dataNode) {
        return null;
    },

    doRef: function (dataNode) {
        var value = this.getNodeText(dataNode);
        var idx = parseInt(value);

        return this._objects[idx];
    },

    doString: function (dataNode) {
        var value = this.getNodeText(dataNode);
        if (value == null) {
            return "";
        }
        return (value);
    },

    doXML : function (dataNode) {
        var value = this.getNodeText(dataNode);
        return unescape(value);
    },

    doFault : function (dataNode) {
        var code = this.getNodeText(dataNode.childNodes[1]);
        var msg = this.getNodeText(dataNode.childNodes[3]);
        var detail = this.deserialize(dataNode.childNodes[5]);
        return new Buffalo.Fault(code, msg, detail);
    }
}

Buffalo.Fault = Class.create();
Buffalo.Fault.prototype = {
    initialize: function(code, message, detail) {
        this.code = code;
        this.message = message;
        this.detail = detail;
    },
    toString: function() {
        return "Buffalo.Fault:[code=" + this.code + ", message=" + this.message + ", detail=" + this.detail + "]";
    }
}
Object.extend(Buffalo.prototype, {
    bindReply : function(service, params, bindElemId, options) {
        this.remoteCall(service, params, function(reply) {
            Buffalo.Bind.bind(bindElemId, reply.getResult(), options);
        })
    }
});

Buffalo.Bind = {
    bind : function(elementId, bindValue, options) {
        var elem = $(elementId); 
        switch (elem.tagName) {
            case "INPUT":
                switch (elem.type.toLowerCase()) { 
                    case "text": ;
                    case "hidden": ;
                    case "password": Buffalo.BindFactory.bindText(elem, bindValue); break;

                    case "checkbox": ;
                    case "radio": Buffalo.BindFactory.bindRadioOrCheckbox(elem, bindValue); break;
                }
                break;
            case "TEXTAREA":
                Buffalo.BindFactory.bindText(elem, bindValue);
                break;
            case "TABLE":
                Buffalo.BindFactory.bindTable(elem, bindValue);
                break;
            case "SELECT":
                Buffalo.BindFactory.bindSelect(elem, bindValue, options);
                break;
            case "DIV": 
            case "LI":
            case "SPAN":
                elem.innerHTML = bindValue;
                  break;
            case "FORM":
                Buffalo.Form.bindForm(elem, bindValue);
        }
    }
}

Buffalo.BindFactory = {
    reportError: function(elem, value, msg) {
        throw "Data bind failed: " + msg;
    },

    bindText: function(elem, value) {
        elem.value = value;
    },

    bindRadioOrCheckbox: function(elem, value) {
        elem.checked = Buffalo.BindFactory.checkTrue(value);
    },

    bindSelect : function(elem, value, options) {
        //TO DO: Check the data type
        if (typeof(value) != "object" || value.constructor != Array) {
            this.reportError(elem, value, "Array Type Needed for binding select!");
        }
        while (elem.childNodes.length > 0) {
            elem.removeChild(elem.childNodes[0]);
        }

		// bind data
        for (var i = 0; i < value.length; i++) {

            var option = document.createElement("OPTION");

            if (options && options.binder) {
                options.binder(value, option, i);
            } else {
                var data = value[i];
                if (typeof(data) != 'object') {
                    option.value = data;
                    option.text = data;
                } else {
                    option.value = data[elem.getAttribute("jvalue")];
                    option.text = data[elem.getAttribute("jtext")];
                    if (Buffalo.BindFactory.checkTrue(data.selected)) {
                        option.selected = true;
                    }
                }
            }

            elem.options.add(option);
        }
    },

    bindTable: function(elem, value) {
        var jHeight = parseInt(elem.getAttribute("jheight"));
        var dataHeader = [];
        var tBody = elem.getElementsByTagName("TBODY")[0];

		// clear the generated rows
        if (elem.getElementsByTagName("TBODY").length > 0) {
            while (tBody.rows.length > jHeight) {
                tBody.deleteRow(jHeight);
            }
        }

        if (jHeight == 0) { // if table is null, push the data to the tables.

            for (var x in value[0]) {
                dataHeader[dataHeader.length] = x;
            }

            var hTr = elem.insertRow(elem.rows.length);
            for (var i = 0; i < dataHeader.length; i++) {
                var td = hTr.insertCell(hTr.cells.length);
                td.innerHTML = dataHeader[i];
            }

            for (var i = 0; i < value.length; i++) {
                var tr = elem.insertRow(elem.rows.length);
                var data = value[i];
                for (x in data) {
                    var td = tr.insertCell(tr.cells.length);
                    td.innerHTML = data[x];
                }
            }
        }

        if (jHeight == 1) { // if there is only one line, first line is header(every td indicate by a jtext property)
            var headerTR = tBody.rows[0];

            for (var i = 0; i < headerTR.cells.length; i++) {
                dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
            }

            for (var i = 0; i < value.length; i++) {
                var tr = tBody.insertRow(tBody.rows.length);
                var data = value[i];
                for (var j = 0; j < dataHeader.length; j++) {
                    var td = tr.insertCell(tr.cells.length);
                    td.innerHTML = data[dataHeader[j]];
                }
            }
        }

        if (jHeight == 2) { // two lines, first line is header, the second is style

            var headerTR = tBody.rows[0];

            for (var i = 0; i < headerTR.cells.length; i++) {
                dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
            }

            for (var i = 0; i < value.length; i++) {

                var tr;

                if (i == 0) { // if the first row
                    tr = elem.rows[1];
                } else { // else copy the first row
                    tr = elem.rows[1].cloneNode(true);
                }

                if (i > 0) {
                    tBody.appendChild(tr);
                }

                var data = value[i];
                for (var j = 0; j < tr.cells.length; j++) {
                    var td = tr.cells[j];

                    td.innerHTML = data[dataHeader[j]];
                }

            }
        }

        if (jHeight >= 3) { // more than 3 rows, first header, second and third is odd/even style, other lines ommited.
            var headerTR = tBody.rows[0];
            for (var i = 0; i < headerTR.cells.length; i++) {
                dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
            }
            for (var i = 0; i < value.length; i++) {
                var tr;

                if (i == 0) { // 1st row
                    tr = tBody.rows[1];
                } else if (i == 1) { // 2nd row
                    tr = tBody.rows[2];
                } else if (i % 2 == 0) { // get the 1st row
                    tr = tBody.rows[1].cloneNode(true);
                } else if (i % 2 == 1) { // the 2nd row
                    tr = tBody.rows[2].cloneNode(true);
                }


                if (i > 1) {
                    tBody.appendChild(tr);
                }

                var data = value[i];

                for (var j = 0; j < tr.cells.length; j++) {
                    var td = tr.cells[j];
                    td.innerHTML = data[dataHeader[j]];
                }
            }
        }

    },

    checkTrue: function(value) {
        switch (typeof(value)) {
            case 'boolean': ret = value; break;
            case 'string': ret = (value == true || value == "1" || value == "true" || value == "yes"); break;
            case 'number': ret = (parseInt(value) == 1); break;
            default: ret = false;
        }
        return ret;
    }
}
Buffalo.bind = Buffalo.Bind.bind;
/*capable with the old version, deprecated*/
Buffalo.View = Class.create();

Buffalo.View.LAST_VIEWNAME = null;
Buffalo.View.CURRENT_VIEW = null;
Buffalo.View.HOME_VIEW = null;
Buffalo.View.HISTORY_IFRAME_ID = "buffalo-view-history-iframe";

Buffalo.View.iframeLoaded = function(loc) {
    var url = loc.href;

    var idx = url.indexOf("?");
    var viewName = "";
    if (idx > -1) {
        viewName = url.substring(idx + 1);
    }

    if (viewName == "") {
        viewName = Buffalo.View.HOME_VIEW;
    }

    if (Buffalo.View.CURRENT_VIEW != null) {
        Buffalo.View.CURRENT_VIEW.doSwitchPart(viewName);
    }
}

Buffalo.View.prototype = {

    initialize:function(buffaloObj) {
        this.buffalo = buffaloObj;
    },

    switchPart: function(partId, viewName, addToHistory) {
        this.partId = partId;
        this.viewName = viewName;
        if (typeof(addToHistory) == "undefined" || addToHistory == true) {
            this.addToHistory = true;
        } else {
            this.addToHistory = false;
        }

        if (Buffalo.View.LAST_VIEWNAME == null) {
            /* the first visit view is home view */
            Buffalo.View.HOME_VIEW = viewName;
            /* The first view, don't add to history */
            this.doSwitchPart(viewName);
            Buffalo.View.LAST_VIEWNAME = viewName;
            return;
        }

        Buffalo.View.CURRENT_VIEW = this;

        if (this.addToHistory) {
            if (document.getElementById(Buffalo.View.HISTORY_IFRAME_ID)) {
                var iframesrc = document.getElementById(Buffalo.View.HISTORY_IFRAME_ID).src;
                var newUrl = iframesrc;
                var idx = iframesrc.indexOf("?");
                if (idx > -1) {
                    newUrl = iframesrc.substr(0, idx);
                }
                newUrl += "?" + viewName;
                document.getElementById(Buffalo.View.HISTORY_IFRAME_ID).src = newUrl;
            } else {
                var msg = "It seems that you havent add the buffalo-blank.html as an Iframe for browser history.";
                msg += "\nSo this view cannot add to browser history.";
                msg += "\n\nTo prevent this dialog, use buffalo.switchPart(partId, viewName, false) or ";
                msg += "add the buffalo-blank.html to your main page with id 'buffalo-view-history-iframe'.";

                alert(msg);
            }
        }

        this.doSwitchPart(viewName);

        Buffalo.View.LAST_VIEWNAME = viewName;

    },

    doSwitchPart: function(viewName) {

        if (Buffalo.View.LAST_VIEWNAME == viewName) {
            return;
        }

        this.transport = XmlHttp.create();
        var nonCachedViewName = viewName;
        try {
            /*Fix for the IE cache*/
            if (/MSIE/.test(navigator.userAgent)) {
                var bfViewHackKey = "_bfviewhackkey_=" + (new Date()).getTime();
                if (viewName.indexOf('?') > -1) {
                    nonCachedViewName += "&" + bfViewHackKey;
                } else {
                    nonCachedViewName += "?" + bfViewHackKey;
                }
            }
            this.transport.open("GET", nonCachedViewName, this.buffalo.async);
            /*use get for static page*/
        } catch (e) {
            var msg = "Buffalo View Error: \n\n Cannot find view with name: " + "[" + viewName + "]";
            alert(msg);
        }

        this.transport.send(null);
        if (this.buffalo.async) {
            this.transport.onreadystatechange = this._viewHandle.bind(this);
            this.buffalo.events["onLoading"](true);
        } else {
            this._processView();
        }

        Buffalo.View.LAST_VIEWNAME = viewName;

    },

    _viewHandle : function() {
        this._processView();
    },

    _processView : function() {
        this.buffalo.events["onLoading"](false);
        if (this.transport.readyState == 4) {
            if (this.transport.status == '200') {
                var data = this.transport.responseText;
                this._showView(this.partId, this.viewName, data);
            } else {
                this.buffalo.events["onError"](this.transport);
            }
        }
    },

    _showView: function(partId, viewPath, viewData) {

        var regexp1 = /<script(.|\n)*?>(.|\n|\r\n)*?<\/script>/ig;
        var regexp2 = /<script(.|\n)*?>((.|\n|\r\n)*)?<\/script>/im;

        /* draw the html first */
        document.getElementById(partId).innerHTML = viewData.replace(regexp1, "");

        var result = viewData.match(regexp1);
        if (result) {
            for (var i = 0; i < result.length; i++) {
                var realScript = result[i].match(regexp2);
                this._executeScript(realScript[2], partId);
                /* Note: do not try to write more than one <script> in your view.*/
                /* break;  process only one script element */
            }
        }

    },

    _executeScript : function(scriptFrag, partId) {
        var scriptContainerId = partId + "_SCRIPT_CONTAINER";
        var obj = document.getElementById(scriptContainerId);
        var ss = document.getElementsByTagName("SCRIPT");
        if (obj != null) {
            document.body.removeChild(obj);
        }
        var scriptContainer = document.createElement('SCRIPT');
        scriptContainer.setAttribute("id", scriptContainerId);
        scriptContainer.text = scriptFrag;
        document.body.appendChild(scriptContainer);
    }

}

Object.extend(Buffalo.prototype, {

    switchView: function(viewName, container) {
        container = container ? container : "body";
        this.switchPart(container, viewName, true);
    },

    switchPart : function(partId, viewName, addToHistory) {
        new Buffalo.View(this).switchPart(partId, viewName, addToHistory);
    }
});
Buffalo.Form = {
    formToBean : function(form, boClass, ignoreButton) {
        var object = {};
        if (boClass) {
            object[Buffalo.BOCLASS] = boClass;
        } else {
            object[Buffalo.BOCLASS] = "java.util.Map";
        }
        if (typeof(ignoreButton) == "undefined" || ignoreButton == true) {
            ignoreButton = true;
        } else {
            ignoreButton = false;
        }

        form = document.getElementById(form);
        var elements = form.elements;
        for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            switch (element.type) {
                case "radio" :
                    if (element.checked) {
                        object[element.name] = element.value
                    }
                    break;
                case "checkbox" :
                    if (!form[element.name].length) {
                        if (element.checked) object[element.name] = element.value;
                        else object[element.name] = "";
                    } else {
                        if (!object[element.name]) {
                            object[element.name] = new Array()
                        }
                        ;
                        if (element.checked) {
                            object[element.name].push(element.value);
                        }
                    }
                    break;
                case "select-one" :
                    var value = '', opt, index = element.selectedIndex;
                    if (index >= 0) {
                        opt = element.options[index];
                        value = opt.value;
                        if (!value && !('value' in opt)) value = opt.text;
                    }
                    object[element.name] = value;
                    break;
                case "select-multiple" :
                    if (!object[element.name]) {
                        object[element.name] = new Array()
                    };
                    for (var j = 0; j < element.options.length; j++) {
                        var opt = element.options[j];
                        if (opt.selected) {
                            var optValue = opt.value;
                            if (!optValue && !('value' in opt)) optValue = opt.text;
                            object[element.name].push(optValue);
                        }
                    }
                    break;
                default :
                    if (ignoreButton) {
                        if (element.type != "submit" && element.type != "button"
                                && element.type != "reset") {
                            object[element.name] = element.value;
                        }
                    } else {
                        object[element.name] = element.value;
                    }
                    break;
            }
        }

        return object;
    },

    bindForm: function(form, data) {
        form = document.getElementById(form);
        for (var i = 0; i < form.elements.length; i++) {
            var element = form.elements[i];
            if (!data[element.name]) continue;
            var val = data[element.name];
            switch (element.type) {
                case "text": ;
                case "hidden": ;
                case "password": element.value = val; break;
                case "radio" :
                case "checkbox" :
                    if (val instanceof Array) element.checked = (val.indexOf(element.value) > -1);
                    else element.checked = (element.value == val);
                    break;
                case "select-one" :
                case "select-multiple" :
                    for (var j = 0; j < element.options.length; j++) {
                        var option = element.options[j];
                        if (val instanceof Array) {
                            option.selected = (val.indexOf(option.value) > -1);
                        } else {
                            option.selected = (option.value == val);
                        }
                    }
                    break;
            }
        }
    }
}
