/**
 * @author Xosé Antonio Rubal López <xantonio@si.usc.es>
 * @package Xescampus.SimpleForm
 * @version 0.0.1
 */
 
 /**
	Creamos o espazo de nomes Xescampus
 */
if(typeof(Xescampus) == 'undefined')
	var Xescampus = {};	
/**
	Control de formulario.
	
	Encapsula as funcións de cargar e actualizar un formulario vía Ajax.
	<script>
		new Xescampus.Form('http://...', 'contedor', 'formulario);
	</script>
	
	<form id="formulario">
		<input type='button'/>;
	</form>
*/

Xescampus.SimpleForm = Class.create();

Object.extend(Xescampus.SimpleForm.prototype, {
	/**
		Establece as propiedades básicas do formulario
		
		@url Localizador da URL de servidor que pinta o formulario
		@div Identificador do elemento que serve de contentor do formulario
		@form Identificador do formulario
		@options
			@buttonSave: id do elemento HTML que se utiliza para enviar o formulario ao servidor. Debe posuir un evento 'click'. O elemento típico é un <input type='button'/>
			@errorsContainer: id do elemento HTML que vai conter a lista de erros de validación, etc
			@errorsContainerList: id do elemento HTML que contén a lista de erros
			@loadMethod: método HTTP co que se vai facer a chamada de carga do formulario (tipicamente get)
			@saveMethod: método HTTP co que se vai facer a chamada de envío dos datos de formulario ao servidor (tipicamente post)
			@onSuccessMethod: método que se executa no caso de que a resposta no envío de datos devolva estado 200. Na implementación por defecto asume que a resposta é unha estrutura de datos JSON e segundo o código de estado
			executa onOkResponseStatus ou onErrorResponseStatus
			@onFailureMethod: método que se executa no caso de que a resposta no envío de datos devolva estado != 200. Na implementación por defecto mostra unha mensaxe nun diálogo de alerta (TODO: corrixir isto)
			@onOkResponseStatus: método que se invoca cando o estado da resposta (no formato JSON por defecto) é OK. TODO: facer que mostre unha confirmación de éxito
			@onErrorResponseStatus: método que se invoca cando o estado da resposta (no formato JSON por defecto) é ERROR. Por defecto mostra a lista de erros no errorDiv
	*/
	initialize:  function(url, div, form, options) {
		this.url = url;
		this.div = div;
		this.form = form;
		
		// Opcións por defecto
		this.options = {
			buttonSave: this.form + '.save',
			errorsContainer: this.form + '.errors',
			errorsContainerList: this.form + '.errors' + '.list',
			loadMethod: 'get',
			saveMethod: 'post',
			onSuccessMethod: this.defaultOnSuccess.bind(this),
			onFailureMethod: this.defaultOnFailure.bind(this),
			onOkResponseStatus: this.defaultOnOkResponseStatus.bind(this),
			onErrorResponseStatus: this.defaultOnErrorResponseStatus.bind(this),
			savingDiv: this.form + '.saving'
		}
		
		// Procesamento das opcións establecidas polo usuario
		Object.extend(this.options,options || {});
		
		/**
			Cargamos o formulario no contentor e instalamos o xestor do evento click do botón do formulario
		*/
		new Ajax.Request(url, {
				method: this.options.loadMethod,
				onSuccess: function(transport) {
					$(this.div).innerHTML = transport.responseText;
					Event.observe(this.options.buttonSave, 'click', this.onSave.bindAsEventListener(this));
				}.bind(this)
			});
	},
	
	/**
		Xestor do evento click do botón do formulario
	*/
	onSave : function() {
		$(this.options.errorsContainer).hide();
		$(this.options.savingDiv).show();
		$(this.form).request({
				method: this.options.saveMethod,
				onSuccess: function(transport){ 
					this.options.onSuccessMethod(transport);
				}.bind(this), 

				onFailure: function(transport){
					this.options.onFailureMethod(transport);
				}.bind(this)     			
			}
		);
	},
	
	/**
		Se ten éxito a petición asume que a resposta está escrita en formato JSON coa seguinte estrutura:
		
		- En caso de éxito:
		{
			status: 'OK'
		}
		- En caso de erro:
		{
			status: 'ERROR',
			globalErrors: [
					{code: 'codigo.error1', codes: [codigo.erro.1, codigo.erro.2,...] , defaultMessage: 'Produciuse un erro...', originalMessage: 'Global failure error ....' }    ,
					...
			]
			fieldErrors: [
				{code: 'codigo.error1', codes: [codigo.erro.1, codigo.erro.2,...] , defaultMessage: 'Produciuse un erro...', originalMessage: 'Global failure error ....', field: 'field.id' }    ,
			]
		}
	*/
	defaultOnSuccess : function(transport) {
		response = transport.responseText.evalJSON(true);
		if(response.status == 'OK') {
			this.options.onOkResponseStatus(response);
		}
		else if(response.status == 'ERROR') {
			this.options.onErrorResponseStatus(response);
		}
		else {
			alert('Estado da resposta incorrecto: ' + response.status + '. Os posibles valores son OK e ERROR');
		}
	},
	
	/**
		Tratamento por defecto dunha responsta incorrecta do XHR
	*/
	defaultOnFailure: function(transport) {
		$(this.options.savingDiv).hide();
		//alert('onFailure');
	},
	
	/**
		O tratamento por defecto é non facer nada!
	*/
	defaultOnOkResponseStatus : function(response) {
		new Effect.Fade($(this.options.savingDiv), {duration : 0.1});
	},
	
	/**
		O tratamento por defecto do estado de resposta ERROR é mostrar a lista de erros
		no errorDiv
	*/
	defaultOnErrorResponseStatus : function(response) {
		$(this.options.savingDiv).hide();
		strErrors = '';
		response.globalErrors.each(
			function(error, index) {
				strErrors += '<li>' + error.defaultMessage + ' </li>';
			}
		)
		
		response.fieldErrors.each(
			function(error, index) {
				strErrors += '<li>' + error.defaultMessage + ' </li>';
			}
		)
		
		if(strErrors != '') {
			strErrors = '<ul>' + strErrors + '</ul>';
			$(this.options.errorsContainerList).innerHTML = strErrors;
			$(this.options.errorsContainer).show();
		}
	}
});