
var Bitrockers_iForm_ajaxRequest = new Class({

	initialize:		function(iFormObject, focusElement, blockID)	{
		this.iFormObject = iFormObject;
		this.focusElement = focusElement;
		this.blockID = blockID;
	},
	complete:		function(request)	{
		// simply call onComplete with request
		this.iFormObject.onComplete(request, this.focusElement, this.blockID);
	}

});

var Bitrockers_iForm = new Class({

	def_iFormBlock: 'iFormBlock',
	def_iFormContainerActive: 'iFormContainerActive',
	def_iFormBlockAlert: 'iFormBlockAlert',
	def_iFormHint: 'iFormHint',
	def_iFormHintActive: 'iFormHintActive',
	def_iFormHintAlert: 'iFormHintAlert',

	iFormBlocks: [],
	inputTags: [],
	activeAlertBlocks: {},
	formID: null,
	inputFields: {},
	focusedElement: null,
	activeContainer: null,
	checks: {},
	freshErrors: {},

	initialize:			function(formID, check)	{

		// not nothing if form id is empty
		this.checks = {};
		if (check)	this.checks = check;
		if (!formID)	return;
		if (!$(formID))	return;
		this.formID = formID;

		// empty new variables
		this.inputTags = [];
		this.iFormBlocks = [];
		this.activeAlertBlocks= {};
		this.inputFields = {};
		this.focusedElement = null;
		this.activeContainer = null;
		this.freshErrors  = {};


		// form id given? look for all form-"block"
		var formBlocks = $$('#' + formID + ' .' + this.def_iFormBlock);
		for(var i = 0; i < formBlocks.length; i++)	{
			var block = formBlocks[i];
			var blockID = block.id;
			var blockArray = { 'id': blockID };

			// find parent iFormContainer
			var container = block.getParent();
			blockArray['container'] = container;

			// find elements (first) formHint
			var formHint = null;
			var formHints = $$('#' + blockID + ' .' + this.def_iFormHint);
			if (formHints.length > 0)	{
				formHint = formHints[0];
			}
			blockArray.formHint = formHint;

			// find elements input tags, and store first input tag
			var inputTags = $$('#' + blockID + ' input');
			inputTags.extend($$('#' + blockID + ' textarea'));
			inputTags.extend($$('#' + blockID + ' select'));
			for(var j =0; j < inputTags.length; j++)	{
				inputTags[j].id = blockID + '_' + inputTags[j].name;
				inputTags[j].onfocus = this.selectBlock.bind(this, [blockID, inputTags[j].id]);
				inputTags[j].onblur = this.unselectBlock.bind(this, [blockID, inputTags[j].id]);
				this.inputTags.push({id: inputTags[j].id, blockID: blockID });
				this.inputFields[inputTags[j].name] = { blockID: blockID, id: inputTags[j].id };
			}
			if (inputTags.length > 0)	blockArray.firstInputTag = inputTags[0];

			// find hint
			var hintBlock = $$('#' + blockID + ' .' + this.def_iFormHint);
			if (hintBlock.length == 1)	{
				hintBlock[0].id = formID + '_' + blockID + '_hint';
				blockArray.hintBlock = hintBlock[0].id;	// store id to global object
			}

			// add on mouse over / field focus
			block.addEvent('click',this.clickBlock.bind(this,blockID));


			// store block in array
			this.iFormBlocks[blockID] = blockArray;
		}
	},


	selectBlock:	function(blockID, focusElement)	{
		$(this.iFormBlocks[blockID].container).addClass(this.def_iFormContainerActive);
		// $(blockID).addClass(this.def_iFormBlockActive);
		if (this.iFormBlocks[blockID]['formHint'] != null)	this.iFormBlocks[blockID]['formHint'].addClass(this.def_iFormHintActive);
		this.focusedElement = focusElement;
	},

	unselectBlock:	function(blockID, focusElement)	{
		$(this.iFormBlocks[blockID].container).removeClass(this.def_iFormContainerActive);
		if (this.iFormBlocks[blockID]['formHint'] != null)	this.iFormBlocks[blockID]['formHint'].removeClass(this.def_iFormHintActive);
		if (this.focusedElement == focusElement)	this.focusedElement = null;

		// do we have to perform a check for this field?
		// if (this.checks[$(focusElement).name])	this.checkElement(focusElement, blockID);
		if (this.checks[$(focusElement).name])				this.checkElement.bind(this, [focusElement, blockID]).delay(200);
	},

	clickBlock:		function(blockID)	{
		if (this.iFormBlocks[blockID].firstInputTag && this.focusedElement == null)	this.iFormBlocks[blockID].firstInputTag.focus();
	},

	makeAlertBlock:	function(blockID)	{
		$(blockID).addClass(this.def_iFormBlockAlert);
		this.alertBlocks['blockID'] = true;
	},
	removeAlertBlock: function(blockID)	{
		$(blockID).removeClass(this.def_iFormBlockAlert);
		this.alertBlocks['blockID'] = false;
	},

	checkTrim:		function(text)	{
		  return text.replace(/^\s+|\s+$/g, '') ;
	},

	checkElement:	function(focusElement, blockID, submitted)	{

		// returns true on success, false if an error occured
		var el = $(focusElement);
		var check = this.checks[el.name];
		var value = this.checkTrim(el.value);

		if (check == undefined)	return true;		// check is successfull, if no check was defined :)

		// if send is in progress, and this call has not been made from submitting, cancel this call
		if (this.sendInProgress === true && !submitted) {

			// prevent ajax from thinking changed value is error
			check.lastAjaxCheck = '___submittedform___';
			return;
		}

		// empty allowed?
		var empty = false;
		if (check.allowEmpty && value === '')	empty = true;


		// check if min/maxlength
		var error = false;
		if (check.minLength && check.minLength.value > value.length)	error = check.minLength.error;
		if (check.maxLength && check.maxLength.value < value.length)	error = check.maxLength.error;
		if (check.alNum)	{
			var alNum = /[^0-9a-zA-Z_\-]/;
			if (alNum.test(value))	error = check.alNum.error;
		}
		if (check.isChecked && !el.checked)	error = check.isChecked.error;
		if (check.length && check.length.value != value.length)	error = check.length.error;
		if (check.minValue && !empty && check.minValue.value > value)	error = check.minValue.error;
		if (check.maxValue && !empty && check.maxValue.value < value)	error = check.maxValue.error;


		// do the ajax check only when this is not called from submitting action
		if (error == false && check.ajax && check.lastAjaxCheck != value && submitted !== true)	{
			// do the ajax check
			var postBody = {}; postBody[el.name] = value;
			var ajaxRequest = new Bitrockers_iForm_ajaxRequest(this, focusElement, blockID);
			var options = { method: 'POST', postBody: postBody, onComplete: ajaxRequest.complete.bind(ajaxRequest) };
			var ajax = new Ajax(check.ajax.url, options).request();

			// show loading ani
			el.addClass('iFormInputLoading');

			// mark this field as "ajax checked" with the specified values
			this.checks[el.name].lastAjaxCheck = value;
		} else if (check.lastAjaxCheck == value)	{
			return check.lastAjaxSuccess;		// dont't change state, return last saved return code
		}

		if (error !== false)	{
			this.freshErrors[blockID]++;
			this.showError(focusElement, blockID, error);
			return false;
		} else {
			if (this.freshErrors[blockID] == 0 || !submitted)	this.hideError(focusElement, blockID);
			return true;
		}
	},

	onComplete:	function(request, focusElement, blockID)	{
		var el = $(focusElement);

		// disable loading
		$(focusElement).removeClass('iFormInputLoading');

		// check if ok or error
		if (request == 'OK')	{
			this.checks[el.name].lastAjaxSuccess = true;
			return;
		}

		// else show error
		this.checks[el.name].lastAjaxSuccess = false;
		this.showError(focusElement, blockID, request);

	},

	initError:	function(focusElement, blockID)	{
		// alreary initialized?
		var errorID = this.formID + '_' + blockID + '_error';
		if ($(errorID))	return $(errorID);
		// create new error-element
		var error = new Element('div');
		error.id = errorID;
		error.addClass('hide');
		error.addClass(this.def_iFormHint); error.addClass(this.def_iFormHintAlert);
		var hintBlock = $(this.iFormBlocks[blockID].hintBlock);
		if (hintBlock == false)	{
			if (!focusElement || true)	{
				// ugly... we only have block id, so find first iFormField and inject before
				var iFormFields = $$('#' + blockID + ' .iFormField');
				var iFormField = iFormFields[0];
				error.setStyles({ 'width': '90%'});
				error.injectBefore(iFormField);
			} else {
				error.setStyles({'padding-top': '0px', 'padding-bottom': '5px', 'width': '100%'});
				error.injectBefore($(focusElement).getParent());
			}
		} else {
			// inject behind hint block
			error.injectAfter(hintBlock);
		}
		return error;
	},

	showError:	 function(focusElement, blockID, message)	{
		var error = this.initError(focusElement, blockID);
		error.innerHTML = message;
		if ($(this.iFormBlocks[blockID].hintBlock) != false) $(this.iFormBlocks[blockID].hintBlock).addClass('hide');
		error.removeClass('hide');
		this.activeAlertBlocks[blockID] = error.id;
		// $(blockID).effect('background-color').custom('#F3F9FF','#fffbb8');
		$(blockID).addClass(this.def_iFormBlockAlert);
	},

	hideError: function(focusElement, blockID)	{
		if (this.activeAlertBlocks[blockID] != undefined)	{
			$(this.activeAlertBlocks[blockID]).addClass('hide');
		};
		if (this.iFormBlocks[blockID].hintBlock != undefined)	{
			$(this.iFormBlocks[blockID].hintBlock).removeClass('hide');
		}
		$(blockID).setStyle('background','none');
		$(blockID).removeClass(this.def_iFormBlockAlert);
	},

	checkCompleteForm: function()	{
		// checks the complete form again for errors
		// returns true on success, or false on error
		var inputTags = this.inputTags;
		var noError = true;
		this.freshErrors = {};
		this.firstError = null;
		for(var i=0; i < inputTags.length; i++)	{
			var checkResult = this.checkElement(inputTags[i].id, inputTags[i].blockID, true);
			if (checkResult === false)	{
				noError = false;
				if (this.firstError == null)	this.firstError = inputTags[i].id;
			}
		}
		return noError;
	},

	resetErrors:		function()	{
		for (key in this.inputFields)	{
			this.hideError(key, this.inputFields[key].blockID);
		}
	},

	send: function(onComplete)	{
		if (this.sendInProgress)	return;
		this.sendInProgress = true;
		// check complete form
		if (!this.checkCompleteForm())	{
			if (this.firstError != null)	{
				var scrollError = new Fx.Scroll(window);
				var yPos = $(this.firstError).getPosition().y - 50;
				if (yPos < 0)	yPos = 0;
				scrollError.scrollTo(0, yPos);
			}
			this.sendInProgress = false;
			return;
		}

		// reset all erros
		this.resetErrors();

		// sends the form via ajax
		this.onFormSubmitHandle = onComplete;
		var options = { method: 'POST', onComplete: this.onSendComplete.bind(this) };
		$(this.formID).send(options);
	},

	onSendComplete: function(request)	{
		this.sendInProgress = false;
		// get response from server-side and redirect to calling function
		var response = parseJson(request);
		if (response.success != true)	{
			// show errors if avialable
			if (!response.errors)	{ alert('Unknown error!'); return; };
			var firstError = false;
			for(var i=0; i < response.errors.length; i++)	{
				var error = response.errors[i];
				var inputField = this.inputFields[error.field];
				this.showError(null, inputField.blockID, error.error);
				if (!firstError)	{
					// scroll to error
					var scrollError = new Fx.Scroll(window);
					var yPos = $(inputField.blockID).getPosition().y - 50;
					if (yPos < 0)	yPos = 0;
					scrollError.scrollTo(0, yPos);
					firstError = true;
				}
			}
		} else {
			this.onFormSubmitHandle(response);
		}

	}



});



