/*
 * IMPORTANTE: este fichero necesita mensajes internacionalizados, para lo cual
 * se deben agregar desde el controller o widget que lo utilice, llamando
 * a addIJMessage
 *
 * Input parameter: tipoPalabraClave must be defined in the client like this:
 * <script>
 * 	var tipoPalabraClave = ...
 * </script>
 * <script src=...func_validacion_palabraFast_18n...></script>
 */

if (tipoPalabraClave == "") {
	tipoPalabraClave = "Oferta";
}

// JScript source code
function Termino() {
	this.texto	 		= "";
	this.prefijo		= "";
	this.tipo  			= "";
	this.padre			= null;
	this.hijos			= [];

	this.PCB_SIN_TERMINO		= 0;
	this.PCB_TERMINO_PREFIJO	= 1;
	this.PCB_TERMINO_COMPUESTO	= 2;
	this.PCB_TERMINO_EXACTO		= 3;
	this.PCB_TERMINO			= 4;

	this.TIPO_LITERAL	= "LT";
	this.TIPO_EXACTO	= "EX";
	this.TIPO_AND		= "AND";
	this.TIPO_OR		= "OR";

	if (tipoPalabraClave == "Oferta"){
		if (getIJMessage("prefijos_validos") == "prefijos_validos_ES"){
			this.PREFIJOS_VALIDOS		= /^\-?(descripci[oóÓ]n|empresa|poblaci[oóÓ]n|puesto|requisitos)$/i;
		} else if (getIJMessage("prefijos_validos") == "prefijos_validos_IT"){
			this.PREFIJOS_VALIDOS		= /^\-?(descrizione|azienda|citt[aàÀA]|posto|requisiti)$/i;
		}
		this.TEXTO_ERROR_PREFIJOS	= getIJMessage("los_unicos_prefijos_validos_para_la_palabra_clave_son_1");
		
	} else {
		if (getIJMessage("prefijos_validos") == "prefijos_validos_ES"){
			this.PREFIJOS_VALIDOS		= /^\-?(puesto|empresa|empresa_?actual|descripci[oóÓ]n|futuro_?empleo|poblaci[oóÓ]n|centro|conocimientos|cv_?texto)$/i;
		} else if (getIJMessage("prefijos_validos") == "prefijos_validos_IT"){
			this.PREFIJOS_VALIDOS		= /^\-?(posto|azienda|azienda_?attuale|descrizione|futuro_?lavoro|citt[aàÀA]|centro|competenze|cv_?dettagliato)$/i;
		}
		this.TEXTO_ERROR_PREFIJOS	= getIJMessage("los_unicos_prefijos_validos_para_la_palabra_clave_son_2");
	}

	Termino.prototype.setTexto = function(texto) {
		/* Substituye secuencias de *? y espacios iniciales/finales */
		this.texto = texto.replace(/(\*[?*]+|[?*]+\*)/g,"*");
		this.texto = this.texto.replace(/\*\*+/g,"*");
		this.texto = this.texto.replace(/(^\s+$|^\s+|\s+$)/g,"");
		this.texto = this.texto.replace(/\s+/g," ");
	}

	Termino.prototype.getTexto		= function () {
		return this.texto;
	}

	Termino.prototype.setPadre		= function (padre) {
		this.padre = padre;
	}

	Termino.prototype.getPadre		= function () {
		return this.padre;
	}

	Termino.prototype.setPrefijo	= function (prefijo) {
		this.prefijo = prefijo;
	}

	Termino.prototype.getPrefijo	= function () {
		return this.prefijo;
	}

	Termino.prototype.setTipo		= function (tipo) {
		this.tipo	= tipo;
	}

	Termino.prototype.getTipo		= function () {
		return this.tipo;
	}

	Termino.prototype.addHijo		= function (hijo) {
		this.hijos[this.hijos.length] = hijo;
		hijo.setPadre(this);
	}

}

