function MCP() {
	
	/*
	* Provides basic XMLHttpRequest method xhr w/ supplied config for callbacks, endpoint, data, etc
	*/
	var _xhr = {
		xhr:function(cfg) {
			
			/*
			* Instantiate XMLHTTPRequest
			*/
			var xhr = XMLHttpRequest?XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP");
			
			/*
			* Set target endpoint
			* 
			* non-async request won't work with FF
			*/
			xhr.open(cfg.method,cfg.endpoint,cfg.sync === false?false:true);
			
			/*
			* Set content type
			* 
			* default: text/html
			*/
			xhr.setRequestHeader('Content-Type',(cfg.content_type?cfg.content_type:'application/x-www-form-urlencoded'));
			
			/*
			* Mixin placeholders for non-existing callbacks
			*/
			if(!cfg.callback.transacting) cfg.callback.transacting = function(xhr) { };
			if(!cfg.callback.sent) cfg.callback.sent = function(xhr) { };
			if(!cfg.callback.connected) cfg.callback.connected = function(xhr) { };
			if(!cfg.callback.instantiated) cfg.callback.instantiated = function(xhr) { };
			
			/*
			* Set default timeout
			*
			* default: 10 seconds
			*/
			cfg.timeout = cfg.timeout?cfg.timeout:15000;
			
			/*
			* Timeout exception monitor
			*/
			if(cfg.timeout != 0) {
				var to = function() {
					return setTimeout(function() {				
						/*
						 * Abort current request
						 */
						xhr.abort();
				
						/*
						 * Call complete w/ timeout error code
						 */
						cfg.callback.complete({xhr:xhr,error:4,data:null,fault:'timeout'});
					},cfg.timeout);
				};
			}
			
			/*
			* Set-up ready state listeners
			*/
			xhr.onreadystatechange = function() {
			
				switch(xhr.readyState) {
				
					case 4:	
					
						if(cfg.timeout != 0) clearTimeout(to);
					
						var response = {xhr:xhr};
						
						/*
						* Error codes:
						* 0 - success
						* 1 - error: hard: permission issue
						* 2 - error: hard: not found
						* 3 - warning: transient : continue cautiously
						* 4 - timeout (see timeout above)
						*/
						switch(xhr.status) {
							case 200:		
							case 302: // Found but redirected
								response.error = 0;
								response.fault = '';
								break;
						
							case 401: // Unauthorized
							case 403: // Forbidden
								response.error = 1;
								response.fault = xhr.readyState + ': ' + xhr.statusText;
								response.data = null;
								break;
							
							case 404: // Not Found
								response.error = 2;
								response.fault = '' + xhr.readyState;
								response.data = xhr.readyState + ': ' + xhr.statusText;
								break;
						
							case 301: // Moved permanently
							case 305: // Request must use a proxy
							default:
								response.error = 3;
								response.fault = xhr.readyState + ': ' + xhr.statusText;
								break;
						}
						
						/*
						* Call complete handler
						*/
						cfg.callback.complete(response);
						
						/*
						* Clean-up to prevent memory leaks
						*/
						xhr.onreadystatechange = function() { };
						
						
						break;						
					case 3:
						cfg.callback.transacting(xhr);
						break;					
					case 2:
						to = to(); // start timeout timer
						cfg.callback.sent(xhr);
						break;
					case 1:
						cfg.callback.connected(xhr);
						break;
					case 0:
						cfg.callback.instantiated(xhr);
						
					default:
				}
			};
			
			/*
			* Send request
			*/
			xhr.send(cfg.data);
		
		}
	};
	
	/*
	* Provides methods to interact directly with MCP data access and modules
	*/
	var _datasource = {
			
		/*
		* Interact directly w/ DAOs
		*/
		dao:function(cfg) {
			
			/*
			* xhr config
			*/
			var xhr = {};
			
			/*
			* Create base endpoint with package and method
			*/
			xhr.endpoint = '/dao.php?pkg='+cfg.pkg+'&method='+cfg.method;
			
			/*
			* Add the response format if it exists
			*/
			if(cfg.format) xhr.endpoint+='&format='+cfg.format;
			
			/*
			* Add arguments
			*/
			if(cfg.args) {
				for(var i=0;i<cfg.args.length;i++) {
					xhr.endpoint+='&args[]=' + cfg.args[i];
				}
			}
			
			/*
			* Change content type for xml request
			*/
			if(cfg.format == 'xml') {
				xhr.content_type = 'text/xml';
			}
			
			/*
			* Mixin complete handler to handle error gracefully
			*/
			xhr.callback = {
				complete:function(response) {
					switch(response.error) {
						case 0: // ok
						case 3: // redirect
							
							/*
							* Convert JSON into object literal 
							*/
							var data = eval('('+response.xhr.responseText+')');
							
							response.fault = data.fault;
							response.error = data.error;
							response.data = data.data;
							
							cfg.callback.complete(response);
							break;
						
						case 1: // authorization error
						case 2: // not found
						case 4: // request timed out
						default:
							response.data = null;
							if(cfg.callback.error) cfg.callback.error(response);
					};
				}
			};
			
			/*
			* Mixin other ready state callbacks
			*/
			if(cfg.callback.transacting) xhr.callback.transacting = cfg.callback.transacting;
			if(cfg.callback.sent) xhr.callback.sent = cfg.callback.sent;
			if(cfg.callback.connected) xhr.callback.connected = cfg.callback.connected;
			if(cfg.callback.instantiated) xhr.callback.instantiated = cfg.callback.instantiated;
			
			/*
			* API is compatible with GET and POST - to keep things simple though lets us GET
			*/
			xhr.method = 'GET';
			
			/*
			* Make xhr request
			*/
			_xhr.xhr(xhr);
		
		}
	
		/*
		* Retrive modules HTML w/ blank template for injection into existing DOM structure
		*/
		,mod:function(cfg) {
			
			/*
			* xhr config 
			*/
			var xhr = [];
			
			/*
			* Create endpoint 
			*/
			xhr.endpoint = cfg.endpoint;
			
			/*
			* Add arguments to endpoint
			*/
			if(cfg.args) {
				for(var i=0;i<cfg.args.length;i++) {
					xhr.endpoint+='/' + cfg.args[i];
				}
			}
			
			/*
			* Mixin complete handler to handle error gracefully
			*/
			xhr.callback = {
				complete:function(response) {
					switch(response.error) {
						case 0: // ok
						case 3: // redirect
							response.data = response.xhr.responseText;
							cfg.callback.complete(response);
							break;
						
						case 1: // authorization error
						case 2: // not found
						case 4: // request timed out
						default:
							response.data = null;
							if(cfg.callback.error) cfg.callback.error(response);
					};
				}
			};
			
			/*
			* Mixin other ready state callbacks
			*/
			if(cfg.callback.transacting) xhr.callback.transacting = cfg.callback.transacting;
			if(cfg.callback.sent) xhr.callback.sent = cfg.callback.sent;
			if(cfg.callback.connected) xhr.callback.connected = cfg.callback.connected;
			if(cfg.callback.instantiated) xhr.callback.instantiated = cfg.callback.instantiated;
			
			/*
			* Always POST 
			*/
			xhr.method = 'POST';
			
			/*
			* Add POST data
			*/
			if(cfg.data) xhr.data = cfg.data;
			
			/*
			* Make xhr request
			*/
			_xhr.xhr(xhr);
			
		}	
	};
	
	return {
		dao:function(cfg) {
			_datasource.dao(cfg);
		}
		,xhr:function(cfg) {
			_xhr.xhr(cfg);
		}
		,mod:function(cfg) {
			_datasource.mod(cfg);
		}
	};

};
