////////////////////////////////////////////////////////////////////////////
/**
 * Constructor
 * 
 * @param Object obj
 * @param function() fnc
 */
function delegate(obj, fnc, args)
{
	var cb =
		function ()
		{
			var _cb = arguments.callee.cb;
			var _args = arguments.callee.args;
			var _target = arguments.callee.target;
			try {
				return _cb.apply(_target, _args);
			} catch (e) {
				return false;
			}
		}

		cb.target = obj;
		cb.cb = fnc;
		cb.args = args ? args : [];
		return cb;
}

////////////////////////////////////////////////////////////////////////////
/**
 * Function parses AJAX response content and executes javascripts
 */
function executeScripts(xContentNode)
{
	var scriptTags = xContentNode.getElementsByTagName('SCRIPT');
	var scripts = [];
	var i;
	var xScriptNode;
	var xParentNode;
	while (scriptTags.length)
	{
		xScriptNode = scriptTags[0];
		xParentNode = xScriptNode.parentNode;
		if (xScriptNode.getAttribute('src')) {
			scripts.push({parent: xParentNode, text: null, src: xScriptNode.getAttribute('src')});
		} else {
			scripts.push({parent: xParentNode, text: xScriptNode.text, src: null});
		}
		xParentNode.removeChild(xScriptNode);
	}
	for (i = 0; i < scripts.length; i++) {
		xParentNode = scripts[i].parent;
		xScriptNode = document.createElement('SCRIPT');
		xParentNode.appendChild(xScriptNode);
		if (scripts[i].src) {
			xScriptNode.src = scripts[i].src;
		} else {
			xScriptNode.text = scripts[i].text;
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/**
 * Returns element of the frm identified by name elName
 *
 * @param form frm
 * @param string elName
 * @return element
 */
function formElement(frm, elName)
{
	if (COMMONS.isIE) {
		var elem = [];
		for (var i = 0; i < frm.elements.length; i++) {
			if (frm.elements[i].name == elName) {
				elem[elem.length] = frm.elements[i];
			}
		}
		if (elem.length == 1) {
			return elem[0];
		} else if (elem.length > 1) {
			return elem;
		} else {
			return null;
		}
	} else {
		return frm.elements[elName];
	}
}

////////////////////////////////////////////////////////////////////////////
/**
 * Sets text content for HTML element
 *
 * @param DOMElement elem
 * @param string text
 */
function setTextContent(elem, text)
{
	if (COMMONS.isIE) {
		while (elem.hasChildNodes()) {
			elem.removeChild(elem.firstChild);
		}
		elem.appendChild(document.createTextNode(text));
	} else {
		elem.textContent = text;
	}
	
}

////////////////////////////////////////////////////////////////////////////
function freezePage(freeze)
{
	var freezePane;
	var selects;
	var i;
	
	if (freeze === true)
	{
		freezePane = document.getElementById('freezePane');
		if (freezePane) {
			return;
		}

		freezePane = document.createElement('DIV');
		freezePane.setAttribute('id', 'freezePane');
		freezePane.className = 'freezePaneOn';

		var innerPane = document.createElement('DIV');
		innerPane.setAttribute('id', 'innerPane');
		freezePane.appendChild(innerPane);

		var innerElem = document.createElement('IMG');
		innerElem.src = '/styles/images/busy.gif';
		innerElem.setAttribute('border', '0');
		innerElem.setAttribute('vspace', '10');
		innerPane.appendChild(innerElem);

		innerElem = document.createElement('P');
		innerElem.style.font = 'bold 14px Arial';
		innerElem.appendChild(document.createTextNode(locale['FREEZE_MESSAGE']));
		innerPane.appendChild(innerElem);
		
		freezePane.style.left   = document.documentElement.scrollLeft + 'px';
		freezePane.style.top    = document.documentElement.scrollTop + 'px';
		freezePane.style.width  = (document.documentElement.clientWidth - 5)  + 'px';
		freezePane.style.height = (document.body.clientHeight - 5) + 'px';

		document.body.appendChild(freezePane);

		if (COMMONS.isIE) {
			selects = document.getElementsByTagName('SELECT');
			for (i = 0; i < selects.length; i++) {
				selects[i].style.visibility = 'hidden';
			}
		}
		
		var scrollCB = function() {
			var freezePane = arguments.callee.fp;
			if (freezePane) {
				freezePane.style.left   = document.documentElement.scrollLeft + 'px';
				freezePane.style.top    = document.documentElement.scrollTop + 'px';
			}
		};
		scrollCB.fp = freezePane;
		window.onscroll = scrollCB;
	}
	else
	{
		freezePane = document.getElementById('freezePane');
		if (freezePane) {
			document.body.removeChild(freezePane);
		}
		window.onscroll = null;

		if (COMMONS.isIE) {
			selects = document.getElementsByTagName('SELECT');
			for (i = 0; i < selects.length; i++) {
				selects[i].style.visibility = 'visible';
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/**
 * By default, converts HTML form element name to JSON path.
 *
 * @param {String} The HTML form element name.
 * @param {Element} The HTML form element.
 *
 * @return {String} Returns element name
 *
 */
function Form_PathConverter(aElementName, aElement)
{
	if (aElement.disabled) {
		return null;
	}
	return aElementName;
};

////////////////////////////////////////////////////////////////////////////
/**
 * Form results cleanup
 */
function Form_ClearErrors()
{
	this.displayFormMessage('');
	this.showFormMessage(false);
	
	var tblFields = document.getElementById(this.attributes['id'].nodeValue + '_fields');
	if (!tblFields) {
		return;
	}
	
	var tblRows = tblFields.getElementsByTagName('TR');
	
	for (var aRow = 0; aRow < tblRows.length; aRow++)
	{
		var row = tblRows[aRow];
		
		if (row.className == 'err_tr')
		{
			row.className = row.oldClassName;
			
			var paras = row.getElementsByTagName('P');
			for (var i = 0; i < paras.length; i++) {
				var para = paras[i];
				if (para.className && para.className.match(/err_msg/)) {
					para.innerHTML = '';
				}
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/**
 * Displays message of list of messages
 */
function FormMessage_Display(message)
{
	var frmMessage = this.formMessage;

	if (!frmMessage) {
		return;
	}
	
	if (typeof(message) == 'array') {
		setTextContent(frmMessage, message.join("<br/>"));
	} else {
		setTextContent(frmMessage, message);
	}
}

////////////////////////////////////////////////////////////////////////////
/**
 * Displays message of list of messages
 */
function FormMessage_Style(styleName, styleValue)
{
	var frmMessage = this.formMessage;
	
	if (!frmMessage || !styleName) {
		return;
	}
	
	frmMessage.style[styleName] = styleValue;
}

////////////////////////////////////////////////////////////////////////////
/**
 * Shows and hides form messages
 */
function FormMessage_Show(display)
{
	var frmMessage = this.formMessage;
	
	if (!frmMessage) {
		return;
	}
	
	if (typeof(display) == 'undefined' || !display)
	{
		frmMessage.style.display = 'none';
		frmMessage.style.visibility = 'hidden';
		return;
	}
	
	frmMessage.style.display = 'block';
	frmMessage.style.visibility = 'visible';
}

////////////////////////////////////////////////////////////////////////////
/**
 * Submit handler
 */
function Form_OnSubmit()
{
	if (this.inProgress) {
		return false;
	}

	this.clearErrors();

	// Validating form data
	if (this.formValidator && !this.formValidator.validate()) {
		return false;
	}

	this.inProgress = true;

	// Populating form data
	var json = new Object();
	var frmdata = this.jTools.populateFormToJson(this, json, Form_PathConverter);
	
	// Constructing ajax request
	
	var callback = delegate(this, this.onAjaxLoad);
	this.jAjax = new Transporter(callback);
	var frmdatastring = new Serializer().serialize(frmdata);
	
	this.clearErrors();

	freezePage(true);

	this.jAjax.request(this.action, this.method, frmdatastring);
	
	return false;
}

function getWindowTop(pageElem)
{
	var res = 0;
	var obj = pageElem;
	while (obj.offsetParent) {
		res += obj.offsetTop;
		obj = obj.offsetParent;
	}
	return res;
}

////////////////////////////////////////////////////////////////////////////
/**
 * Shows error message associated to elem or global if !elem
 * @param string elem
 * @param string msg
 */
function Form_ShowError(elem, msg)
{
	var elemObj = formElement(this, elem);

	if (!elemObj)
	{
		if (typeof(msg) != 'undefined') {
			this.displayFormMessage(msg);
			this.showFormMessage(true);
		}
		
		if (this.formMessage) {
			var t = getWindowTop(this.formMessage) - 15;
			if (document.documentElement.scrollTop > t) {
				window.scroll(0, t);
			}
		}
		
		return;
	}

	if (elemObj.nodeName == 'INPUT' || elemObj.nodeName == 'SELECT' || elemObj.nodeName == 'TEXTAREA') {
		elemObj.focus();
	}
	
	var tdelem = elemObj;
	var it = 5;
	do {
		tdelem = tdelem.parentNode;
	} while (--it && tdelem && tdelem.nodeName != 'TD');
		
	if (!tdelem || tdelem.nodeName != 'TD')
	{
		if (typeof(msg) != 'undefined') {
			this.displayFormMessage(msg);
			this.showFormMessage(true);
		}
			
		return;
	}
		
	try
	{
		var trelem = tdelem.parentNode;
		trelem.oldClassName = trelem.className;
		trelem.className = 'err_tr';
		var para;
		var paras = trelem.getElementsByTagName('P');
		for (var i = 0; i < paras.length; i++) {
			if (paras[i].className && paras[i].className.match(/err_msg/)) {
				para = paras[i];
				break;
			}
		}

		var errMsgText = (typeof(msg) == 'array')? msg.join('<br/>'): msg;

		if (para) {
			para.innerHTML = '<span>' + errMsgText + '</span>';
		} else {
			this.displayFormMessage(errMsgText);
			this.showFormMessage(true);
		}
		
	} catch (err) {}
}

////////////////////////////////////////////////////////////////////////////
/**
 * Result fail handler
 */
function Form_OnResultFailed(res)
{
	
	// Showing errors and warnings
	
	if (!res['errors']) {
		return;
	}

	for (var ierror in res['errors'])
	{
		var error  = res['errors'][ierror];
		this.showError(error['formfield'], error['message']);
	}
	
	this.styleFormMessage('color', 'red');
	this.showFormMessage(true);
}

////////////////////////////////////////////////////////////////////////////
/**
 * Result success handler
 */
function Form_OnResultSuccess(res)
{
/*
	this.styleFormMessage('color', 'green');
	this.displayFormMessage('Saved successfully');
	this.showFormMessage(true);
*/
}

////////////////////////////////////////////////////////////////////////////
/**
 * Called by the transport object if data is loaded successfully.
 */
function Form_OnLoad()
{
	var result_data = this.jAjax.getResponsedText();
	var result = new Serializer().deserialize(result_data);
	
	this.clearErrors();

	this.inProgress = false;
	freezePage(false);
	
	if (result['result'] == true) {
		this.onResultSuccess(result);
		if (this.formCallback) {
			this.formCallback();
		}
		if (result['content'] && result['content'].length && this.formContainer) {
			this.formContainer.innerHTML = result['content'];
			executeScripts(this.formContainer);
			return;
		}
		if (result['location'] && result['location'].length) {
			window.location.href = result['location'];
			return;
		}
	} else {
		this.onResultFailed(result);
	}
	
}

////////////////////////////////////////////////////////////////////////////
/**
 * Initializes AJAX form processing routines.
 * @param string frmId
 * @param string frmMsgId
 */
function configureForm(frmId, frmMsgId, frmContainerId)
{
	var frmObj = document.getElementById(frmId);
	if (!frmObj) {
		return;
	}
	var formMsgObj = document.getElementById(frmMsgId);
	var formContainerObj = document.getElementById(frmContainerId);
	
	frmObj.formMessage   = formMsgObj;
	frmObj.formContainer = formContainerObj;

	frmObj.jAjax  = null;
	frmObj.jTools = new Jsoner();
	
	frmObj.onsubmit           = Form_OnSubmit;
	frmObj.onAjaxLoad         = Form_OnLoad;
	frmObj.clearErrors        = Form_ClearErrors;
	frmObj.showFormMessage    = FormMessage_Show;
	frmObj.displayFormMessage = FormMessage_Display;
	frmObj.styleFormMessage   = FormMessage_Style;
	frmObj.showError          = Form_ShowError;
	frmObj.onResultFailed     = Form_OnResultFailed;
	frmObj.onResultSuccess    = Form_OnResultSuccess;

	frmObj.inProgress = false;

	return frmObj;
}

////////////////////////////////////////////////////////////////////////////
/**
 * Data bearer Execute
 */
function AjaxDataBearer_Execute(do_not_freeze)
{
	if (this.inProgress) {
		return;
	}
	
	var postData = new Serializer().serialize(this.userData);
	var callback = delegate(this, this.onAjaxLoad);
	
	this.inProgress = true;
	this.jAjax = new Transporter(callback);
	
	if (do_not_freeze != true) {
		freezePage(true);
	}

	this.jAjax.request(this.uri, 'POST', postData);
}

////////////////////////////////////////////////////////////////////////////
/**
 * Called by the transport object if data is loaded successfully.
 */
function AjaxDataBearer_OnLoad()
{
	freezePage(false);

	this.inProgress = false;
	
	var result_data = this.jAjax.getResponsedText();
	var result = new Serializer().deserialize(result_data);

	if (result['result'] == true) {
		if (result['content'] != null && this.Container) {
			if (COMMONS.isIE && this.Container.nodeName == 'SELECT') {
				while (this.Container.hasChildNodes()) {
					this.Container.removeChild(this.Container.firstChild);
				}
				var tstr = result['content'];
				var myregexp = new RegExp('<option.+?value="([^"]*)".*?>([^<]*)</option>');
				var match = myregexp.exec(tstr);
				while (match != null && match.length > 1) {
					this.Container.options[this.Container.options.length] = new Option(match[2], match[1]);
					tstr = tstr.replace(myregexp, "");
					match = myregexp.exec(tstr);
				}
			} else {
				this.Container.innerHTML = result['content'];
			}
			executeScripts(this.Container);
		}
		if (this.userFunc) {
			this.userFunc.call(this);
		}
		if (result['location'] && result['location'].length) {
			window.location.href = result['location'];
		}
	} else {
		var msg = '';
		for (var i = 0; i < result['errors'].length; i++) {
			msg += result['errors'][i].message + '\n';
		}
		alert(msg);
	}
}

////////////////////////////////////////////////////////////////////////////
/**
 * AJAX DataBearer.
 * @param string frmId
 * @param string frmMsgId
 */
function AjaxDataBearer(uri, userData, containerId, userFunc)
{
	var containerObj = document.getElementById(containerId);
	
	if (containerObj)
		this.Container = containerObj;
	
	this.uri        = uri;
	this.userData   = (userData)? userData: new Object();
	this.userFunc   = userFunc;
	this.jAjax      = null;
	this.Execute    = AjaxDataBearer_Execute;
	this.onAjaxLoad = AjaxDataBearer_OnLoad;
	this.inProgress = false;

	return this;
}

////////////////////////////////////////////////////////////////////////////
function AjaxUpload(frmId, frmMsgId, frmContainerId, trackProgress)
{
	this.frmObj = document.getElementById(frmId);
	if (!this.frmObj) {
		alert('Invalid form Id: ' + frmId);
		return null;
	}

	this.onLoad               = AjaxUpload_OnLoad;
	this.cleanUp              = AjaxUpload_Cleanup;	
	this.Execute              = AjaxUpload_Execute;
	this.onError              = AjaxUpload_Error;
	this.updateProgress       = AjaxUpload_UpdateProgress;
	this.fetchUploadStatus    = AjaxUpload_FetchUploadStatus;
	this.uploadProgress        = AjaxUpload_UploadProgress;
	this.uploadProgressChange  = AjaxUpload_UploadProgressChange;
	this.uploadProgressTimeOut = AjaxUpload_UploadProgressTimeOut;
	
	this.fTrackProgress = null;
	if (trackProgress === true) {
		this.fTrackProgress = true;
	}

	this.frmObj.formMessage        = document.getElementById(frmMsgId);
	this.frmObj.formContainer      = document.getElementById(frmContainerId);
	this.frmObj.clearErrors        = Form_ClearErrors;
	this.frmObj.showFormMessage    = FormMessage_Show;
	this.frmObj.displayFormMessage = FormMessage_Display;
	this.frmObj.styleFormMessage   = FormMessage_Style;
	this.frmObj.showError          = Form_ShowError;
	this.frmObj.onResultFailed     = Form_OnResultFailed;
	this.frmObj.onResultSuccess    = Form_OnResultSuccess;
	
	// Attaching UploadID input
	
	this.frameId = Math.round(Math.random() * 100000);
	
	// console.debug(this.frameId);
	
	var uploadIdInput = formElement(this.frmObj, 'UPLOAD_IDENTIFIER');
	if (!uploadIdInput) {
		uploadIdInput = document.createElement('INPUT');
		uploadIdInput.setAttribute('type', 'hidden');
		uploadIdInput.setAttribute('name', 'UPLOAD_IDENTIFIER');
		this.frmObj.insertBefore(uploadIdInput, this.frmObj.firstChild);
	}
	
	uploadIdInput.setAttribute('value', this.frameId);
	this.responseData = '';
	this.frameObj = document.createElement('IFRAME');
	document.body.appendChild(this.frameObj);
	
	this.frameObj.style.width        = '0px';
	this.frameObj.style.height       = '0px';
	this.frameObj.style.display      = 'none';
	this.frameObj.style.visibility   = 'hidden';
	this.frameObj.contentWindow.name = 'tmpUploadFrame' + this.frameId;
	this.frameObj.setAttribute('id', this.frameId);
	
	window['onFrm' + this.frameId] = delegate(this, this.onLoad);

	this.frmObj.target = this.frameObj.contentWindow.name;
	this.fProgressId   = 0;

	//console.debug('Action: ' + this.frmObj.action);
	
	var frmUploadId = formElement(this.frmObj, 'uploadId');
	if (!frmUploadId)
	{
		var xUploadId = document.createElement('INPUT');
		xUploadId.setAttribute('type', 'hidden');
		xUploadId.setAttribute('name', 'uploadId');
		this.frmObj.insertBefore(xUploadId, this.frmObj.firstChild);
		frmUploadId = xUploadId;
	}
	
	frmUploadId.value = this.frameId;

	this.inProgress = false;
	
	return this;
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_Execute(timeout, notice)
{
	if (this.inProgress) {
		return;
	}
	
	if (this.frmObj)
	{
		this.frmObj.clearErrors();
		
		// Validating form data
		if (this.frmObj.formValidator && !this.frmObj.formValidator.validate()) {
			return false;
		}
		
		if (notice)
		{
			currentUpload = this;
			currentUploadTimeOut = timeout;
			overlib(initAjaxPopup('', {userId: 'UploadTimeNotice'}),
				STICKY, FULLHTML, CENTERPOPUP, WIDTH, 330);
			return;
		}
		
		this.inProgress = true;
		this.fProgressId = Math.floor(Math.random() * 1000000).toString(16);
		this.frmObj.action += '?X-Progress-ID=' + this.fProgressId;
		this.uploadProgress(true);
		this.fetchUploadStatus();
		
		try {
			this.frmObj.submit();
		} catch (e) {
			this.onError(locale['SECURITY_ERROR']);
		}
		
	} else {
		alert('Form does not specified');
	}
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_FetchUploadStatus()
{
	if (!this.inProgress || !this.fTrackProgress) {
		return;
	}
	
	try {
		var jAjax = new Transporter(this.uploadProgressChange,
			this.fProgressId, "POST", 3);
		
		jAjax.fCallerObject   = this;
		jAjax.getCallerObject = function() { return this.fCallerObject; };
		jAjax.setRequestHeader('X-Progress-ID', '' + this.fProgressId);
		jAjax.request('/progress', 'GET', null, 1);
		jAjax.setResponseHandler(500, delegate(this, this.onError,
			[locale['UPLOADING_ERROR']]));
		
		this.jUploadProgress = jAjax;
		this.jUploadProgressTimeOutId = setTimeout(
			delegate(this, this.uploadProgressTimeOut), 2000); 
		
	} catch (e) {
		jAjax.fLogger.error(e);
	}
}

function AjaxUpload_UploadProgressTimeOut()
{
	var jAjax = this.jUploadProgress;
	
	try {
		jAjax.fReq.abort();
	} catch (e) {
		jAjax.fLogger.error(e);
	}
	
	jAjax=null;

	if (!this.inProgress) {
		return;
	}
	
	setTimeout(delegate(this, this.fetchUploadStatus), 500); 
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_UploadProgressChange()
{
	var result      = null;
	var result_data = this.getResponsedText();
	var uploadForm  = this.getCallerObject();
	var progressBar = document.getElementById('uploadProgressBar');
	
	//clearTimeout(uploadForm.jUploadProgressTimeOutId);
	
	try { result = eval(result_data); } catch (e) {}
	if (!result || !uploadForm.inProgress) {
		return;
	}
	
	if (result['state'] == 'done')
	{
		//clearInterval(uploadForm.uploadFetchTimer);
		//console.debug('100%. Uploading completed');

		if (progressBar) {
			progressBar.setProgress(100);
		}
		
		return true;
		
	} else {
		/*if (uploadForm && result['state'] != 'error') {
			uploadForm.fetchUploadStatus();
		}*/
	}
	
	if (result['state'] == 'uploading')
	{
		var received = result['received'];
		var size     = result['size'];
		var perc     = Math.round(received / size * 100);
		
		if (!received || !size) {
			perc = received = size = 0;
		} else {
			if (perc < 0)   perc = 0;
			if (perc > 100) perc = 100;
		}
		
		// console.debug(perc + '%. Received ' + result['received'] + ' bytes from ' + result['size']);
		
		if (progressBar) {
			progressBar.setProgress(perc, received, size);
		}
		
		return true;
	}
	
	if (result['state'] == 'error') {
		uploadForm.onError(locale['UPLOADING_ERROR']);
	}
	
	return true;
}

function formatFileSize(fileSize)
{
	if (typeof fileSize == 'undefined' || !fileSize || fileSize == null) {
		return '-';
	}
	
	fileSize = 0 + fileSize;
	
	if (fileSize > 1024 && fileSize < 1048576) {
		return (fileSize/1024).toFixed(2) + ' Kb';
	} else if (fileSize > 1048576) {
		return (fileSize/1048576).toFixed(2) + ' Mb';
	} else {
		return fileSize + ' bytes';
	}
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_UploadProgress(show)
{
	var uploadPane;
	var selects;
	var i;
	
	if (show === true)
	{
		uploadPane = document.getElementById('uploadPane');
		if (uploadPane) {
			return;
		}

		uploadPane = document.createElement('DIV');
		uploadPane.setAttribute('id', 'uploadPane');
		uploadPane.className = 'freezePaneOn';

		var innerPane = document.createElement('DIV');
		innerPane.setAttribute('id', 'innerPane');
		uploadPane.appendChild(innerPane);

		var innerElem = document.createElement('IMG');
		innerElem.src = '/styles/images/busy.gif';
		innerElem.setAttribute('border', '0');
		innerElem.setAttribute('vspace', '10');
		innerPane.appendChild(innerElem);

		innerElem = document.createElement('P');
		innerElem.appendChild(document.createTextNode(locale['FREEZE_MESSAGE']));
		innerPane.appendChild(innerElem);

		innerElem = document.createElement('DIV');
		innerElem.setAttribute('id', 'uploadProgressBar');
		innerElem.style.border  = '1px solid silver';
		innerElem.style.margin  = '15px auto auto auto';
		innerElem.style.padding = '1px';
		innerElem.style.width   = '90%';
		
		if (this.fTrackProgress)
		{
			// Progress value bar
			
			progressValueElem = document.createElement('DIV');
			progressValueElem.setAttribute('id', 'prcBar');
			progressValueElem.style.backgroundColor = 'gray';
			progressValueElem.style.textAlign = 'center';
			progressValueElem.style.height    = '20px';
			progressValueElem.style.width     = '0px';
			progressValueElem.style.margin    = '0px auto 0px 0px';
			innerElem.appendChild(progressValueElem);
			innerPane.appendChild(innerElem);
			
			// Progress labels
			
			progressLabelsElem = document.createElement('DIV');
			progressLabelsElem.setAttribute('id', 'prcLabels');
			progressLabelsElem.style.width = '90%';
			progressLabelsElem.style.margin  = '5px auto auto auto';
			progressLabelsElem.style.verticalAlign = 'top';
			progressLabelsElem.style.textAlign = 'center';
			progressLabelsElem.style.font = '12px Arial';
			innerPane.appendChild(progressLabelsElem);
			
			//
			innerElem.setProgress = function(prcValue, bytesLoaded, bytesTotal)
			{
				var prcBar    = null;
				var prcLabels = null;
				
				for (
					aChild = this.firstChild;
					aChild != null;
					aChild = aChild.nextSibling)
				{
					if (aChild.getAttribute('id') == 'prcBar') {
						prcBar    = aChild;
					}
				}
				
				for (
					aChild = this.parentNode.firstChild;
					aChild != null;
					aChild = aChild.nextSibling)
				{
					if (aChild.getAttribute('id') == 'prcLabels') {
						prcLabels = aChild;
					}
				}
				
				if (!prcBar && !prcLabels) {
					return;
				}
				
				prcBar.style.width = prcValue + '%';
				
				if (prcLabels && (prcValue >= 100)) {
					prcLabels.innerHTML = prcValue + '% <b>' + locale['UPLOADING_COMPLETED'] + '</b>';
				} else
				{
					prcLabels.innerHTML = prcValue + '%'
						+ ' ' + locale['UPLOADING_UPLOADED'] + '<b> '
						+ formatFileSize(bytesLoaded) + '</b> ' + locale['UPLOADING_FROM'] + ' <b>'
						+ formatFileSize(bytesTotal)  + '</b>';
				}
			};
		}
		
		uploadPane.style.left   = document.documentElement.scrollLeft + 'px';
		uploadPane.style.top    = document.documentElement.scrollTop + 'px';
		uploadPane.style.width  = (document.documentElement.clientWidth - 5)  + 'px';
		uploadPane.style.height = (document.body.clientHeight - 5) + 'px';

		document.body.appendChild(uploadPane);

		if (COMMONS.isIE) {
			selects = document.getElementsByTagName('SELECT');
			for (i = 0; i < selects.length; i++) {
				selects[i].style.visibility = 'hidden';
			}
		}
		
		var scrollCB = function()
		{
			var uploadPane = arguments.callee.up;
			if (uploadPane) {
				uploadPane.style.left   = document.documentElement.scrollLeft + 'px';
				uploadPane.style.top    = document.documentElement.scrollTop  + 'px';
			}
		};
		
		scrollCB.up = uploadPane;
		window.onscroll = scrollCB;
	}
	else
	{
		uploadPane = document.getElementById('uploadPane');
		if (uploadPane) {
			document.body.removeChild(uploadPane);
		}
		
		window.onscroll = null;

		if (COMMONS.isIE) {
			selects = document.getElementsByTagName('SELECT');
			for (i = 0; i < selects.length; i++) {
				selects[i].style.visibility = 'visible';
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_UpdateProgress()
{
	var progressBar = document.getElementById('uploadProgressBar');
	if (progressBar && (!progressBar.firstChild || progressBar.firstChild.style.width != '100%')) {
		new AjaxDataBearer('/Yagent_Controller_UploadProgressReporter/GetProgress', {uploadId: this.frameId}, 'uploadProgressBar', delegate(this, this.updateProgress)).Execute(true);
	}
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_OnLoad()
{
	if (this.timer) {
		clearTimeout(this.timer);
	}
	
	this.uploadProgress(false);

	if (this.frameObj)
	{
		if (COMMONS.isIE) {
			this.responseData = this.frameObj.contentWindow.document.body.innerText;
		} else {
			this.responseData = this.frameObj.contentWindow.document.body.textContent;
		}
		
		var result = new Serializer().deserialize(this.responseData);
		this.frmObj.clearErrors();
		if (result['result'] == true) {
			this.frmObj.onResultSuccess(result);
			if (result['content'] && result['content'].length && this.frmObj.formContainer) {
				this.frmObj.formContainer.innerHTML = result['content'];
				executeScripts(this.frmObj.formContainer);
			}
			if (result['location'] && result['location'].length) {
				window.location.href = result['location'];
				return;
			}
		} else {
			this.frmObj.onResultFailed(result);
		}

		setTimeout(delegate(this, this.cleanUp), 300);
	}
}

/////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_Error(message)
{
	if (this.timer) {
		clearTimeout(this.timer);
	}

	this.uploadProgress(false);

	if (this.frameObj) {
		result = {"result":false,"location":null,"errors":[{"message":message,"formfield":null}],"content":""};
		this.frmObj.onResultFailed(result);
		setTimeout(delegate(this, this.cleanUp), 300);
	}
}

////////////////////////////////////////////////////////////////////////////////
function AjaxUpload_Cleanup()
{
	if (this.frameObj) {
		document.body.removeChild(this.frameObj);
	}

	this.inProgress = false;
	currentUpload = null;

	if (this.frmObj.uploadCallback) {
		this.frmObj.uploadCallback();
	}
}

////////////////////////////////////////////////////////////////////////////////
function initAjaxPopup(uri, object)
{
	if (object.userId) {
		contentDiv = document.getElementById('popupDiv' + object.userId);
		if (contentDiv) {
			return contentDiv.innerHTML;
		}
	}
	
	var rnd = Math.round(Math.random() * 100000);
	var cb = function () {
		var _uri = arguments.callee.uri;
		var _dataObj = arguments.callee.dataObj;
		var _containerId = arguments.callee.containerId;
		new AjaxDataBearer(_uri, _dataObj, _containerId).Execute(true);
	}
	cb.uri = uri;
	cb.dataObj = object;
	cb.containerId = 'popupContainer' + rnd;
	setTimeout(cb, 300);

	return '<div class=\'popup\' id=\'popupContainer' + rnd + '\'><div class=\'popupTitle\'>' + locale['FREEZE_MESSAGE'] + '</div><div class=\'popupFooter\'>&nbsp;</div></div>';
}

