/**
 * $Id: buffalo.js,v 1.1 2006/07/20 03:46:19 yangm Exp $
 * This script is base on script of Buffalo.
 */
var Buffalo = Class.create();
Buffalo.BOCLASS="_BUFFALO_OBJECT_CLASS_";
Buffalo.VERSION="1.2.3";
Buffalo.debug = false; // Just for debug: show call and reply info

Buffalo.prototype = {
    initialize: function(gateway, async, events) {
        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;
    },
    
    getGateway : function() { return this.gateway;},

    setEvents: function(events) {
        this.events = {
            onLoading: Buffalo.Default.showLoading,
            onFinish: new Function(),
            onException: new Function(),
            onError: Buffalo.Default.showError
        };
        Object.extend(this.events, events || {});
    },
    
    _remoteCall: function(url, burlapCall, callback) {
        this.requesting = true;
        this.transport = XmlHttp.create();
        this.transport.open("POST", url, this.async);
        this.transport.send(burlapCall.xml());
        this.currentCallback = callback;
        if (this.async) {
            this.transport.onreadystatechange = this.onStateChange.bind(this);
            this.events["onLoading"](true);
        } else { 
            this.response();
        }
    },

    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 idx = service.indexOf(".");

        var serviceId = service.substring(0,idx);
        var method = service.substring(idx+1,service.length);
        var newUrl = this.gateway + "/buffalo/" + serviceId;

        var call = new Buffalo.Call(method);
        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();
        }
    },

    remoteCall: function(servlet, method, params, callback) {   
        var action = servlet.substring(0, servlet.lastIndexOf("."));
        var extension = servlet.substring(servlet.lastIndexOf("."));
        var newUrl = action + "!" + method + extension;

        var call = new Buffalo.Call(method);
        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();
        }
    },

    onStateChange: function(){
        if (this.transport.readyState == 4) {
            this.response();
        }
    },

    response : function() {
        if (this.transport.status == '200') {
            var reply;
            var data = this.transport.responseText;
            if (data.indexOf("xmlns:burlap") == -1) {
                data = data.replace("<burlap:reply>",
                    "<burlap:reply xmlns:burlap=\"http://www.amowa.net/buffalo/\">");
                reply = new Buffalo.Reply(data);
            } else {
                reply = new Buffalo.Reply(this.transport);
            }

            this.events["onLoading"](false);
            this.currentCallback(reply);
            this.events["onFinish"](reply);
            this.requesting = false;
            this.nextRemoteCall();
        } else {
            this.events["onError"](this.transport.responseText);
        }
    }

}


Buffalo.Default = {
    loadingPane:null,
    errorPane:null,

    showLoading : function(state) {
        this.loadingPane = $("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:2px;top:1px;height:14px;z-index:10000";
            el.innerHTML = "Loading...";
            document.body.appendChild(el);
            this.loadingPane = el;
        }
        if (state) {
            this.loadingPane.style.display = "";
            //this.loadingPane.style.top = document.body.scrollTop + 1;
        } else {
            this.loadingPane.style.display = "none";
        }
    },

    showError: function(errorStr) {
        this.errorPane = $("buffalo_error");
        if (this.errorPane == null) {
            var el = document.createElement('DIV');
            el.setAttribute("id","buffalo_error");
            el.style.cssText = "font-family:Verdana;font-size:11px;border:1px solid #00CC00;background-color:#fff;padding:1px;position:absolute;overflow:auto; right:1px; top:1px; width:500px; height:300px; z-index:1";
            el.innerHTML=errorStr;
            document.body.appendChild(el);
            this.errorPane = el;
        }
    },

    showException: function(ex) { /*TODO*/ }
}

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 {
            // try to create the objects
            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 {
        // NS & MOZ
        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;
        }
        // IE
        if (window.ActiveXObject) {
            return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
        }
    }
    catch (ex) {}
    // Fail
    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) {
        while (this.hasChildNodes()) {
            this.removeChild(this.lastChild);
        }

        var doc2 = (new DOMParser()).parseFromString(s, "application/xml");
        for (var i = 0, n = doc2.childNodes.length; i < n; i++) {

        /* debug
        alert(doc2.childNodes[i].nodeName + ";" + doc2.childNodes[i].nodeValue);
        var childs = doc2.childNodes[i].childNodes;
        for (var ii = 0; ii < childs.length; ii++) {
            _list(childs[ii]);
        }
        */

            this.appendChild(this.importNode(doc2.childNodes[i], true));
        }
    };

    Document.prototype.__defineGetter__("xml", function () {
        return (new XMLSerializer()).serializeToString(this);
    });
}

