/**
 * Sitebuilder Ajax.Request wrapper
 *
 * @copyright (c) 2004-2008, SWsoft
 */
var SbAjaxRequest = { };

SbAjaxRequest.ContainerUpdater = Class.create();
SbAjaxRequest.ContainerUpdater.prototype = {

	/**
	 * Request options
	 *
	 * @var object
	 * @access private
	 */
	_options: null,

	/**
	 * Overlay containers list
	 *
	 * @var Array
	 * @access private
	 */
	_overlayContainers: null,

	/**
	 * Object constructor
	 *
	 * @access public
	 * @param string
	 * @param object
	 * @param DOM object
	 * @param object
	 * @return void
	 */
	initialize: function(requestUrl, requestParameters, container, options) {
		this._overlayContainers = new Array();
		this._options = {

			method: 'get',

			addOverlay: true,

			addOverlayText: true,

			parameters: requestParameters,

			container: $(container),

			overlayElements: [$(container)]
		};
		Object.extend(this._options, options || { });

		var wrapper = this;
		var requestOptions = { };
		Object.extend(requestOptions, this._options);
		Object.extend(
			requestOptions,
			{
				onSuccess: function(transport) { wrapper.onSuccess(transport); },

				onFailure: function(transport) { wrapper.onFailure(transport); },

				onException: function(transport, exception) { wrapper.onException(transport, exception); },

				onCreate: function() { wrapper.onCreate(); },

				onComplete: function() { wrapper.onComplete(); }
			}
		);
		
		Sb.Console.log('Ajax.Request : ' + requestUrl);
		
		var request = new Ajax.Request(requestUrl, requestOptions);
	},

	/**
	 * Invoked when a request completes
	 * and its status code is undefined or belongs in the 2xy family.
	 * This is skipped if a code-specific callback is defined,
	 * and happens before onComplete.
	 *
	 * @access public
	 * @param object
	 * @return void
	 */
	onSuccess: function(transport) {
		this._removeOverlays();
		if (Object.isFunction(this._options.onSuccess)) {
			return this._options.onSuccess(transport);
		}
		var html = ('undefined' == typeof transport.responseText)
			? '' : transport.responseText.toString();
		this._options.container.innerHTML = html.stripScripts();
		html.evalScripts();
	},

	/**
	 * Invoked when a request completes
	 * and its status code exists but is not in the 2xy family.
	 * This is skipped if a code-specific callback is defined,
	 * and happens before onComplete.
	 *
	 * @access public
	 * @param object
	 * @return void
	 */
	onFailure: function(transport) {
		this._removeOverlays();
		if (Object.isFunction(this._options.onFailure)) {
			return this._options.onFailure(transport);
		}
		alert('Internal Sitebuilder error');
		this._options.container.update(transport.responseText);
	},

	/**
	 * Triggered whenever an XHR error arises.
	 *
	 * @access public
	 * @param object
	 * @param object
	 * @return void
	 */
	onException: function(transport, exception) {
		this._removeOverlays();
		if (Object.isFunction(this._options.onException)) {
			return this._options.onException(transport, exception);
		}
		alert('Internal Sitebuilder error: ' + exception.message);
	},

	/**
	 * Triggered whenever a requester object from the Ajax namespace is created.
	 *
	 * @access public
	 * @return void
	 */
	onCreate: function() {
		if (this._options.addOverlay) {
			for(var i = 0; i < this._options.overlayElements.length; i++) {
				this._addOverlay(this._options.overlayElements[i], ((i < 1) && this._options.addOverlayText));
			}
		}
		if (Object.isFunction(this._options.onCreate)) {
			this._options.onCreate();
		}
	},

	/**
	 * Triggered at the very end of a request's life-cycle, once the request completed.
	 *
	 * @access public
	 * @return void
	 */
	onComplete: function() {
		if (Object.isFunction(this._options.onComplete)) {
			this._options.onComplete();
		}
		this._removeOverlays();
	},

	/**
	 * Removes all created overlays.
	 *
	 * @access private
	 * @return void
	 */
	_removeOverlays: function() {
		for(var i = 0; i < this._overlayContainers.length; i++) {
			this._overlayContainers[i].parentNode.removeChild(this._overlayContainers[i]);
			this._overlayContainers[i] = null;
		}
		this._overlayContainers = new Array();
	},

	/**
	 * Adds overlay for container
	 *
	 * @access private
	 * @return void
	 */
	_addOverlay: function(container, addText) {
		var overlayContainer;
		var opaqueElement;
		var transparentElement;
		var iframeForOpaqueElement;

		overlayContainer = new Element('div');
		if (addText) {
			overlayContainer.update(
				'<table border="0" style="width: 100%; height: 100%;"><tr><td align="center" valign="middle">' +
					'<table style="border: #000000 1px solid; position: relative;">' +
						'<tr><td>' +
							'<table cellpadding="4px" border="0"><tr>' +
								'<td>' +
									'<img src="/images/SbAjaxRequest/loadingIndicator.gif"/>' +
								'</td><td style="white-space: nowrap;">' +
									self.htmlSpecialChars(self.SbGetLocaleByKey('AJAX-REQUEST-WAIT')) +	' ' +
									self.htmlSpecialChars(self.SbGetLocaleByKey('AJAX-REQUEST-LOADING')) +
								'</td>' +
							'</tr></table>' +
						'</td></tr>' +
					'</table>' +
				'</td></tr></table>'
			);
			var tablesList = overlayContainer.getElementsByTagName('TABLE');
			for (var j = 0; j < tablesList.length; j++) {
				if (tablesList[j].parentNode == overlayContainer) {
					continue;
				}
				if (tablesList[j].parentNode.parentNode.parentNode.parentNode.parentNode == overlayContainer) {
					transparentElement = $(tablesList[j]);
					break;
				}
			}
			opaqueElement = $(transparentElement.cloneNode(true));
		} else {
			overlayContainer.update(
				'<table border="0" style="width: 100%; height: 100%;"><tr><td align="center" valign="middle">' +
					'<img src="/images/SbAjaxRequest/loadingIndicator.gif"/>' +
				'</td></tr></table>'
			);
		}
		overlayContainer.setStyle(
			{
				display: 'none',
				opacity: 0.5,
				position: 'absolute',
				zIndex: container.style.zIndex + 2,
				backgroundColor: '#FFFFFF'
			}
		);

		container.parentNode.appendChild(overlayContainer);
		Element.clonePosition(overlayContainer, container);
		overlayContainer.style.cursor = 'wait';

		if (addText) {
			iframeForOpaqueElement = new Element(
				'iframe',
				{
					src: '/blank.html',
					frameborder: '0',
					scrolling: 'no',
					style: 'display: none;'
				}
			);
			container.parentNode.appendChild(iframeForOpaqueElement);
			iframeForOpaqueElement.setStyle(
				{
					borderWidth: '0',
					position: 'absolute',
					zIndex: container.style.zIndex + 1
				}
			);

			opaqueElement.setStyle(
				{
					display: 'none',
					position: 'absolute',
					cursor: 'wait',
					backgroundColor: '#FFFFFF',
					zIndex: container.style.zIndex + 3
				}
			);
			container.parentNode.appendChild(opaqueElement);
		}

		overlayContainer.show();

		if (addText) {
			Element.clonePosition(opaqueElement, transparentElement);
			Element.clonePosition(iframeForOpaqueElement, transparentElement);
			if (Prototype.Browser.IE) {
				var top = Math.ceil((overlayContainer.getHeight() - transparentElement.getHeight()) / 2);
				top += parseInt(overlayContainer.style.top);
				opaqueElement.style.top = top + 'px';
				iframeForOpaqueElement.style.top = top + 'px';
			}

			iframeForOpaqueElement.show();
			opaqueElement.show();
			transparentElement.setStyle({opacity: 0});

			this._overlayContainers.push(opaqueElement);
			this._overlayContainers.push(iframeForOpaqueElement);
		}
		this._overlayContainers.push(overlayContainer);
	}
}

