/**
************************************************************************
*	
************************************************************************
*/

Cobalt.Website.Form.API = function(){
		
	/*********************************************/
	/* DEFAULT SETTINGS */
	
	var _formSettings = {
		method : "post"
		,action : "leadSubmission.do"
		,inlineValidation : false
		,validationEventTriggers :"change"
		,validationEventTriggersForCheckboxAndRadio :"click"
		,validationEventTriggersForSelect :"change"
		,apiEventNameSpace : "cobaltFormApi"
		,ajaxSubmit : false
		,rulesNS : window  //namespace for custom rule-functions
		,formContainerId : "form_mainContainer"
		
		,success :  function(theForm) { 
			_defaultSuccessHandler(theForm);
		}
		,failure : function(theForm) {
			_defaultFailHandler(theForm);
		}
		,elementFailure : function(elemNode, /* optional */errorText) {
			var _errorText = errorText || "";
			_defaultElementFailHandler(elemNode, _errorText);
		}
		,elementSuccess : function(elemNode) {
			_defaultElementSuccessHandler(elemNode);
		}
		
		,validationAdapter : Cobalt.Website.Form.jQueryValidationEngineAdapter
		
		,elementsToValidate : {}
		
		,fieldErrorClass : "fieldErrorFlag"
		,labelErrorClass : "labelErrorFlag"
		,fieldGroupErrorClass : "fieldGroupErrorFlag"
		
		,widgetId : null
		,widgetInstanceId : null
		,widgetContainerId : "quickContactWidget"
		,widgetValidationContainerClass : "validationError"
	};
	
	/****************************/
	
	var _defaultSuccessHandler = function(theForm) {
		if (document.getElementById("otherAddInformation") != null) {addTaxi();}
			theForm.submit(); /* the onsubmit event handler is not executed */
	}
	
	var _defaultFailHandler = function(theForm) {
		// Add validation alert
		if (jQuery('#validationAlert').length < 1) {
			var validationAlert = document.createElement('div');
			jQuery(validationAlert).attr("id", "validationAlert");
			jQuery(validationAlert).text(ERRORMESSAGE_ENTER_REQUIRED_DATA);	
			jQuery("#" + _formSettings.formContainerId).before(validationAlert);
		} else {
			jQuery('#validationAlert').text(ERRORMESSAGE_ENTER_REQUIRED_DATA).show();	
		}
	}
	
	var _defaultElementFailHandler = function(elemNode, errorText) {
		jQuery(elemNode).addClass(_formSettings.fieldErrorClass).parent().find("span.required").addClass(_formSettings.fieldGroupErrorClass);
	}
	
	var _defaultElementSuccessHandler = function(elemNode) {
		jQuery(elemNode).removeClass(_formSettings.fieldErrorClass).parent().find("span.required").removeClass(_formSettings.fieldGroupErrorClass);
	}
	
	/*******************************************************************/
	/* Widget Handlers  */
	/*******************************************************************/

	var _widgetValidationContainer = jQuery("." + _formSettings.widgetValidationContainerClass);
	if (_formSettings.widgetId != null) {
		_widgetValidationContainer = jQuery("#" + _formSettings.widgetId + " ." + _formSettings.widgetValidationContainerClass);
	}

	var _ajaxSuccessHandler = function(data) {
		_publishEvent({ // com.cobaltgroup.ws.leadform.ajax.success
			eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _AJAX_TOKEN + _EVENT_SEPARATOR + _SUCCESS_EVENT
			,publisherData : {
				data : data
			}
		});
	}
	
	var _ajaxFailHandler = function(xhr, status, error) {
		_publishEvent({ // com.cobaltgroup.ws.leadform.ajax.error
			eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _AJAX_TOKEN + _EVENT_SEPARATOR + _FAIL_EVENT
			,publisherData : {
				xhr : xhr
				,status : status
				,error : error
			}
		});
	}
	
	var _ajaxValidationFailHandler = function(msg) {
		_publishEvent({ // com.cobaltgroup.ws.leadform.ajax.submit.error
			eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _AJAX_TOKEN + _EVENT_SEPARATOR + _SUBMIT_EVENT + _EVENT_SEPARATOR + _FAIL_EVENT
			,publisherData : {
				message : msg
			}
		});
	}
	
	/****************************/
	
	var _validationErrors;
	
	var _appendValidationError = function(err) {
		_validationErrors += err;
	}
	
	/****************************/
	
	var _validationRules = {
		"required":{    			  
			"regex":"none",
			"alertText":"This field is required",
			"alertTextCheckboxMultiple":"Please select an option",
			"alertTextCheckboxe":"This checkbox is required"},
		"length":{
			"regex":"none",
			"alertText":"Between ",
			"alertText2":" and ",
			"alertText3": " characters allowed"},
		"minCheckbox":{
			"regex":"none",
			"alertText":"Checks allowed Exceeded"},	
		"confirm":{
			"regex":"none",
			"alertText":"Your field is not matching"},	
		"onlyNumber":{
			"regex": new RegExp("^[1-9]+[0-9]*$"),
			"alertText":"Numbers only"},	
		"noSpecialCaracters":{
			"regex":"/^[0-9a-zA-Z]+$/",
			"alertText":"No special caracters allowed"},	
		"onlyLetter":{
			"regex":"/^[a-zA-Z\ \']+$/",
			"alertText":"Letters only"},
		// Cobalt Rules
		"isEmail":{
			// This 'regex' differs from above usage. The properties.js values are RegExp objects
			"regex":_VALIDATION_EMAIL,
			"alertText":_VALIDATION_FORMATERROR_EMAIL},						
		"isNumericPhoneFax":{
			"regex":_VALIDATION_NUMERIC_PHONEFAX,
			"alertText":_VALIDATION_FORMATERROR_NUMERIC_PHONEFAX},
		"isAddress":{
			"regex":_VALIDATION_ADDRESS,
			"alertText":_VALIDATION_FORMATERROR_ADDRESS},
		"isCity":{
			"regex":_VALIDATION_CITY,
			"alertText":_VALIDATION_FORMATERROR_CITY},
		"isZip":{
			"regex":_VALIDATION_ZIP,
			"alertText":_VALIDATION_FORMATERROR_ZIP},
		"isOdometer":{
			"regex": _VALIDATION_ODOMETER,
			"alertText":_VALIDATION_FORMATERROR_ODOMETER},
		"isYear":{
			"regex": new RegExp("^" + _VALIDATION_DATE_ALLYEARS + "?$"),
			"alertText":_VALIDATION_FORMATERROR_YEAR},
		"isMoney" : {
			"regex": _VALIDATION_MONEY,
			"alertText":_VALIDATION_FORMATERROR_MONEY},
		"isPhoneFax" : {
			"regex": _VALIDATION_PHONEFAX,
			"alertText": _VALIDATION_FORMATERROR_NUMERIC_PHONEFAX},
		"isSSNumber" : {
			"regex": _VALIDATION_SSN,
			"alertText": _VALIDATION_FORMATERROR_SSN},
		"isFreeformDate" : {
			"regex": _VALIDATION_DATE,
			"alertText": _VALIDATION_FORMATERROR_DATE}
		// END Cobalt rules
	};
	
	var _ROOT_EVENT_NAME = "com.cobaltgroup.ws.leadform";
	var _EVENT_SEPARATOR = ".";
	var _AJAX_TOKEN = "ajax";
	var _ELEMENT_TOKEN = "element";
	var _CHANGE_EVENT = "change";
	var _SUCCESS_EVENT = "success";
	var _FAIL_EVENT = "error";
	var _SUBMIT_EVENT = "submit";
	
	/* END DEFAULT SETTINGS */
	/*************************************************************************************/
		
	var _formName = null;
	var _form = null;
	
	var _formRegistered = false;
	
	/*********************************************/
	
	var _validateOverrides = function(settings){
		for(var configname in settings) {
			if(typeof _formSettings[configname] == 'undefined') throw 'Illegal Form Setting Override: '+configname;
		}
		return true;
	}
	
	var _publishEvent = function(eventData) {
		// validate eventData ? 
		EventManager.publish(eventData);
	}
		
	/*******************************************************************/
	/* Inline Validation  */
	/*******************************************************************/
	/**
	*	Set an onchange handler for each element to validate
	*/
	var _bindElementEvents = function(elemOb) {
		var changeEvent, elemName, elemNode;
		var focusEvent = _getFocusEventString();
		for (elemName in elemOb) {
			elemNode = _form[elemName];
			if (elemNode) {
				changeEvent = _getChangeEventString(elemNode.type);
				jQuery(elemNode).bind(changeEvent, _onElementChange);
				// Also add behavior : On focus, if field is already flagged, then do validation action (such as show prompt)
				jQuery(elemNode).bind(focusEvent, _onElementFocus);
			} else {
				//error - elemName is not a form element
			}
		}
	}
	/**
	*	Remove onchange handlers for an element
	*   elemName		The name of the form element to unbind
	*/
	var _unbindElementEvents = function(elemName) {
		var changeEvent, elemNode;
		var focusEvent = _getFocusEventString();
		elemNode = _form[elemName];
		if (elemNode) {
			changeEvent = _getChangeEventString(elemNode.type);
			jQuery(elemNode).unbind(changeEvent, _onElementChange);
			jQuery(elemNode).unbind(focusEvent, _onElementFocus);
		} 
	}
	
	/** 
	*	Given the element's type, return the proper change event, appended with the Cobalt event namespace
	*/
	var _getChangeEventString = function(elemType) {
		var changeEvent, i;
		if (elemType.indexOf("select") != -1) {
			changeEvent = _formSettings.validationEventTriggersForSelect;
		} else if (elemType == "checkbox" || elemType == "radio") {
			changeEvent = _formSettings.validationEventTriggersForCheckboxAndRadio;
		} else {
			changeEvent = _formSettings.validationEventTriggers;
		}
		// Handle multiple event types : each one gets the API namespace appended
		// 	eg: "click change" becomes "click.cobaltFormApi change.cobaltFormApi"
		var evTypes = changeEvent.split(" ");
		for (i=0; i<evTypes.length; i++) {
			evTypes[i] += "." + _formSettings.apiEventNameSpace;
		}
		return evTypes.join(" ");
	}
	/** 
	*	Return the focus event, appended with the Cobalt event namespace
	*/
	var _getFocusEventString = function() {
		return "focus" + "." + _formSettings.apiEventNameSpace;
	}
	
	/** 
	*	This function will be executed when a form element is changed
	*/
	var _onElementChange = function(ev) {
		_publishEvent({
			eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _ELEMENT_TOKEN + _EVENT_SEPARATOR + _CHANGE_EVENT
			,publisherData : {
				element : this
			}
		});
		_validateElement(this);
	}
	
	/** 
	*	This function will be executed when a form element is focused
	*/
	var _onElementFocus = function(ev) {
		if (jQuery(this).hasClass(_formSettings.fieldErrorClass)) {
			_validateElement(this);
		}
	}
	
	/*******************************************************************/
	/* FORM SUBMISSION */
	/*******************************************************************/
	
	var _bindSubmit = function() {
		var submitMethod = (_formSettings.ajaxSubmit) ?  _onAjaxSubmit : _onSubmit;
		
		jQuery(_form).bind("submit", function(ev) {
			return submitMethod();
		})
	}
	
	var _resetValidation = function() {
		// Hide any previous validation messages
		_validationErrors = null;
		_widgetValidationContainer.hide(); // This might run into collisions if there's multiple forms on a page.
		jQuery('.' + _formSettings.fieldErrorClass).removeClass(_formSettings.fieldErrorClass);
	}
	
	var _onAjaxSubmit = function() {
		_resetValidation();
		
		var formValid = _validateAjaxForm();
		var ajaxForm = jQuery("#" + _formSettings.widgetContainerId + _formSettings.widgetInstanceId);
		
		if (formValid) {
			var formData = ajaxForm.serialize() + '&web_id=' + ContextManager.getWebId();
			// AJAX submission
			jQuery.ajax({
				url: _formSettings.action,
				data: formData,
				type: _formSettings.method,
				error: function(xhr, status, error){
					_ajaxFailHandler(xhr, status, error);
				},
				success: function(data){
					_ajaxSuccessHandler(data);
				}
			});
		}
		return false;
	}
	
	var _onSubmit = function() {
		_publishEvent({
			eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _SUBMIT_EVENT
			,publisherData : {
				formName : _formName
			}
		});
		
		try {
			_validateForm();
			//
			// success
			_publishEvent({
				eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _SUCCESS_EVENT
				,publisherData : {
					formName : _formName
				}
				// execute success function after handlers are done
				,callback : function() {
					_formSettings.success(_form);
				}
			});
			
		} catch (err) {
			// Need exception class?
			
			_formSettings.failure(_form);
			
			_publishEvent({
				eventName : _ROOT_EVENT_NAME + _EVENT_SEPARATOR + _FAIL_EVENT
				,publisherData : {
					formName : _formName
				}
			});
			
		} finally {
			return false;
		}
	}
	
	/*******************************************************************/
	/* VALIDATION */
	/*******************************************************************/
	
	var _validationAdapter = null;
	var _ValidationAdapterInterface = new Cobalt.Core.Interface("_ValidationAdapterInterface", ["registerForm", "validateElement", "setValidationRules"]);
	
	var _registerValidationAdapter = function() {
		Cobalt.Core.Interface.ensureImplements(_formSettings.validationAdapter, _ValidationAdapterInterface);
		_validationAdapter = _formSettings.validationAdapter;
	}
	
	var isEmpty =function(testVar)  {
		if ((testVar == undefined) || (testVar == null) || (testVar == "null") || (testVar == "") || (testVar == "undefined")) {
			return true;
		}
		return false;
	}
	
	var addTaxi = function() {
			var taxiPref;
			var additionalInfoText = document.getElementById("otherAddInformation").value;
			if (!isEmpty(pageForm)) {
				if (!isEmpty(pageForm.taxi)) {
					for (var  i=0; i < pageForm.taxi.length; i++) {
						if (pageForm.taxi[i].checked) {
  							taxiPref = pageForm.taxi[i].value;
  						}
					}
					document.getElementById("otherAddInformation").value = "Solicitud de taxis: " + taxiPref + ", Comentario: " + additionalInfoText;	
				}
			}	
		}
	
	var _validateForm = function() {
		// resetErrors
		var validationPass = true;
		var elementIsValid;
		
		for (elemName in _formSettings.elementsToValidate) {
			var elemNode = _form[elemName];
			if (elemNode) {
				elementIsValid = _validateElement(elemNode);
				if (!elementIsValid) {
					validationPass = false;
				}
			}
		}
		
		if (!validationPass) {
			throw new Error("form error");
		}
	}
	
	var _validateAjaxForm = function() {
		var validationPass = true;
		var elementIsValid;
		var msg = ERRORMESSAGE_ENTER_REQUIRED_DATA; //"This is where I should tell you what didn't validate";
		
		for (elemName in _formSettings.elementsToValidate) {
			var elemNode = _form[elemName];
			if (elemNode) {
				elementIsValid = _validateElement(elemNode);
				if (!elementIsValid) {
					validationPass = false;
				}
			}
		}
		if (!validationPass) {_ajaxValidationFailHandler(msg)}; // + ": " + _validationErrors)};
		
		return validationPass;
	}
	
	// We expect a result object to be returned from _validationAdapter.validateElement
	// 	If not, then assume a Boolean
	var _validateElement = function(elemNode) {
		var validationPass;
		var errorText = "";
		
		validationResult = _validationAdapter.validateElement(elemNode);
		
		if (typeof validationResult == "object") {
			validationPass = validationResult.isValid || false;
			errorText = validationResult.errorText || "";
		} else if (typeof validationResult == "boolean") {
			validationPass = validationResult;
		} else {
			validationPass = false;
		}
		
		if (!validationPass) {
			_formSettings.elementFailure(elemNode, errorText);
			_appendValidationError(errorText);
		} else {
			_formSettings.elementSuccess(elemNode);
		}
		return validationPass;
	}
	
	/************************************************************************************************************/
	/************************************************************************************************************/
	return {
		
		ROOT_EVENT_NAME : _ROOT_EVENT_NAME
		,EVENT_SEPARATOR : _EVENT_SEPARATOR
		,AJAX_TOKEN : _AJAX_TOKEN
		,ELEMENT_TOKEN : _ELEMENT_TOKEN
		,CHANGE_EVENT : _CHANGE_EVENT
		,SUCCESS_EVENT : _SUCCESS_EVENT
		,FAIL_EVENT : _FAIL_EVENT
		,SUBMIT_EVENT : _SUBMIT_EVENT
		
		,registerForm : function(formName, /* optional */settings) {
			// validate settings
			if (settings) this.overrideFormSettings(settings);
			
			_formName = formName;
			_form = document.forms[_formName];
			_form.method = _formSettings.method;
			_form.action = _formSettings.action;
			_form.ajaxSubmit = _formSettings.ajaxSubmit;
						
			// Set validation adapter
			_registerValidationAdapter();
			_validationAdapter.setValidationRules(_validationRules);
			_validationAdapter.registerForm(_form, _formSettings);
			
			// if inlineValidation is used, elements must be activated to publish events
			if (_formSettings.inlineValidation) {
				_bindElementEvents(_formSettings.elementsToValidate);
			}
			
			// bind submit
			_bindSubmit();
			
			_formRegistered = true;
		}
		
		,overrideFormSettings: function(settings) {
			_validateOverrides(settings);
			_formSettings = jQuery.extend(_formSettings, settings);	
		}
		
		/**
		*	elemOb		Collection of form elements belonging to a particular form section
		*/
		,registerElements : function(elemOb) {
			_formSettings.elementsToValidate = jQuery.extend(_formSettings.elementsToValidate, elemOb);	
			
			if (_formSettings.inlineValidation && _formRegistered) {
				_bindElementEvents(elemOb);
			}
		}
		
		/**
		*	Remove elements from the collection and unbind event handlers.
		* elemArr  		An array of element names
		*/
		,unRegisterElements : function(elemArr) {
			var i, len = elemArr.length;
			for (i=0; i<len; i++) {
				if (_formSettings.elementsToValidate[elemArr[i]]) {
					if (_formSettings.inlineValidation) {
						_unbindElementEvents(elemArr[i]);
					}
					delete _formSettings.elementsToValidate[elemArr[i]];
				}
			}
		}
		
		,setValidationRules : function(rulesOb) {
			_validationRules = jQuery.extend(_validationRules, rulesOb);
			_validationAdapter.setValidationRules(_validationRules);
		}
		,getValidationRules : function() {
			return _validationRules;
		}
		
		/***********************************************************/
		,getElementsToValidate : function() {
			return _formSettings.elementsToValidate;	
		}
		
		,getValidationAdapter : function() {
			return _validationAdapter;
		}
		
		,getFormSettings : function() {
			return _formSettings;
		}
		
		,getForm : function() {
			return _form;
		}
		/***********************************************************/
	};
}();



