function getFormValues(oForm) {
	var oData = {};
	
	if (!oForm || !oForm.elements || !oForm.length) return oData;

	for (i = 0; i < oForm.length; i++) {
		var field = oForm.elements[i];
		// skip the field if it is a checkbox or a radio button and it is not checked
		if ((field.type == 'checkbox' || field.type == 'radio') && !field.checked) continue;
		
		// skip the field if it doesn't have a name (submit button)
		if (!field.name) continue;

		if (oData[field.name] == null) {
			oData[field.name] = [$(field).val()];
		} else {
			oData[field.name].push($(field).val());
		}
	}
	
	return oData;
}

function clearForm(form) {
	if (!form) return false;
	for (i in form.elements) {
		var element = form.elements[i];
		if (!element.type || !element.tagName) continue;
		if (element.type == 'text' || element.tagName.toLowerCase() == 'textarea') element.value = ''; 
		if (element.type == 'checkbox' || element.type == 'radio') element.checked = false;
		// selecting the first element in popupmenu
		if (element.tagName.toLowerCase() == 'select') element[0].selected = true;
	}
}

/* options = {
	on_success, success
} */
function jqSubmitForm (oForm, o) {
	if (!oForm) return false;
	var jqForm = $(oForm);
	if (!jqForm.attr('action')) return false;

	if (!o) o = {
		on_success: null, // execute function inside the standard success handler
		on_error: null,   // execute function inside the standard error handler
		success:	null, // replace success handler with the specified function
		dataType:	null  // non standard jQuery Ajax dataType
	};
	
	jqForm.find('[__hasChangedCSS]').each(function() {
		var jqThis = $(this);
		jqThis.css({	
			borderLeft: jqThis.attr('__orgBorderLeft'),
			borderTop: jqThis.attr('__orgBorderTop')
		});
	});

	jqForm.find(':text, :password').removeClass('ajax_error');
	
	var jqProgress = jqForm.find("[submitProgress]");
	if (jqProgress.length > 0) setTimeout(function() {jqProgress.show()}, 0);
	
	$.ajax({
		type: jqForm.attr('method') || 'get',
		url: jqForm.attr('action'),
		dataType: (o.dataType ? o.dataType : 'html'),
		cache: false,
		data: getFormValues(oForm),
		beforeSend: function(request) {
			request.setRequestHeader("X-Twibo-Ajax-Version", "2");
			request.setRequestHeader("X-Twibo-Top-Template", __stuffed.topTemplate);
			request.setRequestHeader("X-Twibo-Container-Width", jqForm.parent().width());
		},
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			var data = XMLHttpRequest.responseText;

			jqProgress.hide();
			
			if (o.on_error) o.on_error(data, jqForm);
			
			var jqResponseContainer = $("<div>").html(data);
			var jqErrorMessage = jqResponseContainer.find('#__ajax_error_message');
			if (jqErrorMessage.length > 0) {
				var strFormFields = jqResponseContainer.find('#__ajax_error_fields').text();
				var jqFirstErrorField = null;
				if (strFormFields) {
					var oFormFields = eval(strFormFields);
					for (var i = 0; i < oFormFields.length; i++) {
						var jqField = $(oForm[oFormFields[i]]).eq(0);
						if (!jqFirstErrorField) jqFirstErrorField = jqField;
						if (jqField.is(':text, :password')) {
							jqField.addClass('ajax_error');
						}
						else {
							var jqParent = jqField.closest("td");
							jqParent.attr({
								__hasChangedCSS: 1,
								__orgBorderLeft: jqParent.css('borderLeft') ? jqParent.css('borderLeft') : 'none',
								__orgBorderTop: jqParent.css('borderTop') ? jqParent.css('borderTop') : 'none'
							});
							jqParent.css({
								borderLeft: '1px solid red', 
								borderTop: '1px solid red'
							});
						}
					}
				}
				
				var fCallback = null
				if (jqFirstErrorField) {
					fCallback = function() { jqFirstErrorField.trigger("focus")	};
				} else {
					fCallback = function() { jqForm.find("input[type=text] textarea").eq(0).trigger("focus")	};
				}
				
				$.prompt(jqErrorMessage.text(), {callback: fCallback});
			} else {
				if (data) {
					$.prompt(data, {
						callback: function() {
							jqForm.find("input[type=text]").eq(0).trigger("focus")
						}
					});
				} else {
					jqForm.find("input[type=text]").eq(0).trigger("focus")
				}
			}
		},
		success: function (data, textStatus) {
			jqProgress.hide();
		
			if (o.success) {
				o.success(data, jqForm);
			} else {
				jqForm.parent().fadeOut('normal', function() {
					var jqFormContainer = $(this);
					jqFormContainer.html(data).fadeIn('normal', function() {
						if (o.on_success) o.on_success(data, jqFormContainer);
						jqFormContainer.find("input[type=text] textarea").eq(0).trigger("focus");
					});
					if ($.scrollTo) $.scrollTo(jqFormContainer, {duration: 1000})
				});
			}
		}
	});
		
	return false;
}