function _list(child) {
   if (!child.hasChildNodes()) {
        if (child.nodeValue) {
            alert("type: " + child.nodeType + "; value: " + child.nodeValue.length);
        }
        return;
   }

   var cs = child.childNodes;
   for (var i = 0; i < cs.length; i++) {
        _list(cs[i]);
   }
}

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 = "";
        xmlstr += "<burlap: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 += "</burlap:call>";

        // Just for debug
        if (Buffalo.debug) {
            alert(xmlstr);
        }

        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") {
            // Escape the html chars
            str = str.replace(/&/g,"&amp;");
            str = str.replace(/</g,"&lt;");
            str = str.replace(/>/g,"&gt;");
            str = str.replace(/\"/g,"&quot;");

            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";
        xml += "<type>" +""+ "</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;
    },

    doStructXML : function(data){
        var boClass = data[Buffalo.BOCLASS];
        var boType = boClass ? 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(sourceXML) {
        this._isFault = false;
        this._type = "null";
        this._objects = [];
        this._objectNodes = [];

        var root;
        if (typeof(sourceXML) == "string") {
            this._source = sourceXML;
            root = this.constructNodeFromXmlStringInIEOrFF(this._source);
        } else {
            this._source = sourceXML.responseText;

            if (sourceXML.responseXML) {
                root = sourceXML.responseXML.documentElement;
            }
            if (!root || !root.tagName) {
                root = this.constructNodeFromXmlStringInIEOrFF(this._source);
            }
        }

        // Just for debug
        if (Buffalo.debug) {
            alert(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.childNodes.length == 0) {
            return null;
        } else {
            return dataNode.firstChild.nodeValue;
        }
    },

    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;
        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) {
        this.remoteCall(service, params, function(reply) {
            Buffalo.Bind.bind(bindElemId, reply.getResult());
        })
    }
});

Buffalo.Bind = {
    bind : function(elementId, bindValue) {
        var elem = Buffalo.getElementById(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);
                break; 
            case "DIV":
            case "SPAN":
                alert(bindValue);
                elem.innerHTML = bindValue;
                break;
            //TODO: add more bindings here for 
        }
    }
}

Buffalo.BindFactory = {
    reportError: function(elem, value, msg) { 
        throw "Data bind failed: "+msg;
    },

    bindText: function(elem, value) { 
        elem.value = value;
    },

    bindRadioOrCheckbox: function(elem, value) {
        var ret = false;
        switch (typeof(value)) {
            case 'boolean': ret = value; break;
            case 'string': ret = (value == "1" || value == "true" || value == "yes"); break;
            case 'number': ret = (parseInt(value) == 1); break;
            default: ret = false;
        }
        elem.checked = ret;
    },

    bindSelect : function(elem, value) {
        //TODO: Check the data type
        if (typeof(value) != "object" || value.constructor != Array) {
            this.reportError(elem,value,"Array Type Needed for binding select!");
        }
        // delete all the nodes.
        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");
            var data = value[i];
            if (data == null || typeof(data) == "undefined") {
                option.value = "";
                option.text = "";
            }
            if (typeof(data) != 'object') {
                option.value = data;
                option.text = data;
            } else {
                option.value = data[elem.getAttribute("jvalue")];
                option.text = data[elem.getAttribute("jtext")]; 
            }
            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]];
                }
            }   
        }
    },

    bindRepeater:function(elem, value) {
        //TODO: implementation will be added.
    }

}
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, callback) {
        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, callback);
            Buffalo.View.LAST_VIEWNAME = viewName;
            return;
        }

        Buffalo.View.CURRENT_VIEW = this;

        if (this.addToHistory) {
            if ($(Buffalo.View.HISTORY_IFRAME_ID)) {
                var iframesrc=$(Buffalo.View.HISTORY_IFRAME_ID).src;
                var newUrl = iframesrc;
                var idx = iframesrc.indexOf("?");
                if (idx > -1) {
                    newUrl = iframesrc.substr(0,idx);
                }
                newUrl += "?" + viewName;
                $(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, callback);

        Buffalo.View.LAST_VIEWNAME = viewName;
    },

    doSwitchPart: function(viewName, callback) {
        /*
        if (Buffalo.View.LAST_VIEWNAME == viewName) {
            return ;
        }
        */

        this.buffalo.transport = XmlHttp.create();
        var nonCachedViewName = viewName;
        this.buffalo.callback = callback;
        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.buffalo.transport.open("GET", nonCachedViewName, this.buffalo.async);/*use get for static page*/
            this.buffalo.transport.open("POST", nonCachedViewName, this.buffalo.async);
        } catch (e) {
            var msg = "Buffalo View Error: \n\n Cannot find view with name: " + "[" + viewName + "]";
            alert(msg); 
        }

        this.buffalo.transport.send(null);
        if (this.buffalo.async) {
            this.buffalo.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() {
        if (this.buffalo.transport.readyState == 4) {
            if (this.buffalo.transport.status == '200') {
                var data = this.buffalo.transport.responseText;
                // Just for debug
                if (Buffalo.debug) {
                    alert(data);
                }

                this.buffalo.events["onLoading"](false);
                this._showView(this.partId, this.viewName, data);
                if (this.buffalo.callback != null) {
                    this.buffalo.callback();
                }
            } else {
                this.buffalo.events["onError"](this.buffalo.transport.responseText);
            }
        }
    },

    _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 */
        $(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 = $(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, callback) {
        this.switchPart("body", viewName, true, callback);
    },

    switchPart : function(partId, viewName, addToHistory, callback) {     
        new Buffalo.View(this).switchPart(partId, viewName, addToHistory, callback);
    }, 

    changeLayout : function(newLayout) {
        /* // TODO */
    }
});
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 = $(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 (!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;
    },

    validate : function(formId) {
    }

}

