﻿Type.registerNamespace("Infragistics.Web.UI");

/******************************************Callback Request Handler*********************************/
$IG.CallbackRequestHandler = function(manager, callbackObject, async)
{
	/// <summary>
	/// Handles a CallbackObject's request and resposne.
	/// </summary>
	var me = this;
	this._callbackObject = callbackObject;
	this._manager = manager;
	this._async = async;

	this._responseComplete = function()
	{
		if (me._request.readyState === 4 && me._request.status == "200")
		{
			window.clearTimeout(me._timerId);
			var response = me._request.responseText;
			if (response != null && response.length > 0)
			{
				var obj = Sys.Serialization.JavaScriptSerializer.deserialize(response)
				var viewState = document.getElementById("__VIEWSTATE");
				if (viewState)
					viewState.value = obj[0];
				var eventValidation = document.getElementById("__EVENTVALIDATION");
				if (eventValidation)
					eventValidation.value = obj[1];
				me._manager._requestCompleted(me, me._callbackObject, obj[2]);
				for (var i in obj[3])
				{
					var item = obj[3][i];
					if (typeof item != 'object')
						continue;
					var id = item[0];
					var ctrlObj = $find(id);
					if (ctrlObj && ctrlObj.dispose)
						ctrlObj.dispose();
					if (item[1])
						var x = eval(item[1]);
				}
			}
			else
			{
				me._timedOut();
			}

			me._callbackObject = null;
			me._manager = null;
			me._request = null;
		}
		else if (me._request.readyState === 4)
			me._manager._requestFailed(me, me._callbackObject);		
	}
}