/* options = {
	oClicked or jqClicked, ajaxURL, ajaxData, rowClass, idPostfix, toggleLinks, 
	removeOnClose, success = function, error = function, noClose, indicatorURL,
	jqRow, noAnime
} */
function jqLoadExtraRow(options) {
	if (!options) options = {};
	
	if (options['oClicked']) options['jqClicked'] = $(options['oClicked']); 
	if (options['jqClicked'].attr('inProcess')) return false;
	if (!options['idPostfix']) options['idPostfix'] = '_extra';
	if (!options['indicatorURL']) options['indicatorURL'] = 'images/indicator.gif';
	
	options['jqClicked'].attr({inProcess: true}); 
	
	var jqRow;
	if (options.jqRow) {
		jqRow = options.jqRow;
	} else {
		if (options.jqClicked.get(0).tagName.toLowerCase() == 'tr') {
			jqRow = options.jqClicked;
		} else {
			jqRow = options.jqClicked.parents("tr").eq(0);
		}
	}
	var idRow = jqRow.attr("id");
	
	var extraRowId = idRow+options.idPostfix;
	var jqExtraRow = $("#"+extraRowId);
	
	// the additional row has not been created yet
	if (jqExtraRow.length < 1) {
		jqExtraRow = $(document.createElement('tr')).attr({
			'id': extraRowId, 
			'__opened': 1,
			'class': options['rowClass'] || jqRow.attr('class')
		}).insertAfter(jqRow);
		
		var totalCells = 0;
		jqRow.children().each(function() {
			var colSpan = $(this).attr('colSpan');
			totalCells += colSpan ? parseInt(colSpan) : 1;
		});
		
		var jqCell = $(document.createElement('td')).attr({colSpan: totalCells}).css({padding: 0});
		jqCell.html('<img src="'+options.indicatorURL+'" width="16" height="16" style="margin: 5px">');
		jqCell.appendTo(jqExtraRow);
		
		$.ajax({
			url: options['ajaxURL'],
			data: options['ajaxData'],
			beforeSend: function(request) {
				request.setRequestHeader("X-Twibo-Top-Template", __stuffed.topTemplate);
				request.setRequestHeader("X-Twibo-Container-Width", jqCell.width());
			},
			cache: false,
			success: function (data, textStatus) {
				jqCell.get(0).oClicked = options['jqClicked'].get(0); 
				if (options['success']) {
					options['success'](data, jqCell);
				} else {
					jqCell.html(data);
				}
				if (options['toggleLinks']) {
					options['jqClicked'].parent().hide().next().show();
				}
				options['jqClicked'].removeAttr('inProcess');
				jqCell.find("input[type=text] textarea").eq(0).trigger("focus");
			},
			error: function(XMLHttpRequest, textStatus, errorThrown) {
				jqCell.get(0).oClicked = options['jqClicked'].get(0);
				options['jqClicked'].removeAttr('inProcess');
				if (options.error) {
					options.error(XMLHttpRequest.responseText, jqCell);
				} else if (XMLHttpRequest.responseText) {
					$.prompt(XMLHttpRequest.responseText);
				}
				jqExtraRow.remove();
			}
		});
	} 

	// the additional row already exists we just need to toggle its visibility	
	else {
		// if the row is currently opened, close it
		if (jqExtraRow.attr("__opened") == 1) {
			jqExtraRow.attr({__opened: 0});
			var func = function () {
				if (options['toggleLinks']) {
					options['jqClicked'].parent().hide().prev().show();
				}
				options['jqClicked'].removeAttr('inProcess');
				if (options['removeOnClose'] || options['noClose']) jqExtraRow.remove();
				if (options['noClose']) jqLoadExtraRow(options);
			};
			if (options.noAnime) {
				jqExtraRow.hide();
				func();
			} else {
				jqExtraRow.fadeOut("normal", func);
			}
		} else {
			jqExtraRow.attr({__opened: 1});
			var func = function() {
				if (options['toggleLinks']) {
					options['jqClicked'].parent().hide().next().show();
				}
				options['jqClicked'].removeAttr('inProcess');
			};
			if (options.noAnime) {
				jqExtraRow.show();
				func();
			} else {
				jqExtraRow.fadeIn("normal", func);
			}
		}
	}

	return false;
}

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function execWhenReady(elemId, func) {
	var interval = setInterval(function() {
		// content not in the DOM yet
		if ($("#"+elemId).length < 1) return false;
		clearInterval(interval);
		func();
	}, 100);
}
