// adds autoForm stuff to container
//
// _meef.autoForm is a new static (singleton) handler for creating
// new autoForms. The constructor is
// _meef.autoForm.init(formID)  whereas formID is the dom-id of the form.
// it returns a new AutoForm object.
//
// systems always expects a json-message. If no json ( header)
// is received, it'll be parsed as an error
//
// on success, it parses the following response data
// redirect:		url where to redirect the customer by javascript
// script:			any script that will get executed

// CUSTOM EVENTS
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Event: beforeSubmit(el)
// Gets triggered before the form is send via AJAX to the server. The el-parameter
// is the form that will be submitted
//
// Event: formError(event, data)
// Is triggered if the server response with an error. data parameter maybe unavailable (e.g. if the server
// is not reachable)
//
// Event: formSuccess (event,data)
// After there was a successful server response, this event gets triggered. event contains the
// ajax event handler, data all informationen (server response)


//
// for displaying the error messages:
// if there is a error in form exampleForm at the
// field firstName, this class tries to find a
// div-block with the id exampleForm__firstName_err
// if it is not found. it'll be injected before the input type
//
(function(container) {

	var $ = jQuery;

	// this is our object
	function AutoForm(formID, options)	{

		var self = {
			formID:		null,
			formName:	null,
			ajaxInProgrss: false,
			firstError: null,
			showedMessages: [],

			loadingBlocks: false,
			submitBlocks: false,


			options:	{errorScroll: true, 				// scroll to first error message
						iframe: false						// use iframe instead of ajax (e.g. file uploads)
						}
		};


		// 	inits the form, give formID and options for
		this.init =	function(formID, options)	{
			self.formName = formID;
			self.formID = '#' + formID;

			// mix options
			$.extend(self.options, options);

			// generate jquery selectors for loading and submit blocks
			// we use classes instead of ids because we want to be able to switch on/off multiple
			// submit/loading blocks
			self.loadingBlocks = self.formID + ' .' + self.formName + '_loading';
			self.submitBlocks = self.formID + ' .' + self.formName + '_submit';

			// bind form submit
			$(self.formID).bind('submit', self.formSubmit);
		}

		// event triggered on form submit
		this.formSubmit = function(event)	{
			event.preventDefault();

			$(self.formID).trigger('beforeSubmit', [self.formID]);

			// only allow one call a time
			if (self.ajaxInProgress)	return false;
			self.ajaxInProgress = true;

			// hide all error messages
			self.hideAllErrors(self.formID);

			// hide all displayed messages
			$.each(self.showedMessages, function(){
				$('#' + this).hide();
			});
			self.showedMessages = [];

			// switch loading-indicator and submit block?
			$(self.loadingBlocks).show();
			$(self.submitBlocks).hide();

			// submit form via ajax to action url
			var form = $(self.formID);
			var post = form.serialize();
			var url = form.attr('action');
			$.ajax({
				type:	'POST',
				url:	url,
				cache:	false,
				data:	post,
				error:	self.ajaxError,
				success:self.ajaxSuccess,
				dataType: 'json'
			});
		};


		// clears up some ajax stuff
		this.ajaxComplete =	function()	{
			self.ajaxInProgress = false;
			// reset loading/submit blocks?
			$(self.loadingBlocks).hide();
			$(self.submitBlocks).show();
		};
		// is called when an error on ajax call happens (e.g. server not reachable, or no json result)
		this.ajaxError = function(xmlHttp, errorMessage, ajaxException)	{
			self.ajaxComplete();
			$(self.formID).trigger('formError',[]);
		};

		// called if ajax call was successfull
		this.ajaxSuccess = function(data, textStatus)	{

			// check for application errors
			if (data.errors && data.errors.length > 0)	{
				self.showErrors(data.errors);
			}

			// check for redirect command
			if (data.redirect)	document.location = data.redirect;


			// re-enable ajax form
			self.ajaxComplete();

			// check for javascript
			if (data.script)	eval(data.script);

			// check if we should show messages
			if (data.showMessage)	self.showMessage(data.showMessage);

			// trigger custom events
			if (data.errors && data.errors.length > 0 )	{
				$(self.formID).trigger('formError', [data]);
			} else {
				$(self.formID).trigger('formSuccess', [data]);
			}

		};

		// displays a div with the given id
		this.showMessage = function(messageDiv)	{
			$('#' + messageDiv).css({opacity:0.01, display:'block'});
			container.scrollTo(messageDiv);
			if ($('#' + messageDiv).hasClass('_autoFormNoHide'))	{
				// dont automatic hide
				$('#' + messageDiv).animate({opacity: 1}, {duration: 200});
			} else {
				// hide automatic after x seconds
				$('#' + messageDiv).animate({opacity: 1}, {duration: 200}).pause(3000).animate({opacity: 0}).slideUp();
			}


			// store showed message, so on re-submit we can disable it
			self.showedMessages.push(messageDiv);
		};

		// reads array of errors and shows 'em
		this.showErrors = function(errors)	{
			self.firstError = null;	// reset first error
			$.each(errors, function(key, value){
				self.showError(value[0],value[1], value[2]);		// third parameter is optional blockid where to display/inject error
			});
		};

		// show the specified array
		this.showError = function(field, error, injectErrorField)	{

			// injectErrorField is optinonal, if not set, it should be the same as field
			if (!injectErrorField)	injectErrorField = field;

			// try to find existing error-div
			var errorBlock = $(self.formID + '_' + injectErrorField + '_err');
			if (!errorBlock[0])	{
				errorBlock = self.injectErrorBlock(injectErrorField);
				if (errorBlock == false)	return;			// unknown field name
			} else {
				errorBlock = errorBlock[0];
			}
			$(errorBlock).text(error).show().css('opacity',0.01).animate({opacity: 1});

			if ($(errorBlock).corner)	$(errorBlock).corner();

			// because we're going to show an error, add an onchange handler on that input field
			var errorFields = $(self.formID + ' *[name=' + field + ']');
			if (errorFields.length == 0)	return;
			var errorField = errorFields[0];
			$(errorField).bind('change', injectErrorField, self.hideErrorBlock);

			// is this the first error? scroll to error element
			if (self.firstError == null)	{
				self.firstError = field;
				$.scrollTo(errorBlock, {duration: 300, offset: {top: -30}  });
			}

		};

		this.injectErrorBlock = function(field)	{
			// no error block found? inject error block before input type
			// find input types
			var inputFields = $(self.formID + ' *[name=' + field + ']');
			if (inputFields.length == 0)	return false;		// didnt found
			var inputField = inputFields[0];

			// create error block and inject
			var newBlock = $('<div style="display:none" id="' + self.formName + '_' + field + '_err" class="autoForm_alert"></div>');
			newBlock.insertBefore(inputField);
			return newBlock;
		};

		// if inputfield changed, remove error block
		this.hideErrorBlock =	function(event)	{
			var field = event.data;
			$(self.formID + '_' + field + '_err').slideUp(100);
			// remove event from input field
			$(event.target).unbind('change', event.handler);
		};

		this.hideAllErrors = function()	{
			var formID = self.formID;
			$(formID + ' [id$=_err]').each(function(){
				$(this).hide();
			});
		}

		// merge self with this, so we can call externally AutoForm.init and internally self.init;
		$.extend(self, this);

		// call constructor
		this.init(formID, options);

	};

	// create and return new AutoForm object. Singleton wrapper for AutoForm object
	var self = {
		instances:	{},
		init:	function(formID, options)	{
			var obj =  new AutoForm(formID, options);
			self.instances[formID] = obj;				// store in local array, for later use
		},
		hideAllErrors: function(formID)	{
			self.instances[formID].hideAllErrors();
		}
	}
	container.autoForm = self;


})(_meef);









