function PCSCallback(CallbackId){
	
	this.CallbackId = CallbackId;
	this.CallbackErrorFunction;
	this.AfterCallbackErrorFunction;
	this.Target=null;
	this.CallbackFunction=null;
	this.Context=null;
	this.Method=null;
	this.BypassLoaders=false;
	this.Loaders = new PCSCallbackLoaders();
	this.Timer = new PCSCallbackTimer(CallbackId);
			
	this.DefaultTarget = document.forms[0].id;
	this.DefaultContext = 'GridMain';
	this.DefaultCallbackFunction = null;
	this.Synchronous=false;
	
	this.PageUrl = location.href;
	this.Message = function(Message){
		this.Loaders.Message=Message;
		return this;
	}
	this.Constructor = function(Target,CallbackFunction,Context,Synchronous,BypassLoaders,Message){
		this.Target = (Target ? Target : this.DefaultTarget);
		this.CallbackFunction = CallbackFunction;
		this.Context = (Context ? Context : this.DefaultContext);
		this.Synchronous = (Synchronous ? true : false);
		this.BypassLoaders=BypassLoaders;
		this.Loaders.Message=(Message ? Message : 'Refreshing...');
		return this;
	}
}
function PCSCallbackLoaders(){
	this.Message = 'Refreshing...';
	this.Controls = new Array();
}
PCSCallbackLoaders.prototype.Add=function(){
	for(var i=0;i<arguments.length;i++){
		if(typeof(arguments[i]) == 'string'){
			this.Controls[this.Controls.length] = window[arguments[i]];
		}else{
			if(typeof(arguments[i]) != 'undefined'){
				this.Controls[this.Controls.length] = arguments[i];
			}
		}
	}
}
PCSCallbackLoaders.prototype.Contains=function(loader){
	var bfound = false;
	for(var i=0;i<this.Controls.length;i++){
		if(this.Controls[i].ControlId == loader.ControlId){
			return true;
		}
	}
	return false;
}
PCSCallbackLoaders.prototype.Remove=function(obj){
	for(var i=0;i<arguments.length;i++){
		if(this.Controls[i] == obj){
			this.Controls[i]=null;
			break;
		}
	}
}
PCSCallbackLoaders.prototype.RemoveAll=function(){
	for(var i=0;i<this.Controls.length;i++){
		this.Controls[i] = null;
	}
	this.Controls = new Array();
}
PCSCallbackLoaders.prototype.Show=function(message){
	if(!message) message = this.Message;
	for(var i=0;i<this.Controls.length;i++){
		if(this.Controls[i]){
			this.Controls[i].Show(message);
		}
	}
}
PCSCallbackLoaders.prototype.Hide=function(){
	for(var i=0;i<this.Controls.length;i++){
		if(this.Controls[i]) this.Controls[i].Hide();
	}
}
function PCSCallbackTimer(CallbackId){
	this.TimerID=null;
	this.Interval = 1000;
	this.CallbackFunction=null;
	this.CallbackId=CallbackId;
	this.Target = CallbackId;
	this.BypassLoaders=false;
	this.BeforeCallbackFunction=null;
}
PCSCallbackTimer.prototype.Constructor=function(Target,Interval,CallbackFunction,BeforeCallbackFunction,BypassLoaders){
	this.Target = (!Target ? this.CallbackId : Target);
	this.Interval = Interval;
	this.CallbackFunction = CallbackFunction;
	this.BeforeCallbackFunction=BeforeCallbackFunction;
	this.BypassLoaders=(!BypassLoaders ? false : BypassLoaders);
	return this;
}
PCSCallbackTimer.prototype.Start=function(){
	var t = this;
	this.TimerID = setTimeout(function()
	{
		if(t.BeforeCallbackFunction != null && typeof(t.BeforeCallbackFunction) != 'undefined'){
			if(t.BeforeCallbackFunction()) return;
		}
		window[t.CallbackId].Constructor(t.Target,t.CallbackFunction,t.CallbackId,false,t.BypassLoaders).AjaxCallback(t.CallbackId)
	},this.Interval)
}
PCSCallbackTimer.prototype.Stop=function(){
	clearTimeout(this.TimerID);
	this.TimerID = null;
}
PCSCallback.prototype.GetContext=function(){
	return (this.Context ? this.Context.toString() : this.DefaultContext.toString());
}
PCSCallback.prototype.GetTarget=function(){
	return (this.Target ? this.Target.toString() : this.DefaultTarget.toString());
}
PCSCallback.prototype.GetCallbackFunction=function(){
	var alternate = null;
	if(typeof(refreshNav) != 'undefined' && !this.Synchronous) alternate = refreshNav;
	return (this.CallbackFunction != null ? this.CallbackFunction : (this.DefaultCallbackFunction != null ? this.DefaultCallbackFunction : alternate));
}
PCSCallback.prototype.AjaxCallback=function(){
	var re = new RegExp('\\x2B', 'g');
	var eventArgs = new Array(arguments.length);
	var callbackFunction=this.GetCallbackFunction();
	var context = this.GetContext();
	var target = this.GetTarget();
	var sync = this.Synchronous;
	for (i=0;i<arguments.length;i++){
		eventArgs[i] = arguments[i];
	}
	var eventArgument = eventArgs.join(String.fromCharCode(123));
	postData = "__SCRIPTCALLBACKID=" + target + "&__SCRIPTCALLBACKPARAM=" + escape(eventArgument).replace(re, "%2B");
	return this.doAjaxCallback(postData,callbackFunction,context,sync);
}
PCSCallback.prototype.MethodCallback=function(method,args,synchronous){

	var params=null;
	var re = new RegExp('\\x2B', 'g');
	var eventArgs = new Array(args.length);
	var callbackFunction=this.GetCallbackFunction();
	var context = this.GetContext();
	var target = this.GetTarget();
	//Is there a temporary override on sync
	if(this.Synchronous) synchronous = true;
		
	for(var i=0;i<args.length;i++){
		eventArgs[i]=args[i];
	}
	
	params = (eventArgs.length > 0 ? 'PCS_CallbackMethod_Param=' : '') + eventArgs.join('&PCS_CallbackMethod_Param=');
	params = params.replace(re, '%2B');
    postData = 'PCS_CallbackMethod=' + method + (params != '' ? '&' : '') + params + '&__SCRIPTCALLBACKID=' + target;
    return this.doAjaxCallback(postData,callbackFunction,context,synchronous);
    
}
PCSCallback.prototype.doAjaxCallback = function(postData, callbackFunction, context, synchronous) {

	var controlid = this.CallbackId;
	var usePost = (this.PageUrl.length + postData.length + 1 > 2067)
	var loader = null;

	var xmlRequest = null;

	if (window.XMLHttpRequest) { // FIREFOX
		xmlRequest = new XMLHttpRequest();
	} else if (window.ActiveXObject) { // IE old and new
		try {
			xmlRequest = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e) {
			xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
		}
	}

	if (!xmlRequest) {
		alert('Your browser does not currently support or allow AJAX!');
		return;
	}

	try {
		if (!this.BypassLoaders) {
			//add loaders for controls that this callback targets if the control has a loader
			if (typeof (window[context]) != 'undefined') {
				if (typeof (window[context].Loader) != 'undefined') {
					if (!this.Loaders.Contains(window[context].Loader)) {
						this.Loaders.Add(window[context].Loader);
					}
				}
			}
			this.Loaders.Show();
		}
	}
	catch (e) { }

	if (usePost) {
		if (!synchronous) xmlRequest.onreadystatechange = function() { window[controlid].OnCallbackComplete(xmlRequest, callbackFunction, context) };
		xmlRequest.open("POST", this.PageUrl, !synchronous);
		xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		xmlRequest.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT');
		xmlRequest.send(postData);
	} else {
		if (!synchronous) xmlRequest.onreadystatechange = function() { window[controlid].OnCallbackComplete(xmlRequest, callbackFunction, context) };
		if (this.PageUrl.indexOf("?") != -1) {
			xmlRequest.open("GET", this.PageUrl + "&" + postData, !synchronous);
		} else {
			xmlRequest.open("GET", this.PageUrl + "?" + postData, !synchronous);
		}
		xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		xmlRequest.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT');
		xmlRequest.send();
	}
	if (synchronous) {
		//Remove the temporary override
		this.Synchronous = false;
		return this.OnCallbackComplete(xmlRequest, this.CallbackFunction, context);
	}
}
PCSCallback.prototype.OnCallbackComplete = function(xmlRequest, callbackFunction, context) {

	if (xmlRequest.readyState != 4) return;
	try {
		var response = xmlRequest.responseText;
		var status = xmlRequest.getResponseHeader('PCS_CallbackStatus');
		//clear any existing errors.
		if (document.getElementById(PageProperties.NavigatorClientID + '_lblErrorMessage')) document.getElementById(PageProperties.NavigatorClientID + '_lblErrorMessage').innerText = '';
		if (document.getElementById(PageProperties.ToolbarClientID + '_lblErrp	orMessage')) document.getElementById(PageProperties.ToolbarClientID + '_lblErrorMessage').innerText = '';
		if (document.getElementById('lblErrorMessage')) document.getElementById('lblErrorMessage').innerText = '';
		if (status == '200') {
			if (callbackFunction) {
				eval(callbackFunction(response, context));
			} else {
				return response;
			}
		} else if (status == '998') {
			alert('Your session has timed out. You are being logged out.');
			doPostback('');
		} else if (status == '999') {
			//Two users on the same login or timeout, allow the postback to handle kicking
			doPostback('');
		}
		else {
			throw response;
		}
	}
	catch (e) {
		if (typeof (this.CallbackErrorFunction) == 'function') {
			eval(this.CallbackErrorFunction(typeof (e) == 'string' ? e : e.message, this.CallbackId));
		} else if (typeof (callbackError) == 'function') {
			callbackError(typeof (e) == 'string' ? e : e.message, this.CallbackId);
		}
		if (typeof (this.AfterCallbackErrorFunction) == 'function') {
			eval(this.AfterCallbackErrorFunction(typeof (e) == 'string' ? e : e.message, this.CallbackId))
		} else if (typeof (afterCallbackError) == 'function') {
			afterCallbackError(typeof (e) == 'string' ? e : e.message, this.CallbackId)
		}
		if (typeof (toggleAllLoaders) != 'undefined') {
			toggleAllLoaders(false);
		}
	}
	finally {
		xmlRequest.onreadystatechange = PCSCallbackDummy;
		xmlRequest = null;
		if (!this.BypassLoaders) this.Loaders.Hide();
		this.Constructor(this.DefaultTarget, null, this.DefaultContext, false, false);
	}
}
function PCSCallbackDummy(){
	// This must be here so we can set the xmlRequest.onreadystatechange to it otherwise there is no closure
	// and we have a huge memory leak.
}
