/**
 * @author   Ivan Andonov
 * @email    ivan.andonov[at]design[dot]bg
 *
 * @require  init dbg.ShortcutCall
 *           use  dbg.Utils, dbg.Objects, dbg.Delegate
 * @optional dbg.Debug
 **/

dbg.extend({

	Ajax : dbg.Class.create('Ajax', dbg).extend({
	
		// CONSTRUCTOR
		initialize : function() {
		
			// PRIVATE PROPS
			this.requestObj = null; // current request object
			
			this.queue = []; // waiting requests
			
			this.loading = false;
			
			// PUBLIC METHODS
			this.get = function(link, props, onSuccess, onError, leavePrev, useCache) {
				//$log(this+'.get link='+link+' leavePrev='+leavePrev+' useCache='+useCache);
				this.addRequest(link, props, onSuccess, onError, 'GET', null, leavePrev, useCache);
			};
			
			this.post = function(link, props, onSuccess, onError, encoding, leavePrev, useCache) {
				//$log(this+'.get link='+link+' leavePrev='+leavePrev+' useCache='+useCache);
				this.addRequest(link, props, onSuccess, onError, 'POST', encoding, leavePrev, useCache);
			};
			
			this.cancel = function() {
				//$log(this+'.cancel loading='+this.loading+' requestObj='+this.requestObj);
				if (this.loading && this.requestObj != null) {
					//this.requestObj.request.onreadystatechange = null;
					this.requestObj.request.onreadystatechange = function() {};
					this.requestObj.request.abort();
					this.requestObj = null;
				}
			};
			
			// PRIVATE METHODS
			this.addRequest = function(link, props, onSuccess, onError, method, encoding, leavePrev, useCache) {
				//$log(this+'.addRequest link='+link+' method='+method+' encoding='+encoding+' leavePrev='+leavePrev+' useCache='+useCache);
				var obj = {
					link:link,
					props:props,
					onSuccess:onSuccess,
					onError:onError,
					method:method,
					encoding:encoding,
					useCache:useCache
				};
				// (useCache ? '' : (link.indexOf('?') == -1 ? '?' : '&')+'cache='+(new Date().getTime()));
				if (this.loading && leavePrev) {
					this.queue.push(obj);
				} else {
					if (this.loading) this.cancel();
					this.loading = true;
					this.doRequest(obj);
				}
				return true;
			};
			
			this.doRequest = function(obj) {
				$log(this+'.doRequest link='+obj.link+' props='+this.classInstance.propsToString(obj.props)+' method='+obj.method);
				this.requestObj = obj;
				this.requestObj.request = this.classInstance.getAjax();
				var req = this.requestObj.request;
				req.onreadystatechange = $d(this, 'onreadystatechange');
				//alert('req.onreadystatechange'+req.onreadystatechange);
				if (!obj.useCashe && obj.method != 'POST') {
					var time = new Date().getTime();
					if (obj.props.cache != null) {
						obj.props['cache'+time] = time;
					} else {
						obj.props.cache = time;
					}
				}
				var props = this.classInstance.propsToString(obj.props, true);
				switch (obj.method) {
					case 'GET':
						if (props.length) obj.link += (obj.link.indexOf('?') == -1 ? '?' : '&')+props;
						req.open(obj.method, obj.link, true);
						dbg.Utils.isIE() ? req.send() : req.send(null);
						break;
					case 'POST':
						req.open(obj.method, obj.link, true);
						//req.setRequestHeader('Content-Encoding', 'windows-1251');
						//req.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT' );
						req.setRequestHeader('Method', 'POST ' + obj.link + ' HTTP/1.1');
						req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
						req.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset='+(obj.encoding || 'UTF-8'));
						req.send(props);
						break;
				}
			};
			
			this.onreadystatechange = function() {
				$log(this+'.onreadystatechange readyState='+this.requestObj.request.readyState);
				if (this.requestObj == null) return;
				var reqObj = this.requestObj;
				var req = reqObj.request;
				if (req.aborted) return;
				if (reqObj != null && req.readyState == 4) {
					delete req['onreadystatechange'];
					this.requestObj = null;
					this.loading = false;
					var haveError = false;
					try {
						if ((req.status == 200 || (util.isLocal() && req.status == 0))) {
							if (typeof(reqObj.onSuccess)=='function') {
								reqObj.onSuccess(req, reqObj);
							}
						} else if (typeof(reqObj.onError)=='function') {
							haveError = true
						}
					} catch(er) {
						haveError = true;
					}
					if (haveError && typeof(reqObj.onError)=='function') {
						reqObj.onError(req, reqObj);
					}
					reqObj.xmlHttpRequest = null;
					// call next
					if (this.queue.length) {
						this.doRequest(this.queue.shift());
					} else {
						this.loading = false;
					}
				}
			};
			
		},
		
		// STATIC METHODS
		/**
		* Static method which check for ajax availability
		* if ajax is not supported the onclick will return true and the href will be executed
		*
		* usage:
		* 		link.onclick = $d(dbg.Ajax, 'call', $d(target, 'method'));
		*       or
		* 		onclick="$d(dbg.Ajax, 'call', $d(target, 'method')).apply(null, arugments)"
		*/
		call : function(callback, event) {
			if (!this.available) {
				return true;
			}
			if (callback) {
				$delegate(window, callback, event)();
			}
			return false;
		},
		
		getAjax : function() {
			var req = false;
			if (window.XMLHttpRequest) {
				try {
					req = new XMLHttpRequest();
				} catch(e) {
					req = false;
				};
			} else if (window.ActiveXObject) {
				try {
					req = new ActiveXObject('Msxml2.XMLHTTP');
				} catch(e) {
					try {
						req = new ActiveXObject('Microsoft.XMLHTTP');
					} catch(e) {
						req = false;
					};
				};
			};
			return req;
		},
		
		propsToString : function(props, encode) {
			//$log('propsToString props='+props+' encode='+encode);
			var str = '';
			var tmp_str = '';
			var type;
			for (var prop in props) {
				type = typeof(props[prop]);
				switch (type.toLowerCase()) {
					case 'string':
					case 'number':
						str += (str.length ? '&' : '')+this.formatVar(prop, props[prop], encode);
						break;
					case 'object':
						tmp_str = this.formatObject((encode ? encodeURIComponent(prop) : prop), props[prop], encode, props[prop] instanceof Array);
						if (tmp_str.length) {
							str += (str.length ? '&' : '')+tmp_str;
						}
				}
			}
			return str;
		},
		
		formatVar : function(prop, value, encode, onlyValue) {
			//$log('formatVar prop='+prop+' value='+value+' encode='+encode+' onlyValue='+onlyValue);
			return encode ? (onlyValue ? prop : encodeURIComponent(prop))+'='+encodeURIComponent(value) : prop+'='+value;
		},
		
		formatObject : function(prop, props, encode, isArray) {
			//$log('formatObject prop='+prop+' props='+props+' encode='+encode+' isArray='+isArray);
			var type;
			var str = '';
			for (var prop in props) {
				type = typeof(props[prop]);
				switch (type.toLowerCase()) {
					case 'string':
					case 'number':
						str += (str.length ? '&' : '')+this.formatVar(prop+(isArray ? '[]' : '['+(encode ? encodeURIComponent(prop) : prop)+']'), props[prop], encode, true);
						break;
					case 'object':
						str += (str.length ? '&' : '')+this.formatObject(prop+(isArray ? '[]' : '['+(encode ? encodeURIComponent(prop) : prop)+']'), props[prop], encode, true, props[prop] instanceof Array);
				}
			}
			return str;
		}
		
	}, true) // rewrite
	
});

// STATIC PROP
dbg.Ajax.available = !!dbg.Ajax.getAjax();

// create shortcuts
$shortcut(['ajax', 'ajaxCall'], dbg.Ajax, 'call');