SbAjaxRequest.JsonAction = Class.create();
SbAjaxRequest.JsonAction.prototype = {

	/**
	 * Request options
	 *
	 * @var object
	 * @access private
	 */
	_options: null,

	/**
	 * Request result
	 *
	 * @var object
	 * @access private
	 */
	_requestResult: null,

	/**
	 * Object constructor
	 *
	 * @access public
	 * @param string
	 * @param object
	 * @param DOM object
	 * @param object
	 * @return void
	 */
	initialize: function(requestUrl, requestParameters, options) {
		this._requestResult = new Object();
		this._options = {

			method: 'post',

			parameters: requestParameters,

			asynchronous: false,

			addOverlay: true
		};
		Object.extend(this._options, options || { });

		var wrapper = this;
		var requestOptions = { };
		Object.extend(requestOptions, this._options);
		Object.extend(
			requestOptions,
			{
				onSuccess: function(transport) { wrapper.onSuccess(transport); },

				onFailure: function(transport) { wrapper.onFailure(transport); },

				onException: function(transport, exception) { wrapper.onException(transport, exception); },

				onCreate: function() { wrapper.onCreate(); },

				onComplete: function() { wrapper.onComplete(); }
			}
		);
		var request = new Ajax.Request(requestUrl, requestOptions);
	},

	/**
	 * Invoked when a request completes
	 * and its status code is undefined or belongs in the 2xy family.
	 * This is skipped if a code-specific callback is defined,
	 * and happens before onComplete.
	 *
	 * @access public
	 * @param object
	 * @return void
	 */
	onSuccess: function(transport) {
		var html = ('undefined' == typeof transport.responseText)
			? '' : transport.responseText.toString();
		try {
			this._requestResult = html.evalJSON(true);
		} catch (e) {
			this.onJsonException(html);
			return;
		}
		if (this._requestResult.error) {
			if (Object.isFunction(this._options.onActionError)) {
				this._options.onActionError(this._requestResult.error);
			} else {
				alert(this._requestResult.error);
			}
		} else {
			if (Object.isFunction(this._options.onActionSuccess)) {
				this._options.onActionSuccess(this._requestResult);
			}
		}
		if (Object.isFunction(this._options.onSuccess)) {
			return this._options.onSuccess(transport);
		}
	},

	/**
	 * Invoked when a request completes
	 * and its status code exists but is not in the 2xy family.
	 * This is skipped if a code-specific callback is defined,
	 * and happens before onComplete.
	 *
	 * @access public
	 * @param object
	 * @return void
	 */
	onFailure: function(transport) {
		if (this._options.addOverlay) {
			self.sbPreloader.hide();
		}
		self.document.body.style.cursor = 'default';
		if (Object.isFunction(this._options.onFailure)) {
			return this._options.onFailure(transport);
		}
		alert('Internal Sitebuilder error: ' + transport.responseText);
	},

	/**
	 * Triggered whenever an XHR error arises.
	 *
	 * @access public
	 * @param object
	 * @param object
	 * @return void
	 */
	onException: function(transport, exception) {
		if (this._options.addOverlay) {
			self.sbPreloader.hide();
		}
		self.document.body.style.cursor = 'default';
		if (Object.isFunction(this._options.onException)) {
			return this._options.onException(transport, exception);
		}
		alert('Internal Sitebuilder error: ' + exception.message);
	},

	/**
	 * Triggered whenever an JSON parse error arises.
	 *
	 * @access public
	 * @param string
	 * @return void
	 */
	onJsonException: function(html) {
		if (this._options.addOverlay) {
			self.sbPreloader.hide();
		}
		self.document.body.style.cursor = 'default';
		if (Object.isFunction(this._options.onJsonException)) {
			return this._options.onJsonException(html);
		}
		self.document.body.innerHTML = html.stripScripts();
		html.evalScripts();
	},

	/**
	 * Triggered whenever a requester object from the Ajax namespace is created.
	 *
	 * @access public
	 * @return void
	 */
	onCreate: function() {
		if (this._options.addOverlay) {
			self.sbPreloader.show();
		}
		self.document.body.style.cursor = 'wait';
		if (Object.isFunction(this._options.onCreate)) {
			this._options.onCreate();
		}
	},

	/**
	 * Triggered at the very end of a request's life-cycle, once the request completed.
	 *
	 * @access public
	 * @return void
	 */
	onComplete: function() {
		if (this._options.addOverlay) {
			self.sbPreloader.hide();
		}
		self.document.body.style.cursor = 'default';
		if (Object.isFunction(this._options.onActionComplete)) {
			this._options.onActionComplete(this._requestResult);
		}
		if (Object.isFunction(this._options.onComplete)) {
			this._options.onComplete();
		}
	}
}