/**
 *  Copyright (c) 2006 Elvis Navarro Vega ( http://www.unipamplona.edu.co )
 *	@autor: Ing Elvis Navarro Vega
 *  @email: elvisnv@unipamplona.edu.co 
 *	Grupo de Desarrollo Plataforma - Universidad de Pamplona.
 *  Grupo de Trabajo Hermesoft 
 *  Plataforma - Vicerrectoria de Gestion y Desarrollo Tecnologico
 *	Pamplona, Norte de Santander. Colombia.
 *	Octubre del 2006
 *	@descripcion :	framework sobre js para la validacion de los campos de un formulario, 
 *					este framework requiere de la inclusion de hmsgeneral.
 *
 */

hms = window.hms || {} ;

/**
 * Configuración de los mensajes estandar de los errores
 * Para los mensajes particulares se debe crear un js que incluya los mensajes particulares.
 * y estos js se han de incluir en las paginas donde se necesite.
 * Se debe agregar esta linea hms.configmessage = window.hms.configmessage || {} ; y cada mensaje 
 * particular se declarara de la siguiente manera.
 * hms.configmessage.[name del mensaje]	= [Cadena de texto que representa el mensaje] ;
 */

hms.configmessage = window.hms.configmessage || {} ;
hms.configmessage.required	= 'El valor para el campo { /**field**/ } es obligatorio' ;
hms.configmessage.integer	= 'El valor para el campo { /**field**/ } no es un número entero válido' ;
hms.configmessage.flotante	= 'El valor para el campo { /**field**/ } no es un número con punto flotante válido' ;
hms.configmessage.minlength	= 'El campo { /**field**/ } debe tener por lo menos { /**count**/ } caracteres' ;
hms.configmessage.maxlength	= 'La cantidad de caracteres asignado al campo { /**field**/ } supera el máximo permitido { /**count**/ }' ;
hms.configmessage.shared	= 'Debe indicar por lo menos uno de los siguientes campos { /**fields**/ }' ;
hms.configmessage.list		= 'Debe agregar por lo menos un registro a la lista' ;
hms.configmessage.email		= 'El campo { /**field**/ } no contiene un dato de e-mail válido' ;
hms.configmessage.time		= 'El campo { /**field**/ } no contiene un dato de hora válido, debe pertenecer a este rango [ 00:00:00 - 23:59:59 ]' ;
hms.configmessage.date		= 'El campo { /**field**/ } no contiene un dato de fecha válido' ;
hms.configmessage.datetime	= 'El campo { /**field**/ } no contiene un dato de fecha y hora válido' ;
hms.configmessage.string	= 'El campo { /**field**/ } debe ser alfanumérico, solo permite letras, números y subrayado' ;
hms.configmessage.range		= 'El atributo especificado para el campo { /**field**/ } no se encuentra entre los valores esperados { /**min**/ } y { /**max**/ }' ;
hms.configmessage.option	= 'Debe seleccionar un registro de la lista' ;
hms.configmessage.checkbox	= 'Debe seleccionar por lo menos un registro de la lista' ;

/**
 * Maneja las funciones de validacion de los campos de un formulario.
 * En esta version falta la implementación de la validacion de los check
 * de los options e incrementar la de comparacion a varios parametros
 */
hmsvalidator = hms.validator = new Object () ;
hms.validator.form 	 = null ;
hms.validator.message = null ;

/**
 * inicia el proceso de validacion y devuelve el posible mensaje que se haya capturado
 * @param form, contiene el nombre del formulario que se ha de analizar
 * @return message, cadena de mensaje de error formada, null en caso de que no hayan errores
 */
hms.validator.init = function ( form ) {
	this.message 	= null ;	
	this.form 		= ( typeof form == 'string' ? $( form ) : form ) ;
	var elements	= hms.form.getElements ( form ) ; 
	if ( !this.validateOnlyForm () )
		this.elements ( elements ) ;
	this.validateForm () ;
	return ( this.message ) ;
} ;

