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 = new ActiveXObject("Microsoft.XMLHTTP");
    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.
}