/* Esta función lee un fragmento de la expresión 'busqueda' (entre inicio y fin) y crea un término a partir de su contenido */
/* Es recursiva si encuentra una subexpresión */
function leerBusqueda (key, objPalabra, busqueda, inicio, fin, padre, generarMensajesError) {

/* Estas variables mantienen el estado del resúltado de la lectura a medida que se va analizando la expresión			*/
	var terminoActual	= padre.PCB_SIN_TERMINO;	/* Indica el tipo de término detectado actualmente					*/
	var nvlTermComp		= 0;						/* Controla el nivel de anidamiento en subexpresiones anidadas		*/
	var inicioTerm		= -1;						/* Define el punto de inicio del término actual 						*/
	var inicioReal		= -1;						/* Permite no considerar los espacios en blanco iniciales o finales	*/
	var	prefijo			= '';						/* Guarda el prefijo detectado en el término actual					*/

	for (posicion = inicio; (posicion <= fin); posicion++) {
		var caracter = busqueda.charAt(posicion);

/* Puede estar detectando un término compuesto, delimitado por paréntesis */
		if (terminoActual == padre.PCB_TERMINO_COMPUESTO) {
			if (caracter == ')') {
				/* Ha encontrado el final de un término compuesto */
				if (nvlTermComp > 1) {
				/* Si había varios niveles de anidamiento sólo decrementa el nivel */
					nvlTermComp--;
				} else if (inicioReal == -1) {
				/* Si no se había detectado un inicioReal es que está vacio (ó solo contiene espacios en blanco) */
					if (generarMensajesError) {
						addErrorMessageWithKey(key, objPalabra, getIJMessage('no_puede_haber_terminos_opcionales_vacios'));
					}
					return false;
				} else {
				/* Crea un nuevo término compuesto: AND/OR */
					var tipo = padre.TIPO_OR;
					if (padre.getTipo() == padre.TIPO_OR) {
						tipo= padre.TIPO_AND;
					}
					if ((padre.getTipo() == padre.TIPO_AND) || (prefijo.length == 0) || (prefijo.charAt(0) != ' ')) {
						var hijo = buildTermino(tipo, inicioReal, posicion - 1, prefijo, busqueda, padre);
						if (! leerBusqueda(key, objPalabra, busqueda, inicioReal, posicion - 1, hijo, generarMensajesError)) { return false; }
					}
					prefijo			= '';
					terminoActual	= padre.PCB_SIN_TERMINO;
					inicioTerm		= -1;
					inicioReal		= -1;
					nvlTermComp 	=  0;
				}
			} else if (caracter != ' ') {
				if (inicioReal == -1 ) { inicioReal = posicion;	}
				if (caracter   == '(') { nvlTermComp++;			}
			}

/* Puede estar detectando un término exacto, delimitado por comillas */
		} else if (terminoActual == padre.PCB_TERMINO_EXACTO) {
			if (caracter == '"') {
			/* Ha encontrado el final */
				if (inicioReal == -1) {
					if (generarMensajesError) {
						addErrorMessageWithKey(key, objPalabra, getIJMessage('no_puede_haber_terminos_exactos_vacios'));
					}
					return false;
				} else {
					var tipo = padre.TIPO_EXACTO;
					buildTermino(tipo, inicioReal, posicion - 1, prefijo, busqueda, padre);
					prefijo			= '';
					terminoActual	= padre.PCB_SIN_TERMINO;
					inicioTerm		= -1;
					inicioReal		= -1;
				}
			} else if (caracter != ' ') {
				if  (inicioReal == -1) { inicioReal = posicion; }
			}
		
	/* En cualquier otro caso */
		} else {
			/* Inicio de término compuesto ó exacto */
			if	((caracter == '(') || (caracter == '"')) {
				if (terminoActual == padre.PCB_TERMINO) {
					if ((inicioTerm == (posicion - 1)) && (busqueda.slice(inicioTerm, posicion) == '-')) {
						prefijo			= '-';
						terminoActual	= padre.PCB_SIN_TERMINO;
						inicioTerm 		=  -1;
					} else {
						if (generarMensajesError) {
							addErrorMessageWithKey(key, objPalabra, getIJMessage("sintaxis_erronea_en_la_posicion") + ' <' + busqueda.slice(posicion) + '>');
						}
						return false;
					}
				} 
				if (terminoActual != padre.PCB_TERMINO) {
					if (caracter == '(') {
						terminoActual	= padre.PCB_TERMINO_COMPUESTO;
						nvlTermComp++;
					} else {
						terminoActual	= padre.PCB_TERMINO_EXACTO;
					}
					inicioTerm		= posicion;
				}

			} else if (caracter == ':')		{ // fin de un prefijo
			/* Delimitador de prefijo */
				/* Debe estar capturando un termino */
				if ((terminoActual == padre.PCB_SIN_TERMINO) || (terminoActual == padre.PCB_TERMINO_PREFIJO)) {
					if (generarMensajesError) {
						addErrorMessageWithKey(key,objPalabra, getIJMessage("separador_de_prefijo_inesperado_en_la_posicion") + ' <' + busqueda.slice(posicion) + '>');
					}
					return false;
				} else {
					prefijo	= busqueda.slice(inicioTerm, posicion);
					if (! validar_prefijo(prefijo, padre.PREFIJOS_VALIDOS)) {
						if (generarMensajesError) {
							addErrorMessageWithKey(key, objPalabra, padre.TEXTO_ERROR_PREFIJOS);
						}
						return false;
					}
					terminoActual	= padre.PCB_TERMINO_PREFIJO;
					inicioTerm		= -1;
				}
			} else if (caracter == ' ')	{ // caracter blanco
				/* Es preciso que esté capturando un término ó un prefijo */
				if 	(terminoActual == padre.PCB_TERMINO) {
					if (busqueda.charAt(inicioTerm) == '-') {
						prefijo		= "-";
						inicioTerm	= inicioTerm + 1;
					}
					buildTermino(padre.TIPO_LITERAL, inicioTerm, posicion - 1, prefijo, busqueda, padre);
					prefijo			= '';
					terminoActual	= padre.PCB_SIN_TERMINO;
					inicioTerm		= -1;

				} else if (terminoActual == padre.PCB_TERMINO_PREFIJO) {
					if (prefijo.charAt(0) == '-') {
						prefijo = prefijo.slice(1);
					}
					padre.setPrefijo(prefijo);
					prefijo			= '';
					terminoActual	= padre.PCB_SIN_TERMINO;
				}
			} else {
				if (terminoActual != padre.PCB_TERMINO) {
					terminoActual	= padre.PCB_TERMINO;
					inicioTerm		= posicion;
				}
			}
		}
	}

	/* Si finaliza comprueba si tenía un término actual en curso de análisis */
	if 	(terminoActual == padre.PCB_TERMINO)	{
		if (busqueda.charAt(inicioTerm) == '-') {
			prefijo		= "-";
			inicioTerm	= inicioTerm + 1;
		}
		buildTermino(padre.TIPO_LITERAL, inicioTerm, fin, prefijo, busqueda, padre);

	} else if (terminoActual == padre.PCB_TERMINO_COMPUESTO)	{
		if (generarMensajesError) {
			addErrorMessageWithKey(key,objPalabra, getIJMessage("sintaxis_incorrecta_expresion_opcional_inacabada") + ' <' + busqueda.slice(inicioTerm) + '>');
		}
		return false;

	} else if (terminoActual == padre.PCB_TERMINO_EXACTO)	{
		if (generarMensajesError) {
			addErrorMessageWithKey(key,objPalabra, getIJMessage("sintaxis_incorrecta_expresion_exacta_inacabada") + ' <' + busqueda.slice(inicioTerm) + '>');
		}
		return false;

	}

	return true;
}