/**
 * Recorre cada uno de los elementos del formulario y chequea si debe ser analizado.
 * @param element, contiene la lista de elementos de un formulario
 */
hms.validator.elements = function ( elements ) {
	for ( var i = 0; i < elements.length; i ++ ) {
		var hmsvalidate = elements [ i ].getAttribute ( 'hmsvalidate' ) ;
		if ( hmsvalidate != null ) {
			hmsvalidate = this.object ( hmsvalidate ) ;
			this.properties ( elements [ i ], hmsvalidate ) ;
		}
	}
} ;

/**
 * Analiza cada una de las propiedades de los elementos del formulario
 * ejecuta la validacion de cada una de ellas e instancia los posibles errores
 * que se puedan presentar.
 * @param object, contiene el elemento del formulario que se desee analizar.
 * @param properties, contiene las propiedades del elemento que se han de validar
 */
hms.validator.properties = function ( object, properties ) {
	for ( var i = 0; i < properties.length; i ++ ) {
		var propertie = properties [ i ] ;
		switch ( propertie.hmstype ) {
			case 'required' :
				if ( hms.field.empty ( object.id ) ) 
					this.setInstanceMessage ( object.id, propertie ) ;
				break ;
				
			case 'shared' :
				var shared = propertie.hmsshared ;
				shared [ shared.length ] = object.id ;
				this.processShared ( shared, propertie ) ;
				break ;
				
			case 'integer' :
			case 'flotante' :
				if ( ! hms.field.empty ( object.id ) ) {
					var str	= " if ( ! hms.field." + propertie.hmstype + " ( object.id ) ) " +
							  "		this.setInstanceMessage ( object.id, propertie ) ;" + 	
							  " else { " +
							  "		this.compare ( object.id, propertie ) ;" + 
							  "		this.processRange ( object.id, propertie ) ;" + 
							  "	} " ;
					eval ( str ) ;				  
				}
				break ;
				
			case 'minlength' :
			case 'maxlength' :
				var count = Number ( propertie.hmscount ) ;
				if ( ! hms.field.empty ( object.id ) ) {
					var operator = propertie.hmstype == 'minlength' ? '<' : '>' ;
					var str	= " if ( hms.field.length ( object.id ) " + operator + " count ) { " +
							  "		propertie.hmsconfigmessage != null ? this.setMessage ( propertie.hmsconfigmessage ) :" +  
							  "			propertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: propertie.hmsmessage } ) :" +
					 		  "				this.setMessage ( '" + propertie.hmstype + "', { hmsid: object.id, hmscount: count } ) ;" +
							  " } " ;
					eval ( str ) ;		  
				}
				break ;
			case 'depends' :
				var depends = propertie.hmsdepends ;
				if ( hms.field.empty ( object.id ) ) 
					this.processDepends ( object.id, depends, propertie ) ;
				break ;

			case 'list' :
				if ( hms.field.empty ( object.id ) ) 
					propertie.hmsconfigmessage != null ? this.setMessage ( propertie.hmsconfigmessage ) :
							propertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: propertie.hmsmessage } ) :
									this.setMessage ( 'list' ) ;						
				break ;
				
			case 'email' :
				if ( ! hms.field.empty ( object.id ) ) 
					if ( ! hms.field.email ( object.id ) ) 
						this.setInstanceMessage ( object.id, propertie ) ;
				break ;
			
			case 'time' :
				if ( ! hms.field.empty ( object.id ) ) {
					if ( ! hms.field.time ( $( object.id ).value ) ) 	
						this.setInstanceMessage ( object.id, propertie ) ;
					else
						this.compare ( object.id, propertie ) ;
				}
				break ;

			case 'date' :
				if ( ! hms.field.empty ( object.id ) ) {
					if ( ! hms.field.date ( $( object.id ).value ) )	
						this.setInstanceMessage ( object.id, propertie ) ;
					else {
						if ( ! this.processDate ( $( object.id ).value ) ) 
							this.setInstanceMessage ( object.id, propertie ) ;
						else
							this.compare ( object.id, propertie ) ;
					} 
						
				}
				break ;

			case 'datetime' :
				if ( ! hms.field.empty ( object.id ) ) {
					if ( ! hms.field.datetime ( $( object.id ).value ) )	
						this.setInstanceMessage ( object.id, propertie ) ;
					else {
						var adate = $( object.id ).value.split ( ' ' ) ;
						if ( ! this.processDate ( adate [ 0 ] ) ) {
							propertie.hmstype = 'date' ;
							this.setInstanceMessage ( object.id, propertie ) ;
						} else 
							this.compare ( object.id, propertie ) ;
					}
				}
				break ;
				
			case 'string' :
				if ( ! hms.field.empty ( object.id ) ) {
					if ( ! hms.field.string ( $( object.id ).value ) )	
						this.setInstanceMessage ( object.id, propertie ) ;
					else 
						this.compare ( object.id, propertie ) ;
				}
				break ;
		}
	}
} ;

