//=========================================================
//	Browser Features
//=========================================================

var Browser = {
	IE:     !!(window.attachEvent && !window.opera),
	Opera:  !!window.opera,
	WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
	Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
	MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
};

//=========================================================
//	Basic Function Calls
//=========================================================

function $(id) {
	return document.getElementById(id);
}

function $F(id) {
	return document.getElementById(id).value;
}

//=========================================================
//	Extensions of Object, Array, and Function
//=========================================================

// Object.extend
Object.extend = function(destination, source) {
	for (var property in source) {
		destination[property] = source[property];
	}
	return destination;
}

Object.extend(Object, {
	keys: function(object) {
		var keys = [];
		for (var property in object)
		keys.push(property);
		return keys;
	},

	values: function(object) {
		var values = [];
		for (var property in object)
		values.push(object[property]);
		return values;
	},
	
	toQueryString: function(object) {
		var params = [];
		for (var key in object) {
			params.push(encodeURI(key) + "=" + encodeURI(object[key]));
		}
		return params.join("&");
	},
	
	clone: function(object) {
		return Object.extend({ }, object);
	},

	isElement: function(object) {
		return object && object.nodeType == 1;
	},

	isArray: function(object) {
		return object && object.constructor === Array;
	},

	isFunction: function(object) {
		return typeof object == "function";
	},

	isString: function(object) {
		return typeof object == "string";
	},

	isNumber: function(object) {
		return typeof object == "number";
	},

	isUndefined: function(object) {
		return typeof object == "undefined";
	}
});


// Array.prototype.concat
if (Browser.Opera) {
	Array.prototype.concat = function() {
		var array = [];
		for(var i=0, length=this.length; i<length; i++) array.push(this[i]);
		for(var i=0, length=arguments.length; i<length; i++) {
			if(arguments[i].constructor == Array) {
				for(var j=0, arrayLength=arguments[i].length; j<arrayLength; j++)
				array.push(arguments[i][j]);
			} else {
				array.push(arguments[i]);
			}
		}
		return array;
	}
}

// Array.prototype.indexOf
if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item) {
	for (var i=0, length=this.length; i < length; i++) {
		if (this[i] === item) return i;
	}
	return -1;
};


// Function.prototype.bind
Function.prototype.bind = function(object) {
	var __method = this;
	return function() {
		return __method.apply(object, arguments);
	}
}


// Function.prototype.bindAsEventListener
Function.prototype.bindAsEventListener = function(object) {
	var __method = this;
	return function(event) {
		return __method.apply(object, [(event || window.event)].concat(arguments));
	}
}



//=========================================================
//	Cross Browser Utils
//=========================================================

var Try = {
	these: function() {
		var returnValue;
		
		for (var i = 0, length = arguments.length; i < length; i++) {
			var lambda = arguments[i];
			try {
				returnValue = lambda();
				break;
			} catch (e) {}
		}
		
		return returnValue;
	}
}


//=========================================================
//	Object Oriented Utils
//=========================================================

/* Based on PrototypeJS 1.6.0 */
var Class = {
	create: function() {
		var parent = null, properties = {};
		if (arguments.length > 0) {
			if (Object.isFunction(arguments[0])) {
				parent = arguments[0];
				if (arguments.length > 1)  properties = arguments[1];
			} else {
				properties = arguments[0];
			}
		}
		
		function klass() {
			this.initialize.apply(this, arguments);
		}
		
		Object.extend(klass, Class.Methods);
		klass.superclass = parent;
		klass.subclasses = [];
		
		if (parent) {
			var subclass = function() { };
			subclass.prototype = parent.prototype;
			klass.prototype = new subclass;
			parent.subclasses.push(klass);
		}
		
		klass.addMethods(properties);
		
		if (!klass.prototype.initialize)
			klass.prototype.initialize = function() {};

		klass.prototype.constructor = klass;

		return klass;
	}
};

Class.Methods = {
	addMethods: function(source) {
		var ancestor   = this.superclass && this.superclass.prototype;
		var properties = Object.keys(source);

		if (!Object.keys({ toString: true }).length)
			properties.push("toString", "valueOf");

			for (var i = 0, length = properties.length; i < length; i++) {
				var property = properties[i], value = source[property];
				if (ancestor && Object.isFunction(value) &&
					value.argumentNames().first() == "$super") {
				var method = value, value = Object.extend((function(m) {
					return function() { return ancestor[m].apply(this, arguments) };
				})(property).wrap(method), {
					valueOf:  function() { return method },
					toString: function() { return method.toString() }
				});
			}
			this.prototype[property] = value;
		}

		return this;
	}
};

//=========================================================
//	AjajRequest
//=========================================================

var AjajRequest = Class.create();
	
AjajRequest.List = [];
AjajRequest.CUR_ID = 0;

AjajRequest.getHtmlHead = function() {
	try {
		return document.getElementsByTagName("head").item(0);
	} catch (e) {
		return null;
	}
}

AjajRequest.onStateChange = function(id, data) {
	var  ajaj = AjajRequest.List[id];
	if (ajaj) {
		ajaj.state = 1;
		ajaj.data = data;
	}
}

Object.extend(AjajRequest.prototype, {
	initialize: function(url, options) {
		var defaults = {
			timeout: 5000,
			onComplete: null,
			onError: null
		}
		this.options = Object.extend(defaults, options || {});
		this.id = "ajaj" + AjajRequest.CUR_ID++;
		AjajRequest.List[this.id] = this;
		this.state = 0;
		this.data = null;
		
	    try {
			this.element = document.createElement("script");
			// this.element.setAttribute("id", this.id);
			this.element.setAttribute("type", "text/javascript");
			this.element.setAttribute("charset", "utf-8");
			this.element.setAttribute("src", url + ((url.indexOf("?")!=-1) ? "&" : "?") + "r=" + (new Date()).getTime() + "&ajajId=" + this.id);
			
			AjajRequest.getHtmlHead().appendChild(this.element);
			
			this.escapedTime = 0;
			this.timer = setInterval(this.onTimer.bind(this), 100);
			
	    } catch (e) {
	    	if (this.options.onError) this.options.onError();
	    }
	},
	
	onTimer: function() {
		if (this.state != 0) {
			clearInterval(this.timer);
			AjajRequest.getHtmlHead().removeChild(this.element);
			AjajRequest.List[this.id] = null;
			if (this.options.onComplete) this.options.onComplete(this.data);
		} else {
			this.escapedTime += 100;
			if (this.escapedTime > this.options.timeout) {
				clearInterval(this.timer);
				AjajRequest.getHtmlHead().removeChild(this.element);
				AjajRequest.List[this.id] = null;
				if (this.options.onError) this.options.onError();
			}
		}
	}
});
