﻿/*

	使用本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] = encodeURI(_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; } 
	} 
};

*/