$IG.CallbackRequestHandler.prototype =
{
	execute: function()
	{
		/// <summary>
		/// Executes a XmlHttpRequest to the server
		/// </summary>
		this._request = null;
		if (typeof XMLHttpRequest != "undefined")
			this._request = new XMLHttpRequest();
		else if (typeof ActiveXObject != "undefined")
		{
			try { this._request = ig_createActiveXFromProgIDs(["MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]); } catch (e) { }
		}

		if (this._request)
		{
			var ctl = this._manager._control;
			if (ctl)
			{
				/* get ajaxIndicator: do not use ctl._pi, because, child grid does not have it and */
				/* filters through ajaxIndicator of hierarchical grid */
				var pi = this._noPI ? null : ctl.get_ajaxIndicator;
				if (pi)
					pi = ctl.get_ajaxIndicator();
				/* show ajaxIndicator */
				if (pi)
					pi.show(ctl);
				/* set _posted flag (control in posted-state) */
				ctl._posted = true;
			}
			this._request.open(this._manager.getHttpVerb(), this._manager.getUrl(), this._async);
			this._request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			// This header will inform the server to compress the response, if browser supports compression
			this._request.setRequestHeader("X-AJAX", "true");
			this._request.onreadystatechange = this._responseComplete;
			this._timerId = window.setTimeout(Function.createDelegate(this, this._timedOut), this._manager.getTimeout());
			this._request.send(this._getArgs());
		}
	},

	_getArgs: function()
	{
		var form = this._manager._getForm();
		if (!form) return;

		/* Ensures that all Infragistics Controls have their PostData set. */
		if (typeof ig_controls == 'object')
			for (var id in ig_controls)
				ig_controls[id]._onIgSubmit();

		var count = form.elements.length;
		var element;
		for (var i = 0; i < count; i++)
		{
			element = form.elements[i];
			if (element.tagName.toLowerCase() == "input" && (element.type == "hidden" || element.type == 'password' || element.type == 'text' || ((element.type == "checkbox" || element.type == 'radio') && element.checked)))
				this._addCallbackField(element.name, element.value);
			else if (element.tagName.toLowerCase() == "textarea")
				this._addCallbackField(element.name, element.value);
			else if (element.tagName.toLowerCase() == "select")
			{
				var o = element.options.length;
				while (o-- > 0)
				{
					if (element.options[o].selected)
						this._addCallbackField(element.name, element.options[o].value);
				}
			}
		}

		var args = this._postdata + "__EVENTTARGET=&__EVENTARGUMENT=&__IGCallback_" + this._manager._control._id + "=";
		args += Sys.Serialization.JavaScriptSerializer.serialize(this._callbackObject._getServerData());
		return args;
	},

	_addCallbackField: function(name, value)
	{
		if (!this._postdata)
			this._postdata = "";
		this._postdata += name + "=" + this._encodeValue(value) + "&";
	},

	_encodeValue: function(uri)
	{
		if (encodeURIComponent != null)
			return encodeURIComponent(uri);
		else
			return escape(parameter);
	},

	_timedOut: function()
	{
		this._manager._requestFailed(this, this._callbackObject, true);
	}
};
$IG.CallbackRequestHandler.registerClass("Infragistics.Web.UI.CallbackRequestHandler");
/******************************************END Callback Request Handler*****************************/

/******************************************Control Callback Manager*********************************/
$IG.ControlCallbackManager = function(control)
{
	/// <summary>
	/// An object in charge of managin all Callbacks for an Infragistics.Web.UI.Control.
	/// </summary>
	this._control = control;
	this._httpVerb = "POST"
	this._async = true;
	this._timeout = 20000;
	this._url = this._getForm().action;

	this._currentRequests = 0;
	this._callbackQueue = [];
}

$IG.ControlCallbackManager.prototype =
{
	createCallbackObject: function(control)
	{
		/// <summary>
		/// Creates a new CallbackObject for the control.
		/// </summary>
		if (!control)
			control = this._control;
		return new $IG.CallbackObject(control);
	},

	execute: function(callback, queue, async, noIndicator)
	{
		/// <summary>
		/// Initiates an XmlHTTPRequest for the specified CallbackObject.
		/// </summary>
		/* flag that response failed because of timeout */
		this._timeOut = null;
		if (callback)
		{
			if (async == null)
				async = this.getAsync();
			var requestHandler = new $IG.CallbackRequestHandler(this, callback, async);
			requestHandler._noPI = noIndicator;
			if (queue && this._currentRequests > 0)
				this._pushCallback(requestHandler)
			else
			{
				this._currentRequests++;
				requestHandler.execute();
			}
		}
	},

	_pushCallback: function(callback)
	{
		this._callbackQueue.push(callback);
	},

	_popCallback: function()
	{
		for (var i = 0; i < this._callbackQueue.length; i++)
		{
			var requestHandler = this._callbackQueue[i];
			if (requestHandler != null)
			{
				delete this._callbackQueue[i];
				this._currentRequests++;
				requestHandler.execute();
			}
		}
	},

	getAsync: function()
	{
		/// <summary>
		/// Get/Sets whether or not the Callback should be Async.
		/// The Default is true.
		/// </summary>
		return this._async;
	},
	setAsync: function(val) { return this._async; },

	getHttpVerb: function()
	{
		/// <summary>
		/// Get/Sets the HTTP Verb for the Callback.
		/// The Default is "Post"
		/// </summary>
		return this._httpVerb;
	},
	setHttpVerb: function(verb) { this._httpVerb = verb; },

	getUrl: function()
	{
		/// <summary>
		/// Get/Sets the url for the Callback. 
		/// The default is the current form's action.
		/// </summary>
		return this._url;
	},
	setUrl: function(url) { this._url = url; },

	getTimeout: function()
	{
		/// <summary>
		/// Get/Sets the amount of time (in ms) that is allowed to pass before failing the Callback.
		/// The default is 20000
		/// </summary>
		return this._timeout;
	},
	setTimeout: function(val) { this._timeout = val; },

	_getForm: function()
	{
		if (!this._form)
		{
			if (document.forms.length > 1)
			{
				for (var i = 0; i < document.forms.length; i++)
				{
					if (document.forms[i].method == "post" && document.forms[i].action != "")
					{
						this._form = document.forms[i];
						break;
					}
				}
				if (!this._form)
					this._form = document.forms[0];
			}
			else
				this._form = document.forms[0];
			if (!this._form)
				this._form = document.form1;
		}
		return this._form
	},

	_endRequest: function()
	{
		this._currentRequests--;
		if (this._callbackQueue.length > 0)
			this._popCallback();
		/* get ajaxIndicator: do not use ctl._pi, because, child grid does not have it and */
		/* filters through ajaxIndicator of hierarchical grid */
		var pi = this._control;
		pi = (pi && pi.get_ajaxIndicator) ? pi.get_ajaxIndicator() : null;
		/* hide ajaxIndicator (do not reset _posted here) */
		if (pi)
			pi.hide();
	},

	setResponseComplete: function(func, context)
	{
		/// <summary>
		/// Sets the method that should be called when the Callback has returned from the server. 
		/// </summary>
		this._responseCompleteFunction = func;
		if (!context)
			context = this._control;
		this._responseCompleteContext = context;
	},

	_requestFailed: function(requestHandler, callbackObject, timedOut)
	{
		window.clearTimeout(requestHandler._timerId);
		if (requestHandler._request.readyState == 4)
			callbackObject._responseCompleteError(requestHandler._request, timedOut || this._timeOut);
		else
			/* when requestFailed is called with timedOut=true, then readyState!=4, */
			/* and _responseCompleteError never gets that flag, so, save timeOut at member-flag */
			this._timeOut = true;
		this._endRequest();
		requestHandler._request.abort();
		requestHandler._request = null;
		/* reset _posted flag (not posted-state) */
		if (this._control)
			this._control._posted = false;
	},

	_requestCompleted: function(requestHandler, callbackObject, responseObject)
	{
		/* that will hide possible ajaxIndicator */
		this._endRequest();
		/* After response _control can be replaced by new instance (grid does that). */
		/* To prevent disposing ajaxIndicator: copy it to new instance of this._control (var pi). */
		var ctl = this._control;
		if (!ctl)
			return;
		var id = ctl._id, pi = ctl._pi, elem = ctl._element;
		/* set global flag to skip creation of ajaxIndicator (if control is recreated by response) */
		$util._skip_pi = true;
		/* temporary remove indicator */
		ctl._pi = null;
		this._recursiveResponseCompleted(callbackObject, responseObject, requestHandler._request);
		/* remove flag to skip creation of ajaxIndicator */
		$util._skip_pi = null;
		/* check if control was disposed and find newly created control */
		if (ctl._element != elem)
			ctl = ig_controls[id];
		/* restore indicator and reset _posted (not posted-state) */
		if (ctl)
		{
			ctl._pi = pi;
			ctl._posted = false;
		}
	},

	_recursiveResponseCompleted: function(callbackObject, responseObject, browserResponseObject)
	{
		this._responseComplete(callbackObject, responseObject, browserResponseObject);
		for (var i = 0; i < callbackObject._childCallbacks.length; i++)
			this._recursiveResponseCompleted(callbackObject._childCallbacks[i], responseObject.children[i], browserResponseObject);
	},

	_responseComplete: function(callbackObject, responseObject, browserResponseObject)
	{
		if (!callbackObject._responseComplete(responseObject, browserResponseObject))
		{
			if (this._responseCompleteFunction)
				this._responseCompleteFunction.apply(this._responseCompleteContext, [callbackObject, responseObject, browserResponseObject]);
		}
		callbackObject.dispose();
	},

	dispose: function()
	{
		this._control = null;
		this._form = null;
		this._responseCompleteContext = null;
	}

};
$IG.ControlCallbackManager.registerClass("Infragistics.Web.UI.ControlCallbackManager");
/******************************************END Control Callback Manager*****************************/

/******************************************Callback Object******************************************/
$IG.CallbackObject = function(control)
{
	/// <summary>
	/// An object that contains information about a Callback that should be made to the server.
	/// </summary>
	this._control = control;
	this.serverContext = {};
	this.clientContext = {};
	this._childCallbacks = [];
}

$IG.CallbackObject.prototype =
{
	createCallbackObject: function(control)
	{
		/// <summary>
		/// Creates a child CallbackObject of the current CallbackObject
		/// </summary>
		if (!control)
			control = this._control;
		var callbackObject = new $IG.CallbackObject(control);
		this._childCallbacks.push(callbackObject);
		return callbackObject;
	},

	getId: function()
	{
		/// <summary>
		/// Returns the id of the control that is attached to the callback.
		/// </summary>
		return this._control._id;
	},

	getServerContext: function()
	{
		/// <summary>
		/// Returns the JSON object that will be used to pass infomration to the server about the specific Callback
		/// </summary>    
		return this.serverContext;
	},
	getClientContext: function()
	{
		/// <summary>
		/// Returns the JSON object that will be used to pass infomration to the ResponseComplete event of the Callback.
		/// </summary>    
		return this.clientContext;
	},

	setResponseComplete: function(func, context, funcError)
	{
		/// <summary>
		/// Sets an event listener for the ResponseComplete event of the CallbackObject
		/// </summary>    
		this._responseCompleteFunction = func;
		this._responseCompleteErrorFunction = funcError;
		if (!context)
			context = this._control;
		this._responseCompleteContext = context;
	},

	_responseComplete: function(responseObj, browserResponseObject)
	{
		if (this._responseCompleteFunction)
		{
			this._responseCompleteFunction.apply(this._responseCompleteContext, [this, responseObj, browserResponseObject]);
			return true;
		}
		else if (this._control && this._control.__responseCompleteInternal)
		{
			this._control.__responseCompleteInternal(this, responseObj, browserResponseObject);
			return true;
		}
		return false;
	},

	_responseCompleteError: function(responseObj, timedOut)
	{
		if (this._responseCompleteErrorFunction)
		{
			this._responseCompleteErrorFunction.apply(this._responseCompleteContext, [this, responseObj, timedOut]);
			return true;
		}
		else if (this._control && this._control._responseCompleteError)
		{
			this._control._responseCompleteError(this, responseObj, timedOut);
			return true;
		}
		return false;
	},

	_parseErrorMessage: function(browserResponseObject)
	{
		var errorMessage = browserResponseObject.responseText;
		if (errorMessage.substr(0, 6) == "<html>")
		{
			var indexStart = errorMessage.indexOf("<!--");
			var indexEnd;
			if (indexStart > 0)
			{
				indexStart += 4;
				indexEnd = errorMessage.indexOf("-->", indexStart);
				if (indexEnd < 0)
					indexEnd = errorMessage.length;
				errorMessage = errorMessage.substr(indexStart, indexEnd - indexStart);
			}
		}
		return errorMessage;
	},
	_getServerData: function()
	{
		var data = { id: this._control ? this._control.get_uniqueID() : '', context: this.serverContext, children: [] };
		for (var i = 0; i < this._childCallbacks.length; i++)
			data.children[i] = this._childCallbacks[i]._getServerData();
		return data;
	},

	dispose: function()
	{
		this._control = null;
		this.serverContext = null;
		this.clientContext = null;
	}

};
$IG.CallbackObject.registerClass("Infragistics.Web.UI.CallbackObject");
/******************************************END Callback Object**************************************/
