/*

使用本script的先決條件是必須引入json2.js，除非網頁只打算給IE8開。

引用本程式後即可擁有以下類別與物件:

[class]
DOMParser 
parseFromString()

Ajax
get()
set()
callCSharpService()

[static]
UnicodeParser
encode()
decode()
*/


// parseXmlToObject_old預設只能處理簡單格式，如果要處理其他類型須重寫本方法
function parseXmlToObject_old(xml) {
    var json = {};
    var root = xml.documentElement;
    json[root.tagName] = root.text || root.textContent;
    return json;
}
function parseXmlToObject(xml) {
    var json = {};
    var root = xml.documentElement;
    var json = parseNodeToObject(root);
    return json;
}

function parseNodeToObject_old(node) {
    var obj = {};
    var n = node.childNodes.length;
    var nodeName = node.tagName;
    if (n == 1) {
        obj[nodeName] = node.text || node.textContent;
    } else {
        obj[nodeName] = {};
        for (var k = 0; k < n; k++) {
            var child = node.childNodes[k];
            if (child.nodeType == 1) {
                //if (!obj[nodeName]) obj[nodeName] = {};
                obj[nodeName][child.tagName] = child.text || child.textContent;
            } else if (child.nodeType == 3) {
            }
        }
    }
    return obj;
}

function parseNodeToObject(node) {
    var obj = {};
    var nodeName = node.tagName;
    if (node.nodeType == 1) {
        if (nodeName.substr(0, 7) == 'ArrayOf') {
            var typeName = nodeName.substr(7);
            var arr = [];
            if (typeName.substr(0, 7) != 'ArrayOf') typeName = typeName.toLowerCase();
            //var children = node.getElementsByTagName(typeName);
            var children = (document.all) ? node.childNodes : node.getElementsByTagName(typeName);
            for (var k = 0; k < children.length; k++) {
                var child = children[k];
                if (child.nodeType == 1) arr.push(parseNodeToObject(child));
            }
            //obj[typeName] = arr;
            obj = arr;
        } else {
            var v = node.text || node.textContent;
            switch (nodeName.toLowerCase()) {
                case 'int':
                case 'string':
                    return v;
                default:
                    break;
            }

            obj[nodeName] = v;
        }

    } else {
        return node.text || node.textContent;
    }
    return obj;
}



/*
window.DOMParser
仿造 Xml.loadXML方法製作跨瀏覽器的 XmlDocument。
使用方法:
var xmlDoc = new DOMParser().parseFromString(xmlString,'text/xml');
*/
if (!window.DOMParser) window.DOMParser = function() {
    var _xml = null;
    var xmlDomVersions = ['MSXML2.DOMDocument.6.0', 'MSXML2.DOMDocument.3.0', 'Microsoft.XMLDOM'];
    for (var i = 0; i < xmlDomVersions.length; i++) {
        try {
            _xml = new ActiveXObject(xmlDomVersions[i]);
            _xml.async = false;
            break;
        } catch (e) { }
    }
    this.xml = _xml;
    this.parseFromString = function(xmlString, xmlType) {
        if (this.xml != null) {
            this.xml.loadXML(xmlString);
            return this.xml;
        } else {
            alert('DOMParser ERROR');
        }
    }

}