/**
 * Verifica que tipo de mensaje se debe instanciar 
 * @param oId, contiene el id del elemento que se esta analizando
 * @param propertie, contiene las propiedades del elemento para la manipulacion de los mensajes
 */
hms.validator.setInstanceMessage = function ( oId, propertie ) {
	propertie.hmsconfigmessage != null ? this.setMessage ( propertie.hmsconfigmessage ) :
		propertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: propertie.hmsmessage } ) :
			this.setMessage ( propertie.hmstype, { hmsid: oId } ) ;
} ;

/** 
 * Instancia un mensaje a la cadena de mensaje general
 * @param type, contiene el tipo de mensaje que se desea buscar en la lista de mensajes estandares
 * @param attributes, contiene los diferentes valores que se le pueden asignar a la cadena del mensaje
 */
hms.validator.setMessage = function ( type, attributes ) {
	var message = null ;
	if ( type != null )
		eval ( 'message = hms.configmessage.' + type ) ;
	
	if ( attributes ) {
		if ( attributes.hmsmessage )		message = attributes.hmsmessage ;
		if ( attributes.hmsshared )			message = message.replace ( '/**fields**/', attributes.hmsshared ) ;	
		if ( attributes.hmscount )			message = message.replace ( '/**count**/', attributes.hmscount ) ;	
		if ( attributes.hmsid )				message = message.replace ( '/**field**/', $( 'ol_' + attributes.hmsid ).innerHTML ) ;
		if ( attributes.hmsmin != null )	message = message.replace ( '/**min**/', attributes.hmsmin ) ;	
		if ( attributes.hmsmax != null )	message = message.replace ( '/**max**/', attributes.hmsmax ) ;	
	} 
	
	this.message = this.message == null ? message : this.message + '\n' + message ;
} ;

/**
 * convierte una cadeba que representa a un objeto en el objeto como tal
 * @param strObject, contiene la cadena a convertir en objeto
 * @return object, contiene el objeto como tal
 */
hms.validator.object = function ( strObject ) {
	return eval ( strObject ) ;
} ;

/**
 * Procesa la validacion de objetos compartidos.
 * @param aShared, contiene el listado de id que son compartidos para validar
 * @aProperties, contiene las propiedades del objeto.
 */
hms.validator.processShared = function ( aShared, aPropertie ) {
	var isEmpty = true ;
	var  strId  = '' ;
	for ( var i = 0; i < aShared.length; i ++ ) {
		strId += $( 'ol_' + aShared [ i ] ).innerHTML + ( i < aShared.length - 1 ? ', ' : '' ) ;  
		if ( ! hms.field.empty ( aShared [ i ] ) )
			isEmpty = false ;
	}

	if ( isEmpty ) 
		aPropertie.hmsconfigmessage != null ? this.setMessage ( aPropertie.hmsconfigmessage ) :
				aPropertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: aPropertie.hmsmessage } ) :
						this.setMessage ( 'shared', { hmsshared: strId } ) ;						
} ;

