// Extend prototypes

if(!Array.prototype.push) {
	Array.prototype.push = function(o) {
		this[this.length] = o;
	}
}

Function.prototype.bind = function(o) {
	if(!window.__objs) {
		window.__objs = [];
		window.__funcs = [];
	}

	var objId = o.__oid;
	if(!objId)
		__objs[objId = o.__oid = __objs.length] = o;

	var me = this;
	var funcId = me.__fid;
	if(!funcId)
		__funcs[funcId = me.__fid = __funcs.length] = me;

	if(!o.__closures)
		o.__closures = [];

	var closure = o.__closures[funcId];
	if(closure)
		return closure;

	o = null;
	me = null;

	return __objs[objId].__closures[funcId] = function() {
		return __funcs[funcId].apply(__objs[objId], arguments);
	};
}

Object.extend = function(destination, source) {
	for(property in source) {
		destination[property] = source[property];
	}
	return destination;
}

Object.prototype.extend = function(o) {
	return Object.extend.apply(this, [this, o]);
}

var Class = {
	create: function() {
		return function() {
			if(typeof this.initialize == "function")
				this.initialize.apply(this, arguments);
		}
	}
}

if(!window.addNamespace) {
	window.addNamespace = function(ns) {
		var nsParts = ns.split(".");
		var root = window;

		for(var i=0; i<nsParts.length; i++) {
			if(typeof root[nsParts[i]] == "undefined")
				root[nsParts[i]] = {};
			root = root[nsParts[i]];
		}
	}
}

// Event handling methods

function addEvent(o, evType, f, capture) {
	if(o.addEventListener) {
		o.addEventListener(evType, f, capture);
		return true;
	} else if (o.attachEvent) {
		var r = o.attachEvent("on" + evType, f);
		return r;
	} else {
		// alert("Handler could not be attached");
	}
} 

function removeEvent(o, evType, f, capture) {
	if(o.removeEventListener) {
		o.removeEventListener(evType, f, capture);
		return true;
	} else if (o.detachEvent) {
		var r = o.detachEvent("on" + evType, f);
		return r;
	} else {
		// alert("Handler could not be removed");
	}
}

// Browser related properties

addNamespace("MS.Browser");

MS.Browser.isIE = (window.navigator.appName.toLowerCase().indexOf('explorer') != -1 || window.navigator.appName.toLowerCase().indexOf('msie') != -1 );


// Debugging

addNamespace("MS.Debug");

MS.Debug.enabled = false;
MS.Debug.trace = function(s){}


// AJAX.NET

addNamespace("CJAX");

CJAX.toJSON = function(o) {

	if(o == null)
		return "null";

	switch(o.constructor) {
		
		case String:
			var s = o; // .encodeURI();
			s = '"' + s.replace(/(["\\])/g, '\\$1') + '"';
			s = s.replace(/\n/g,"\\n");
			s = s.replace(/\r/g,"\\r");
			return s;
		
		case Array:
			var v = [];
			for(var i=0; i<o.length; i++)
				v.push(CJAX.toJSON(o[i])) ;
			return "[" + v.join(", ") + "]";
		
		case Number:
			return isFinite(o) ? o.toString() : CJAX.toJSON(null);
	
		case Boolean:
			return o.toString();
			
		case Date:
			var d = new Object();
			d.__type = "System.DateTime";
			d.Year = o.getUTCFullYear();
			d.Month = o.getUTCMonth() +1;
			d.Day = o.getUTCDate();
			d.Hour = o.getUTCHours();
			d.Minute = o.getUTCMinutes();
			d.Second = o.getUTCSeconds();
			d.Millisecond = o.getUTCMilliseconds();
			d.TimezoneOffset = o.getTimezoneOffset();
			return AjaxPro.toJSON(d);
	
		default:
			if(o["toJSON"] != null && typeof o["toJSON"] == "function")
				return o.toJSON();
				
			if(typeof o == "object") {
				var v=[];
				
				for(attr in o) {
					if(typeof o[attr] != "function")
						v.push('"' + attr + '": ' + CJAX.toJSON(o[attr]));
				}

				if(v.length>0)
					return "{" + v.join(", ") + "}";
				else
					return "{}";		
			}
			return o.toString();
	}
}

function createResponse(resp) {
		var r = new Object();
		r.error = null;
		r.value = null;
		r.version = null;		
		eval("r.value = " + resp.responseText + ";");		
		r.version = r.value.version;	
		r.value = r.value.value;	
		//r.value = eval(resp.responseText);
		return r;
}

CJAX.Base = function() {};
CJAX.Request = Class.create();
CJAX.Request.prototype = (new CJAX.Base()).extend({
	initialize: function(url) {
		this.url = url;		
		this.callback = null;
		
		this.timeoutPeriod = 5000;	// 5 seconds
	},	
	invoke: function(method, data, callback, version) {
		var async = typeof callback == "function";
		var json = CJAX.toJSON(data) + "\r\n";
		var hasVersion = typeof version != "undefined";				
		
		var opt = {    		
   			method: 'post',    		
    		postBody: json,
    		asynchronous: async,
    		onComplete: (async) ? 
				function(result){ 
					callback(createResponse(result));
				} 
				: 
				null,
			requestHeaders: ((hasVersion) ? ["CJAX-Method", method, "Version", version] :
			            ["CJAX-Method", method]),
    		// Handle 404
    		on404: function(t) {
        		alert('Error 404: location "' + t.statusText + '" was not found.');
    		},
			onError: function(t) {
        		var r = new Object();
				r.value = t;
				r.error = t;
				
				callback(r);
    		},
    		// Handle other errors
    		onFailure: function(t) {
        		alert('Error ' + t.status + ' -- ' + t.statusText);
    		}
		}

		var req = new Ajax.Request(this.url, opt);	
		
		if(!async) {
			return createResponse(req.transport);
		}
		
		return true;	
	}
});

addNamespace("CJAX.Web");

CJAX.Web.NameValueCollection = function()
{
	this.__type = "System.Collections.Specialized.NameValueCollection";

	this.add = function(key, value) {
		if(this[key] == null) {
			this[key] = value;
		}
	}
	
	this.getKeys = function() {
		var keys = [];
		
		for(key in this)
			if(typeof this[key] != "function")
				keys.push(key);
			
		return keys;
	}
	
	this.getValue = function(key) {
		return this[key];
	}
	
	this.toJSON = function() {
		var o = this;
		o.toJSON = null;
		delete o.toJSON;
		return CJAX.toJSON(o);
	}
}