//建立類別，可以在需要的時候才製作實體，並可避免各實體之間的互相干擾。
function Ajax() {
    var xmlHttp = null;
    var onCompleteCallback = null;
    var onTimeoutCallback = null;
    var onErrorCallback = null;
    var xmlHttpTimeout = null;
    var defaultTimeout = 5000;
    var createXMLHttpRequest = function() {
        if (xmlHttp == null) {
            if (window.XMLHttpRequest) {
                xmlHttp = new XMLHttpRequest();
                //xmlHttp.overrideMimeType('text/xml'); // firefox
                //因為IE8也支援window.XMLHttpRequest，所以這一行不能用了
            } else if (window.ActiveXObject) {
                xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
        }
    }
    this.get = function(_url, _options) {
        return this.run('GET', _url, _options);
    }
    this.post = function(_url, _options) {
        return this.run('POST', _url, _options);
    }
    this.getXML = function(_url, _options) {
        _options.parser = function(data) {
            return new DOMParser().parseFromString(xmlString, 'text/xml');
        }
        return this.run('GET', _url, _options);
    }

    this.callCSharpService = function(_url, _options) {
        //原則上也是用post，但是要處理回傳的XML字串
        /* 回傳值是這個格式:
        <?xml version="1.0" encoding="utf-8"?>
		
		<string xmlns="http://tempuri.org/">Hello World</string>
        */
        _options.parser = function(xmlString) {
            //alert(xmlString);
            var xml = new DOMParser().parseFromString(xmlString, 'text/xml');
            var xmlObject = parseXmlToObject(xml);

            if (xmlObject != null) {
                var text = JSON.stringify(xmlObject
				, function(key, value) {
				    return this[key] instanceof Date ? 'JSDate:' + this[key] : value;
				});
                return text.indexOf('\\u') >= 0 ? UnicodeParser.decode(text) : text;
            } else {
                return null;
            }
        }

        return this.run('POST', _url, _options);
    }
    this.callCSharpServiceRtnObj = function(_url, _options) {
        //原則上也是用post，但是要處理回傳的XML字串
        /* 回傳值是這個格式:
        <?xml version="1.0" encoding="utf-8"?>
		
		<string xmlns="http://tempuri.org/">Hello World</string>
        */
        _options.parser = function(xmlString) {
            //alert(xmlString);
            var xml = new DOMParser().parseFromString(xmlString, 'text/xml');
            return (xml != null) ? parseXmlToObject(xml) : null;
        }

        return this.run('POST', _url, _options);
    }

    this.run = function(_method, _url, _options) {
        //createXMLHttpRequest();
        if (window.XMLHttpRequest) {
            xmlHttp = new XMLHttpRequest();

            //因為IE8也支援window.XMLHttpRequest了，所以這一行不能用了
            //xmlHttp.overrideMimeType('text/xml'); // firefox only

        } else if (window.ActiveXObject) {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }

        if (!xmlHttp) {
            alert("The XMLHttpRequest not supported");
            return;
        }
        onCompleteCallback = _options.onComplete;
        onTimeoutCallback = _options.onTimeout;
        onErrorCallback = _options.onError;
        var timeoutMS = _options.timeout || defaultTimeout;
        // IE8 natively supports xmlHttp.ontimeout event, don't know if other browsers can do?
        xmlHttpTimeout = setTimeout(function() {
            xmlHttp.abort();
            if (typeof (onTimeoutCallback) == 'function') onTimeoutCallback();
        }, timeoutMS);

        /* readyState 所有可能的值如下：
        * 0 (還沒開始)
        * 1 (讀取中)
        * 2 (已讀取)
        * 3 (資訊交換中)
        * 4 (一切完成) 
        */
        var dataParser = _options.parser;
        xmlHttp.onreadystatechange = function() {
            if (xmlHttp.readyState == 4) {
                if (xmlHttpTimeout != null) clearTimeout(xmlHttpTimeout);
                if (xmlHttp.status == 200) {
                    if (typeof (onCompleteCallback) == 'function') {
                        var response = xmlHttp.responseText;
                        if (typeof (dataParser) == 'function') response = dataParser(response);
                        onCompleteCallback(response);
                    }
                } else {
                    if (typeof (onErrorCallback) == 'function') onErrorCallback(xmlHttp.status);
                }
            }
        };
        var parameterString = ''; //據說在IIS6不能傳null，但我在IIS7 post時也沒辦法傳null
        var parameterLength = 0;
        if (_options.parameters) {
            var parameters = [];
            for (var k in _options.parameters) {
                _options.parameters[k] = encodeURIComponent(_options.parameters[k]);
                if (parameters.length > 0) parameters.push('&');
                parameters.push(k);
                parameters.push('=');
                parameters.push(_options.parameters[k]);
            }
            parameterString = parameters.join('');
            parameterLength = parameterString.length;
        }

        xmlHttp.open(_method, _url, true); //(httpMethod,  URL,  asynchronous)

        if (_method.toLowerCase() == 'post') {
            // set the necessary request headers
            xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
            xmlHttp.setRequestHeader("Content-Length", parameterLength);
            xmlHttp.setRequestHeader("Connection", "close");
        } else if (_method.toLowerCase() == 'get') {
            if (parameterString.length > 0) _url += parameterString;
        }
        //alert(parameterString);

        xmlHttp.send(parameterString);

    }

}


var UnicodeParser = {
    encode: function(str) {
        var a = [],
		i = 0;
        for (; i < str.length; ) a[i] = ("00" + str.charCodeAt(i++).toString(16)).slice(-4);
        return "\\u" + a.join("\\u")
    },
    decode: function(str) {
        return unescape(str.replace(/\\/g, "%"))
    }
};

/*
呼叫的時候用new敘述產生新的instance:

new Ajax().get('text2.txt', {
onComplete: function(returnData){
document.getElementById('textarea1').value += returnData;
}
,onErrorCallback: function(){}
,onTimeoutCallback: function(HTTPStatus){}
}
);

*/
/*
Date.prototype.toJSON = function(){
return 'new Date('+this.getTime()+')';
}
*/

String.prototype.toMultiply = function(num) {
    var output = [];
    for (var i = 0; i < num; i++) {
        output.push(this);
    }
    return output.join('');
}

var type = {
    is: {
        Null: function(a) { return a === null; },
        Undefined: function(a) { return a === undefined; },
        nt: function(a) { return (a === null || a === undefined); },
        Function: function(a) { return (typeof (a) === 'function') ? a.constructor.toString().match(/Function/) !== null : false; },
        String: function(a) { return (typeof (a) === 'string') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/string/i) !== null : false; },
        Array: function(a) { return (typeof (a) === 'object') ? a.constructor.toString().match(/array/i) !== null || a.length !== undefined : false; },
        Boolean: function(a) { return (typeof (a) === 'boolean') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/boolean/i) !== null : false; },
        Date: function(a) { return (typeof (a) === 'date') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/date/i) !== null : false; },
        HTML: function(a) { return (typeof (a) === 'object') ? a.constructor.toString().match(/html/i) !== null : false; },
        Number: function(a) { return (typeof (a) === 'number') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/Number/) !== null : false; },
        Object: function(a) { return (typeof (a) === 'object') ? a.constructor.toString().match(/object/i) !== null : false; },
        RegExp: function(a) { return (typeof (a) === 'function') ? a.constructor.toString().match(/regexp/i) !== null : false; }
    }
	, of: function(a) {
	    for (var i in this.is) {
	        if (this.is[i](a)) {
	            return i.toLowerCase();
	        }
	    }
	}
};

/* 簡易版typeof
var type = { 
of: function(obj) { 
var type = typeof(obj); 
if(type == 'object') { 
if(obj == null) { return 'null'; } 
else if(obj.constructor.toString().match(/regexp/i) != null) { return 'regexp'; } 
else if(obj.constructor.toString().match(/date/i) != null) { return 'date'; } 
else if(obj.constructor.toString().match(/html/i) != null) { return 'html'; } 
else if(obj.constructor.toString().match(/array/i) != null && typeof(obj.length) != 'undefined') { return 'array'; } 
else { return 'object'; } 
} 
else { return type; } 
} 
};

*/