/**
 * Procesa la validacion de objetos cuando hay dependencia entre ellos.
 * @param oId, contiene id del elemento que se esta analizando
 * @param aDepends, contiene el listado objeto de la cual depende el objeto actual
 * @aProperties, contiene las propiedades del objeto.
 */
hms.validator.processDepends = function ( oId, aDepends, aPropertie ) {
	var element = $( oId ) ;
	var isEmpty = false ;
	
	for ( var i = 0; i < aDepends.length; i ++ ) {
		var oDepends = aDepends [ i ] ;
		switch ( oDepends.type ) {
			case 'text' :
				if ( ! hms.field.empty ( oDepends.field ) ) 
					isEmpty = true ;
				break ;
				
			case 'checkbox' :
				var chk = $( oDepends.field ) ;
				if ( chk.checked )
					isEmpty = true ;
				break ;
		}
	}

	if ( isEmpty ) {
		aPropertie.hmstype = 'required' ;
		this.setInstanceMessage ( oId, aPropertie ) ;
	}
} ;

/**
 * Ejecuta la validacion de comparacion, verifica si el objeto con el que se desea comparar es diferente de vacio
 * @param oId, contiene id del elemento que se esta analizando
 * @aProperties, contiene las propiedades del objeto.
 */
hms.validator.compare = function ( oId, propertie ) {
	if ( propertie.hmscompare != null ) {
		var value = propertie.hmscompare [ 0 ] ? $(propertie.hmscompare [ 1 ]).value : propertie.hmscompare [ 1 ] ;
		if ( value.length > 0 ) 
			this.processCompare ( oId, propertie ) ;
	}
} ;

/**
 * Ejecuta la validacion de comparacion, verifica que tipo de comparacion se ha de ejecutar
 * @param oId, contiene id del elemento que se esta analizando
 * @aProperties, contiene las propiedades del objeto.
 */
hms.validator.processCompare = function ( oId, aPropertie ) {
	var hmscompare 	= aPropertie.hmscompare ;
	var isObject 	= hmscompare [ 0 ] ;
	var value  		= isObject ? $( hmscompare [ 1 ] ).value : hmscompare [ 1 ] ;
	var operation  	= hmscompare [ 2 ] ;
	var message		= hmscompare [ 3 ] ;
	
	switch ( aPropertie.hmstype ) {
		case 'integer' :
			if ( hms.field.integer ( Number ( value ) ) ) {
				if ( this.processOperatorNumber ( $( oId ).value, value, operation ) ) 
					message.configmessage != null ? this.setMessage ( message.configmessage ) :
						this.setMessage ( null, { hmsmessage: message.message } ) ;
			} else 
				this.setMessage ( 'integer', { hmsid: hmscompare [ 1 ] } ) ;
			break ;
			
		case 'flotante':
			if ( hms.field.flotante ( Number ( value ) ) ) {
				if ( this.processOperatorNumber ( $( oId ).value, value, operation ) ) 
					message.configmessage != null ? this.setMessage ( message.configmessage ) :
						this.setMessage ( null, { hmsmessage: message.message } ) ;
			} else 
				this.setMessage ( 'flotante', { hmsid: hmscompare [ 1 ] } ) ;
			break ;
			
		case 'string' :
			if ( this.processOperatorString ( $( oId ).value, value, operation ) ) 
				message.configmessage != null ? this.setMessage ( message.configmessage ) :
					this.setMessage ( null, { hmsmessage: message.message } ) ;
			break ;
			
		case 'time' :
			if ( hms.field.time ( value ) ) {
				var time_1 = this.convertTime ( $( oId ).value ) ;
				var time_2 = this.convertTime ( value ) ;
				if ( this.processOperatorNumber ( time_1, time_2, operation ) ) 
					message.configmessage != null ? this.setMessage ( message.configmessage ) :
						this.setMessage ( null, { hmsmessage: message.message } ) ;
			} else {
				this.setMessage ( 'time', { hmsid: hmscompare [ 1 ] } ) ;				
			}
			break ;
			
		case 'date' :
			if ( hms.field.date ( value ) ) {
				if ( this.processDate ( value ) ) {
					var date_1 = this.convertDate ( $( oId ).value ) ;
					var date_2 = this.convertDate ( value ) ;
					if ( this.processOperatorNumber ( date_1, date_2, operation ) ) 
						message.configmessage != null ? this.setMessage ( message.configmessage ) :
							this.setMessage ( null, { hmsmessage: message.message } ) ;
				} else {
					this.setMessage ( 'date', { hmsid: hmscompare [ 1 ] } ) ;				
				}
			} else {
				this.setMessage ( 'date', { hmsid: hmscompare [ 1 ] } ) ;				
			}
			break ;
		
		case 'datetime' :
			var adate = $( oId ).value.split ( ' ' ) ;
			if ( hms.field.datetime ( value ) ) {
				var _adate = value.split ( ' ' ) ;
				if ( this.processDate ( _adate [ 0 ] ) ) {
					var datetime_1 = this.convertDate ( adate [ 0 ] ) + '' + this.convertTime ( adate [ 1 ] ) ;
					var datetime_2 = this.convertDate ( _adate [ 0 ] ) + '' + this.convertTime ( _adate [ 1 ] ) ;
					if ( this.processOperatorNumber ( datetime_1, datetime_2, operation ) ) 
						message.configmessage != null ? this.setMessage ( message.configmessage ) :
							this.setMessage ( null, { hmsmessage: message.message } ) ;
				} else {
					this.setMessage ( 'date', { hmsid: hmscompare [ 1 ] } ) ;		
				}
			} else {
				this.setMessage ( 'datetime', { hmsid: hmscompare [ 1 ] } ) ;		
			}
			break ;
	}
} ;

