(function(){
    String.prototype.trim = function()
    {
        return this.replace(/(^\s*)|(\s*$)/g, "");
    }
	var _temp,_temp1;
	_temp = [
		function(){return new XMLHttpRequest();},
		function(){return new ActiveXObject('Msxml2.XMLHTTP');},
		function(){return new ActiveXObject('Microsoft.XMLHTTP');},
		function(){return new ActiveXObject('MSXML2.XMLHTTP.5.0');},
		function(){return new ActiveXObject('MSXML2.XMLHTTP.4.0');},
		function(){return new ActiveXObject('MSXML2.XMLHTTP.3.0');},
	];
	var makeXhr;
	for(var n=0;n<_temp.length;n++){
		try{var fn = _temp[n];_temp1 = fn(); makeXhr = fn;break;}catch(e){}
	}
	
	var setXhrHandle;
	if(makeXhr){
		_temp = [
			function(xhr,handle){xhr.onreadystatechange = handle;},
			function(xhr,handle){xhr.readyState = 4;xhr.onload = handle;}
		];
		var h = function(){};
		for(var i=0;i<_temp.length;i++){
			try{var fn = _temp[i];fn(_temp1,h);setXhrHandle = fn;break;}catch(e){}
		}
		
	}else{
		makeXhr = function(){throw "Eanyee:Can't create raw XmlHttpRequest Object!";}
	}
	if(!setXhrHandle) setXhrHandle = function(){throw "Raw XmlHttpRequest don't suport callback handle!";};
	_temp = undefined;
	_temp1 = undefined;

	var buildUrl = function(url){
		var rnd = Math.random();
		if (url.indexOf("?")<0) url = url += "?";else url += "&";
		return url + rnd;
	}
	var makeData = function(data){
		if(typeof(data)=='string') return data;
		var ret = [];
		for(var n in data){
		    var val = data[n];
		     try{
		    val = val ? val.toString() : val;
		    }catch(e){continue;}
			ret.push(escape(n));ret.push("=");ret.push(escape(val));ret.push("&");
		}
		return ret.join("");
	}
	var Error = function(msg,code,context,innerError){
	    this.message = msg;
	    this.code = code;
	    this.context = context;
	    this.innerError = innerError;
	    this.toString = function(){
	        return "Error("+code+"):" + msg;
	    }
	}
	/****
	@Name		connect
	@Namespace	Eanyee
	@Type		Function
	@Return		{Object:XmlHttpRequest}	(raw xmlHttpRequest object)
	@Param		[callback]	{Function}	(the callback handle which will be invoked while the remote host response data arrived .the callback will pass two params to the function: the first is return value.if some error happened the first param is null and the sencond param is a string to describe the error)
	@Param		[params]	{Object:Map}$Must	(
												METHOD	:{String} Suport POST GET etc.. Default is "POST"
												ASYN	:{Boolean} if this param set as false the program will be blocked until the remote host response the data or an error ocurr.Default is true
												HEANDERS :{Object:Map} set the requests headers.if the mehtod is POST,the Content-Type header will set to 'application/x-www-form-urlencoded' forcely.
												CONTENT_TYPE :{String} assigned how to process the return content.suport RAW(the raw object of xmlhttprequest),TEXT,JSON,XML.Default is Text
												POST_DATA : the data to post
												URL : $Must which address you want to connect to
												CONST_PARAMS : the client pass the arguments to the callback 
											)
	@Remarks this function is a wrap of xmlHttpRequest.Main purpose is to create a simple method to request remote host data.
	****/
	var connect = function(params,callback,agent){
		var p = {};
		//var agent = agent;
		var x = p._xhr = makeXhr();
		var url = p.URL = buildUrl(params.URL || params);
		var data = p.POST_DATA = makeData(params.POST_DATA) || "";
		var method = params.METHOD;method = p.METHOD = (method)?method.toUpperCase():(data?"POST":"GET");
		var headers = params.HEANDERS || {};
		var asyn = p.ASYN = (params.ASYN===false)?false:true;
		var retType = p.CONTENT_TYPE = params.CONTENT_TYPE || "TEXT"; 
		p.CONST_PARAMS = params.CONST_PARAMS;
		var trueMethod;
		try{
			x.open(trueMethod = agent?'POST':method, (p.CALL_URL = agent||url), asyn);
		}catch(e){
			p.ERROR = new Error("fail to open the URL: " + (p.CALL_URL = agent||url),-1,arguments.callee,e);
			callback(null,p);
			return x;
		}
		if(callback) setXhrHandle(x,function(){
			 if (x.readyState !== 4) {
				return;
			}

			if (x.status !== 200) {
				p.ERROR =  new Error("connect error",x.status,arguments.callee,null);
				callback(null,p);
				return;
			}
			var text;
			try{
				text = x.responseText;
			}catch(e){
				p.ERROR = new Error("Can't get the Response Content",-2,arguments.callee,e);
				callback(null,p);
			}
			var retValue;
			switch(retType){
				case "XML":
					if (window.ActiveXObject) {
						var dom = new ActiveXObject("Microsoft.XMLDOM");
						dom.async = false;
						dom.validateOnParse = false;
						dom.resolveExternals = false;
						if (!dom.loadXML(text)) {
							p.ERROR = "failed to parse XML";
						} else {
							retValue = dom;
						}
					} else {
						var parser = new DOMParser();
						var dom = parser.parseFromString(text, "text/xml");
						if ("parsererror" === dom.documentElement.nodeName) {
							p.ERROR = "ERROR Parse to XML";
						} else {
							retValue = dom;
						}
					}

					break;
				case "RAW":
					retValue = x;
					break;
				case "JSON":
					var s;
					 try {
						//s = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
						//	text.replace(/("(\\.|[^"\\])*")|('(\\.|[^'\\])*')/g, ''))) &&
						retValue = eval('retValue=' + text);
						//retValue = s;
					} catch (e) {
						p.ERROR = "can't parse :" + text;
					}
					
					break;
				default:
					retValue = text;
					break;
			}
			callback(retValue,p,text);
		});
		if(trueMethod==="POST" &&  !headers["Content-Type"]){headers['Content-Type']='application/x-www-form-urlencoded';}
		var retHds = {};
		for(var n in headers){var v =headers[n]; x.setRequestHeader(n,v);retHds[n] = v;}
		p.HEADERS = retHds;
		if (agent){
			p.HEADERS = makeData(retHds);
			data = makeData(p);
		}
		
		x.send(data);
		return x;
	}
	function convertFeatureName(name){
		var libUrl = Eanyee.libUrls;
		if(name.indexOf("http://")!==0 && name.indexOf('https://')!==0 && name.indexOf("file:///")!==0){
			return libUrl + name;
		}
		return name;
	}
	/****
	@Name		loadFeature
	@Namespace	Eanyee
	@Type		Function
	@Return		{Object}	(with a field "isComplete".the client can regular watch this field to find the script is completed)
	@Param		[featureName]	{String}	$Must (the feature name.This name will convert to an urlif it is not)
	@Param		[callback]	{Function}	(this function will be invoked while the feature is avialible)
	
	@Remarks	we can use this function to load script or frameworks featue 
	****/
	var loadFeature = function(featureName,callback){
		
		var name = featureName;
		featureName = convertFeatureName(featureName);

		var fts = Eanyee.Features;
		var ft = fts[featureName];
		if (ft){callback(ft); return {isComplete:true};}
		var ret = {isComplete:false};
		
		var script = document.createElement("script");
		script.type = "text/javascript";
		script.src = featureName;
		script.onreadystatechange = script.onload = function(e){
			
			if (script.readyState && script.readyState!=='loaded') return;
			
			var ft = fts[featureName];
			if (!ft) fts[featureName] = ft = script;
			ret.isComplete = true;
			if(callback)callback(featureName,ft,name);
		}
		script.language="JavaScript";

		var head,doc,body;
		try{
			head = document.getElementsByTagName("head")[0];
		}catch(e){
			doc = document.documentElement;
			body = document.body;
		}
		if (head) head.appendChild(script);
		else{
			try{
				if(doc.firstChild) doc.insertBefore(script,firstChild);
				else doc.appendChild(script);
			}catch(e){


				try{
					if (body.firstChild)body.insertBefore(script,body.firstChild);
					else body.appendChild(script);
				}catch(e){
					throw "Eanyee:can't load feature check your browser!";
				}
			}
		}
		return ret;
	}

	var addFeature = function(featureName,featureBody){
		var fts = Eanyee.Features;
		var ft;
		if (featureBody){
			ft = featureBody();
		}
		ft = ft || featureBody || true;
		fts[convertFeatureName(featureName)] = ft;
		return ft;
	}

	var base=function(){
			//alert(arguments.callee.caller.virtual);
		return arguments.callee.caller._$vfp.apply(this,arguments);
	}
	
	var registerClass = function(cls,interfaces){
		if (typeof(cls)==='string'){
			var clsNm = cls;
			eval("cls = " + cls);
			cls.toString = function(){return clsNm;}
			if (!cls.prototype.toString)
				cls.prototype.toString = function(){return "Object<" + clsName + ">";}
		}
		var ifcs = arguments;
		var proto = cls.prototype;
		for(var i=1;i<ifcs.length;i++){
			var ifc = ifcs[i];
			var iproto = ifc.prototype;
			
			for(var n in iproto){
				var ifn = iproto[n];var fn = proto[n];
				if (fn===undefined){proto[n] = ifn;}
				else if (ifn.virtual && !fn.virtual){
					fn.virtual = true;fn._$vfp = ifn;
					proto.$base = base;
				}
			}
		}
		return cls;
	}

	
	var enums = function(){
		var args = arguments;
		var ret = {};
		var s = [];
		for(var i=0;i<args.length;i++){
			var n = args[i];
			ret[n] = n; 
			s.push(n);
		}
		var b = s.join(',');s = undefined;
		ret.toString = function(){return "{" + b + "}";};
		return ret;
	}

	var delegate = function(obj,func){
		var name;
		if (typeof func === 'string'){
			name = func;
			func = obj[name];
		}
		var ret = function(){
			return func.apply(obj,arguments);
		}
		if (name)obj[name] = ret;
		return ret;
	}
	var extend = function(target,src){
		for(var n in src){target[n] = src[n];}
		return target;
	}
	
	window.Eanyee = {
		'version' : "0.1 beta",
		'libUrls' : 'http://libUrl.com/',
		'agentUrl' : null,
		'Features' : {},
		'connect' : connect,
		'loadFeature' : loadFeature,
		'addFeature' : addFeature,
		'registerClass' : registerClass,
		'makeEnum' : enums,
		'delegate' : delegate,
		'extend' : extend
	}
	
}());