var Bitrockers_iTableForm = new Class({

	initialize: 		function(formID, rowPrefix, checkboxPrefix)	{
		this.formID = formID;
		this.rowPrefix = rowPrefix + '_';
		this.checkboxPrefix = checkboxPrefix + '_';

		// default classes to add/remove on highlighting
		this.defaultBackgroundActiveClass = 'tableRowHighlight';

	},


	addCheckbox:		function(checkboxID)	{
		// adds a checkbox event
		$(this.checkboxPrefix + checkboxID).onclick = this.checkboxClick.pass(checkboxID, this);
		// for firefox because it sometimes on refresh leaves checkboxes checked
		this.checkboxClick.pass(checkboxID, this)();

	},

	checkboxClick:		function(checkboxID)	{
		var checkBox = $(this.checkboxPrefix + checkboxID);
		if (checkBox.checked)	{
			// get all elements in this form with class activated
			//var rows = $ES('td', this.rowPrefix + checkboxID);
			//for(var i=0; i < rows.length; i++)	{
			//	rows[i].toggleClass(this.defaultBackgroundActiveClass);
			//};
			$(this.rowPrefix + checkboxID).addClass(this.defaultBackgroundActiveClass);
		} else {
			$(this.rowPrefix + checkboxID).removeClass(this.defaultBackgroundActiveClass);
		}
	},

	toggleAll:			function()	{
		// toggle all checkboxes. so find all checkboxes, toggle, and call checkboxClick
		var checkboxes = $ES('input', this.formID);
		for(var i  = 0; i < checkboxes.length; i++)	{
			if (checkboxes[i].name && checkboxes[i].name.substr(0, this.checkboxPrefix.length) == this.checkboxPrefix)	{
				var id = checkboxes[i].name.substr(this.checkboxPrefix.length);
				checkboxes[i].checked = !checkboxes[i].checked;
				this.checkboxClick.pass(id, this)();
			}
		}

	},

	addSelectSubmit:	function(submitID)	{
		$(submitID).onchange = this.submitForm.pass(submitID, this);
	},

	submitForm:			function(submitID)	{
		if ($(submitID).value == '') return false;
		// eventually display progress
		var progress = $(submitID + '_progress');
		if (progress)	progress.setStyle('display','block');
		$(this.formID).submit();
	}



});