/**
 * Ejecuta una comparacion de tipo numerico a traves de una operacion
 * @param v1, contiene el primer valor a comparar
 * @param v2, contiene el segundo valor a comparar
 * @operation, contiene la operacion que se debe ejecutar para la comparacion.
 * @return true, si la ejecucion de la operacion es verdadera, false en caso contrario
 */
hms.validator.processOperatorNumber = function ( v1, v2, operation ) {
	return eval ( 'Number (v1) ' + operation + ' Number (v2)' ) ;
} ;

/**
 * Ejecuta una comparacion entre cadenas a traves de una operacion
 * @param v1, contiene el primer valor a comparar
 * @param v2, contiene el segundo valor a comparar
 * @operation, contiene la operacion que se debe ejecutar para la comparacion.
 * @return true, si la ejecucion de la operacion es verdadera, false en caso contrario
 */
hms.validator.processOperatorString = function ( v1, v2, operation ) {
	return eval ( 'v1 ' + operation + ' v2' ) ;
} ;

/**
 * Convierte una cadena de tipo fecha a la fecha que representa y verifica si esa fecha es valida
 * @param strDate, contiene la representacion textual de una fecha
 * @return true si la fecha obtenida es una fecha valida, false en caso contrario
 */
hms.validator.processDate = function ( strDate ) {
	var afecha	= strDate.split ( '-' ) ;
	var fecha 	= new Date ( afecha [ 2 ], afecha [ 1 ] - 1, afecha [ 0 ] );
	if ( fecha.getMonth () != Number ( afecha [ 1 ] - 1 ) )
		return false ;
	return true ;
} ;

/**
 * Convierte una cadena de tipo hora al valor numerico que representa
 * @param strTime, contiene la representacion textual de una hora
 * @return el numero representativo de la hora, por ej.: 20:15:10 devuelve 201510
 */
hms.validator.convertTime = function ( strTime ) {
	var cmpTime = strTime.split ( ':' ) ;
	return Number ( cmpTime [ 0 ] + '' + cmpTime [ 1 ] + '' + cmpTime [ 2 ] ) ;
} ;