/* Esta función construye un nuevo término a partir de la subexpresión indicada */
function buildTermino (tipo, inicio, fin, prefijo, busqueda, padre) {

	if (prefijo == '') { prefijo = padre.getPrefijo(); }
	
	var termino = new Termino();

	termino.setTipo(tipo);
	termino.setPrefijo(prefijo);

	if 	((tipo == termino.TIPO_EXACTO) || (tipo == termino.TIPO_LITERAL)) {
		var texto = busqueda.slice(inicio, fin+1);
		termino.setTexto(texto);
	}

	padre.addHijo(termino);

	return termino;
}


/* Esta función valida que el prefijo sea uno de los permitidos según el tipo de expresión: Oferta ó CVs */
function validar_prefijo(prefijo, prefijosValidos) {

	var regexPrefijosValidos = new RegExp(prefijosValidos);
	return (prefijo.match(regexPrefijosValidos) != null);

}

function validar_palabra(objPalabra) {
	return validar_palabra_with_key("",objPalabra);
}

/* Esta función es la responsable de la validación de la expresión de búsqueda */
function validar_palabra_with_key(key, objPalabra) {

	var palabra			= objPalabra.value.replace(/(^\s+$|^\s+|\s+$)/g,"");
	objPalabra.value	= palabra;

	// Si solo contiene espacios en blanco la expresión es correcta
	if (palabra == '')
		return true;

	var generarMensajesError = true;	/* Por defecto generamos mensajes de error. */
	if (arguments.length > 1) {			/* Determina si hay que generar mensajes de error mediante addErrorMessage o no. */
		generarMensajesError = arguments[1];
	}
	
	var errorNoAlertado = null;
	if(arguments.length == 3){
		errorNoAlertado = arguments[2];
		errorNoAlertado[0] = true;
	}

	var REGEX_CARACTERES_NO_VALIDOS	= /([^-_a-zA-Z0-9áàâãäåÀÁÂÃÄÅèéêëÈÉÊËìíîïÌÍÎÏòóôõöÒÓÔÕÖùúûüÙÚÛÜñÑçÇ*?.+#:()"/]+|)/g;

	palabra = palabra.replace(REGEX_CARACTERES_NO_VALIDOS," ");

	// Si solo contiene caracteres no validos la expresión es incorrecta
	if (palabra.replace(" ","") == '') {
		if (generarMensajesError) {
			addErrorMessageWithKey(key, objPalabra, getIJMessage("la_expresion_es_incorrecta"));
			if( errorNoAlertado != null){
				errorNoAlertado[0] = false;
			}
		}
		return false;
	}

/* Crea la raiz del árbol de análisis de la expresión */
	var termino = new Termino();
	termino.setTipo(termino.TIPO_AND);

/* leerBusqueda es la función que realiza el análisis, generando el árbol de análisis a partir del término raiz recibido */
	var resultado = leerBusqueda(key, objPalabra, palabra, 0, palabra.length - 1, termino, generarMensajesError);
	if (resultado) {
		resultado = (termino.hijos.length > 0);
	}

	return resultado;
}