/**
 * Convierte una cadena de tipo fecha al valor numerico que representa, tomando el orden año, mes y dia
 * @param strDate, contiene la representacion textual de una fecha
 * @return el numero representativo de la fecha, por ej.: 10-02-2006 devuelve 20060210
 */
hms.validator.convertDate = function ( strDate ) {
	var cmpTime = strDate.split ( '-' ) ;
	return Number ( cmpTime [ 2 ] + '' + cmpTime [ 1 ] + '' + cmpTime [ 0 ] ) ;
} ;

/**
 * Ejecuta la validacion de rango permitido para un numero.
 * @param oId, contiene id del elemento que se esta analizando
 * @propertie, contiene las propiedades del objeto.
 */
hms.validator.processRange = function ( oId, propertie ) {
	if ( propertie.hmsrange != null ) {
		if ( this.processOperatorNumber ( $(oId).value, propertie.hmsrange[0], '<' ) ||
				this.processOperatorNumber ( $(oId).value, propertie.hmsrange[1], '>' ))
			propertie.hmsconfigmessage != null ? this.setMessage ( propertie.hmsconfigmessage ) :
				propertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: propertie.hmsmessage } ) :
					this.setMessage ( 'range', { hmsid: oId, hmsmin: propertie.hmsrange[0], hmsmax: propertie.hmsrange[1] } ) ;						
	}
} ;

/**
 * Ejecuta las validaciones relacionadas directamente con el formulario
 * @param form, contiene el nombre del formulario que se desea validar
 */

hms.validator.validateOnlyForm = function () {
	var hmsvalidate = this.form.getAttribute ( 'hmsvalidate' ) ;
	if ( hmsvalidate != null ) {
		hmsvalidate = this.object ( hmsvalidate ) ;		
		
		for ( var i = 0; i < hmsvalidate.length; i ++ ) {
			var propertie = hmsvalidate [ i ] ;
			
			switch ( propertie.hmstype ) {		
				case 'onlyform' :
					return ( true ) ;	
					break ;
			}
		}
	}
	return ( false ) ;
} ;
 
hms.validator.validateForm = function () {
	var hmsvalidate = this.form.getAttribute ( 'hmsvalidate' ) ;
	if ( hmsvalidate != null ) {
		hmsvalidate = this.object ( hmsvalidate ) ;		
		this.propertiesForm ( hmsvalidate ) ;
	}

} ;


hms.validator.propertiesForm = function ( properties ) {
	for ( var i = 0; i < properties.length; i ++ ) {
		var propertie = properties [ i ] ;
		switch ( propertie.hmstype ) {		
			case 'option' :
				this.processOption ( propertie ) ;	
				break ;
			
			case 'checkbox' :
				this.processCheckbox ( propertie ) ;	
				break ;
		}
	}
} ;

hms.validator.processOption = function ( propertie ) {
	for ( var i = 0; i < this.form.elements.length; i ++ ) {
		var el = this.form.elements [ i ];
		if ( el.type == 'radio' && el.name == propertie.hsmname ){
			if ( el.checked )
				return ;
		}		
	}
	
	propertie.hmsconfigmessage != null ? this.setMessage ( propertie.hmsconfigmessage ) :
		propertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: propertie.hmsmessage } ) :
			this.setMessage ( 'option' ) ;						
	
} ;

hms.validator.processCheckbox = function ( propertie ) {
	for ( var i = 0; i < this.form.elements.length; i ++ ) {
		var el = this.form.elements [ i ];
		if ( el.type == 'checkbox' && el.name == propertie.hsmname ){
			if ( el.checked )
				return ;
		}		
	}
	
	propertie.hmsconfigmessage != null ? this.setMessage ( propertie.hmsconfigmessage ) :
		propertie.hmsmessage != null ? this.setMessage ( null, { hmsmessage: propertie.hmsmessage } ) :
			this.setMessage ( 'checkbox' ) ;						
	
} ;


