/* 
©2003 IntelyGenZ  - www.intelygenz.com - info@intelygenz.com
i_exml.js v1.14beta6 [libs v1.14]
Basado en ev_exml.js v0.20

http://aspirina/ig_intelygenz/ig05_intranet/desarrollo/areas/dev/docs/i_exml.html

v1.10 [Fix] OrdenarArray()	[Fix] GetTagEXML()	[Fix] ParseEXMLs()	[Fix] <ifBD>
v1.11 [New] JoinMArray()	[New] GetOuterTag	[Fix] OrdenarArray()[Fix] ParseEXML()
v1.12 [New] <IF>...[<ELSE />...]</IF>			[Fix] CambiaTexto()	[New] MAcountMatches()	[Fix] ParseEXMLs	[Mod] FechaHoraEXML	[Fix] RegsMultiarray	[Fix][New] JoinMArray()	
v1.13 [New] F12 DebugMArray()	[Fix] nCoreVer	[Fix] OrdenarMultiarray() BuscarSubMArray() SubMArray()		[Fix]GetPropEXML	[Fix] BuscaMultiarrayBlock	[Fix]<SUMA>
v1.14 Compatible con IntelyWeb	[Upd] DebugMArray	[Upd] <IF>		[Fix] GetPropEXML()		[Upd] RegsMultiarray()

* Fix
GetPropEXML()	hay que mejorarla
	es muy dificil detectar las propiedades
	estos textos se confunden como final de propiedad: "' ..." / "'>..." 
Opcion para que en PRO no muestre los errores y los mande al IntelyWeb (ahora no los manda)
JoinMArray() : ¿vale para algo la version que es solo para MA iguales o la borramos?
Ordenar MArrays 
Ordenar por defecto sin importar acentos porque tarda mucho
BUG: deberiamos comprobar version de i_core.js
Poder buscar un valor aproximado en un MArray ¿estara hecho ya? (buscar el valor exacto si que lo hace)
GetTagEXML()
Pulir y ¿optimizar? : MAcountMatches()
[OBJ] oObj.m_sObj (cuidado con sDato con espacios, como el problema de SUMA)
Deprecate: <ifBD> y <ifFUN>
Deprecate y Remove CambiaTexto() del todo

* Docs
<IF bd='' fun=''>...[<ELSE />...]</IF> (comentarla y poner ejemplos)
	Ej: 1.	"<IF fun='<BD>nID</BD>==5'>Funciona</IF>"
		2.	"<IF fun='\"<BD>inactivo</BD>\"==\"Falso\"'>si<ELSE />no</IF>"
		3.	sFun = '"<BD>inactivo</BD>"=="Falso"'
			"<IF fun='"+sFun+"'>si<ELSE />no</IF>"
JoinMArray("Clientes","Clientes2","id")
JoinMArray("Clientes","Clientes2","id","id2",["email2","nombre2"])
MAcountMatches (sMArrayBase,a_sCampos,a_vValues,sLogic)
F12 : DebugMArray()

* Moverlas a i_core.js
AddCampo2Multiarray ("Clientes","nuevo","f+'.'+(<BD>nivel</BD>+17)")
ModMultiarray("Proyectos","codProyecto","<BD>PC.id</BD><BD>codigo</BD>") 


USO:
<SCRIPT language='JavaScript' src='../libs/js/i_core.js' id='Ncore'></SCRIPT>
<SCRIPT language="JavaScript" src="../libs/js/i_exml.js"></SCRIPT>

var sEXML = "Mi nombre es <BD>sNombre</BD>"
var nRegs = "NombreArrayDatos".f_getRegsNum()		
//var nRegs = maDatos.f_getRegsNum()		

for(var f=0; f<nRegs; f++){
	sHTML += ParseEXMLs (sEXML,"","NombreArrayDatos",f)
	var sEmail = GetMArray("NombreArrayDatos","Email",f)
}

*/

oIEXML=new function(){
	this.m_sObj="oIEXML";
	this.m_nVersion=1.14;
	this.m_sMArrayBase = "";
}

if(typeof(oIGZ)!="undefined") {
	oIGZ.f_loadLib("i_exml",oIEXML.m_nVersion);
	nCoreVer = .495
	if (oCore.m_nVersion<nCoreVer) ErrorJS ("[i_exml.js] Version de i_core.js menor de la requerida: "+nCoreVer,oIEXML,1)
	new oIGZ.f_keyEvent (["CTRL","F12"], function (){ alert(DebugMArray())} )
}
else {			//no es imprescindible
	var sPage = document.location.pathname
//	sPage = sPage.substr (1+sPage.lastIndexOf("/"))
	window.status = "["+ sPage + "] Falta la libreria o el ID de 'i_core.js' o no existe 'i_igz.js'"
}

g_oOnErrorEvent=window.onerror;
g_sJSarrayBase = "";

function ParseEXMLs (sEXML,oObj,sJSarrayBase,nRegistro) {		//5.3
var sErrror,f,s
//a_sTags = new Array("ifBD","SUMAEXML","SUMA","INPUT","SELECT","CHECKBOX","RADIO","RADIOS","BD","OBJ","FUN","ifFUN")	//Es muy importante el orden !!!
var a_sTags = new Array("DATO","ifBD","SUMAEXML","SUMA","CAMPO","BD","OBJ","FUN","ifFUN","IF")	//Es muy importante el orden !!!

	if (typeof(sEXML)=="undefined") {
		var nAlertMode = 1
		if (oObj) {
			sError = "ParseEXMLs() Le faltan datos al "+oObj.m_sObj+".f_createStyle"			
		}
		else {
			sError = "ParseEXMLs() No hay sEXML"
			nAlertMode = 3
		}
		ErrorJS ("[i_exml.js] "+sError,oObj,nAlertMode)
		return ("")
	}
	if (!sJSarrayBase) {
		if (oObj) sJSarrayBase=eval (oObj.m_sObj+".m_sJSarrayBase")
		else if (!g_sJSarrayBase) ErrorJS ("[i_exml.js] ParseEXMLs() No hay ningun MArray definido en sJSarrayBase",oObj,1)
		else sJSarrayBase = g_sJSarrayBase
	}
	g_sJSarrayBase = sJSarrayBase;

	for (f=0;f<a_sTags.length;f++){
		if (sEXML.indexOf(a_sTags[f])!=-1){
			if(this.m_sObj) sEXML = this.f_parseEXML(a_sTags[f],sEXML,oObj,sJSarrayBase,nRegistro);
			else sEXML = ParseEXML(a_sTags[f],sEXML,oObj,sJSarrayBase,nRegistro);
		}
	}
	return sEXML
}

//Bug: tags dentro de otros tags
//Este ParseEXML es una version especial para los MA de David (usa BuscaMultiarrayBlock)
function ParseEXML(sTag,sEXML,oObj,sJSarrayBase,nRegistro) {		//5.4
var nRegistros,nPos1,nPos1Fin,nPos2,sDato
var sTagInit = "<"+sTag+">", sTagFin = "</"+sTag+">";
var sTagIni = sTagInit;
var sFinal=""
var nTag1=sTagInit.length, nTag2=sTagFin.length

	if (!sJSarrayBase && oObj) sJSarrayBase=eval (oObj.m_sObj+".m_sJSarrayBase")
	if (sJSarrayBase){
		oIEXML.m_sMArrayBase = sJSarrayBase
		nRegistros = sJSarrayBase.f_getRegsNum()
		if (nRegistros<=nRegistro) {
			sError = "ParseEXML() no existe el registro "+ nRegistro + " en 'a_v"+sJSarrayBase+"' "
			if (nRegistros) sError += "[0-"+(nRegistros-1)+"]"		
			else sError += "(no hay ningun dato)"
			ErrorJS ("[i_exml.js] "+sError,oObj,3)
			return (sEXML)
		}
	}
	
	nPos1	= sEXML.indexOf(sTagInit)
	if (nPos1==-1){
		sTagInit = "<"+sTag
		nPos1	= sEXML.indexOf(sTagInit)
		if (nPos1!=-1){
			nPos1Fin = sEXML.indexOf(">",nPos1)
			sTagIni = sEXML.substring(nPos1,nPos1Fin+1)
//alert (nPos1+"_"+nPos1Fin+"_"+sTagIni)
			nTag1=sTagIni.length
		}
	}

	if (nPos1!=-1) nPos2 = sEXML.indexOf(sTagFin,nPos1+nTag1)

	
//	WhileLabel:
	while (nPos1!=-1 && nPos2!=-1){
		sFinal	= sFinal + sEXML.substr(0,nPos1) 

		sDato	= sEXML.substr(nPos1+nTag1,nPos2-nPos1-nTag1)
		switch (sTag){
		case "IF":
			window.onerror = function ErrorTrapJS(sError,sURL,nLinea) { sError="\n\n"+sURL+"\nLinea "+nLinea + " : " + sError;ErrorJS ("[i_exml.js] ParseEXML() <IF> no existe o da error:\n\t"+sDato+sError,oObj,1); return (true);}	
			var sBD = GetPropEXML(sTagIni,"bd",1)
			var sFUN = GetPropEXML(sTagIni,"fun",1)
			var a_sDatos = TagELSE(sDato)
			sDato = a_sDatos[0]
			if (sBD){
				bValidar= BuscaMultiarrayBlock (sBD,sJSarrayBase,nRegistro)	
				if (CheckFalse (bValidar)){
					sDato = a_sDatos[1]
				}
			}
			else if (sFUN){
				window.onerror = function ErrorTrapJS(sError,sURL,nLinea) { sError="\n\n"+sURL+"\nLinea "+nLinea + " : " + sError;ErrorJS ("[i_exml.js] ParseEXML() <IF fun> no existe o da error la funcion JS:\n\t"+sFUN+sError,oObj,1); return (true);}	
				bValidar = eval (sFUN)
	
				if (CheckFalse (bValidar)){
					sDato = a_sDatos[1]
				}
			}

//alert ("sDato: "+sDato + "\n sBD:"+sBD + "\n sFUN: "+sFUN)
			break
		case "ifFUN":
			window.onerror = function ErrorTrapJS(sError,sURL,nLinea) { sError="\n\n"+sURL+"\nLinea "+nLinea + " : " + sError;ErrorJS ("[i_exml.js] ParseEXML() <ifFUN> no existe o da error la funcion JS:\n\t"+sDato+sError,oObj,1); return (true);}	
			bValidar = eval (sDato)

			if (CheckFalse (bValidar)){
//				sEXML=""
				sDato = GetPropEXML(sTagIni,"false")
				if (sDato) sFinal +=sDato				
				else if (!GetPropEXML(sTagIni,"true")) sEXML=""
			}
			else{ 				//Verdadero
//				sFinal=""
				sDato = GetPropEXML(sTagIni,"true")
				if (sDato) sFinal +=sDato				
				else if (!GetPropEXML(sTagIni,"false")) sFinal=""
			}
			sDato=""

			break
		case "ifBD":
			bValidar= BuscaMultiarrayBlock (sDato,sJSarrayBase,nRegistro)

			if (CheckFalse (bValidar)){
				sDato = GetPropEXML(sTagIni,"false")
				if (sDato) sFinal +=sDato				
				else if (!GetPropEXML(sTagIni,"true")) sEXML=""
			}
			else{ 				//Verdadero
				sDato = GetPropEXML(sTagIni,"true")
				if (sDato) sFinal +=sDato				
				else if (!GetPropEXML(sTagIni,"false")) sFinal=""
			}
			sDato=""
			break
		case "CAMPO":
			var sProp = GetPropEXML(sTagIni,"tipo")
			var sExtras = GetPropEXML(sTagIni,"extras")
			
			switch (sProp){
			case "INPUT":
				var sCampo = sDato.substr(2)
				var sValue = BuscaMultiarrayBlock (sCampo,sJSarrayBase,nRegistro)
				var nSize = sValue.length
				sDato = '<INPUT name="'+ sDato +'" type="text" value="'+ sValue + '" ' + sExtras +'/>'
				break
			case "SELECT":
				var sTitulo = ""
				var sCampo = sDato.substr(2)
//eval (oObj.m_sObj+".m_nSUMA"+sCampo+"='12'")
				var sTexto = "<BD>"+sCampo+"</BD>"			
				var sValue = BuscaMultiarrayBlock (sCampo,sJSarrayBase,nRegistro)
				if (!sValue) sTitulo = " - Elige -"
				sDato = CreaComboEXML(sDato,sExtras,"",sJSarrayBase,sTexto,sTexto,sValue,sCampo,sCampo)
				break
			case "CHECKBOX":
				var sChecked = " "
				var sCampo = sDato.substr(2)
				var sValue = BuscaMultiarrayBlock (sCampo,sJSarrayBase,nRegistro)
				if (sValue && sValue!="0" && sValue!="False" && sValue!="Falso") {
					sChecked = " checked "
					sValue = ' value="'+ sValue + '"'
				}
				else {
					sValue =""
				}
				sDato = '<INPUT type="checkbox" name="'+ sDato +'"' + sValue + sChecked + ' ' + sExtras +'/>'
				break
			case "RADIO":
				var sChecked = " "
				var sCampo = sDato.substr(2)
				var sValue = BuscaMultiarrayBlock (sCampo,sJSarrayBase,nRegistro)
				if (sValue && sValue!="0" && sValue!="False" && sValue!="Falso") {
					sChecked = " checked "
					sValue = ' value="'+ sValue + '"'
				}
				else {
					sValue =""
				}
				sDato = '<INPUT type="radio" name="'+ sDato +'"' + sValue + sChecked + ' ' + sExtras +'/>'
				break
			case "RADIOS":
				var sChecked = " "
				var	sChecked2 = " checked "
				var sName = sDato
				var sCampo = sDato.substr(2)
				var sValue = BuscaMultiarrayBlock (sCampo,sJSarrayBase,nRegistro)
				if (sValue && sValue!="0" && sValue!="False" && sValue!="Falso") {
					sChecked = " checked "
					sChecked2 = " "
//					sValue = ' value="'+ sValue + '"'
				}
				else {
					sValue ="1"
				}
				sDato = 'Si<INPUT type="radio" name="'+ sName +'" value="' + sValue + '"' + sChecked + ' ' + sExtras +'/>'
				sDato += '&nbsp;No<INPUT type="radio" name="'+ sName +'" value="0"' + sChecked2 + ' ' + sExtras +'/>'
				break
			case "HIDDEN":
				var sCampo = sDato.substr(2)
				var sValue = BuscaMultiarrayBlock (sCampo,sJSarrayBase,nRegistro)
				var nSize = sValue.length
				sDato = '<INPUT name="'+ sDato +'" type="hidden" value="'+ sValue + '" ' + sExtras +'/>'
				break
			default:
				ErrorJS ("[i_exml.js] ParseEXML() Tag <CAMPO> de tipo invalido: "+sTagIni,oObj,1)
			}
			break
		case "BD":
			sDato = BuscaMultiarrayBlock (sDato,sJSarrayBase,nRegistro)
			break
		case "OBJ":
			if (sDato.indexOf("_")!=2) sDato = "m_" + sDato
			sDato = eval (oObj.m_sObj+"."+sDato)
			break
		case "DATO":		// nRegistro, nRegistros
			sDato = eval (sDato)
			break
		case "SUMA":
			if (oObj){
				var sDatoClean = sDato.replace(/[^a-z]/g,"")
				vDato = eval (oObj.m_sObj+".m_n"+sTag+sDatoClean)
				if (typeof(vDato)=="undefined") {
					vDato = OperarMultiEXML(sJSarrayBase,"0+<BD>"+sDato+"</BD>")
					eval (oObj.m_sObj+".m_n"+sTag+sDatoClean+"=vDato")
				}
			}
			else{
				vDato = OperarMultiEXML(sJSarrayBase,"0+<BD>"+sDato+"</BD>")
			}
			sDato = vDato
			break	
		case "SUMAEXML":
			sDato = OperarMultiEXML(sJSarrayBase,sDato)
			break	

		case "FUN":
			window.onerror = function ErrorTrapJS(sError,sURL,nLinea) { sError="\n\n"+sURL+"\nLinea "+nLinea + " : " + sError;ErrorJS ("<FUN> no existe o da error la funcion JS:\n\t"+sDato+sError,oObj,1); return (true);}	

//			sDato = sDato.replace (/[\"]/gi, "\\\"");
//			sDato = sDato.replace (/[\']/gi, "\\\'");
			if (sDato) sDato = eval (sDato)			
			break	
		default:
		}
		window.onerror = g_oOnErrorEvent	

//		if (IsDate(vDato)) then vDato=FechaFormatoBD (vDato, "ES")	'Fechas BD
//		if (IsNumeric(vDatoBD)) then vDato=Round(vDato,2)
		sFinal	= sFinal + sDato

		sEXML	= sEXML.substr(nPos2+nTag2)			//v1.12 el +1 es nuevo!!!
		nPos1	= sEXML.indexOf(sTagInit)
		if (nPos1!=-1 && sTagInit!=sTagIni){
			nPos1Fin = sEXML.indexOf(">",nPos1)
			sTagIni = sEXML.substring(nPos1,nPos1Fin+1)
			nTag1=sTagIni.length
		}
		nPos2	= sEXML.indexOf(sTagFin,nPos1+nTag1)
	}
	sFinal	= sFinal + sEXML

	return sFinal
}

function CheckFalse (bValidar){
	bFalse = 0
	if (bValidar) bValidar = bValidar.toString().toLowerCase()
	if (!bValidar || bValidar=="0" || bValidar=="null" || bValidar=="false" || bValidar=="falso") bFalse=1
	return (bFalse)
}

function TagELSE(sDato){
	var a_sDatos = []
	var sTagElse = "<ELSE />"
	a_sDatos[0]=sDato
	a_sDatos[1]=""
	var nPos = sDato.f_indexOf (sTagElse,0)
	if (nPos!=-1){
		a_sDatos[0] = sDato.substring(0,nPos)
		a_sDatos[1] = sDato.substring(nPos+sTagElse.length)
	}
	return (a_sDatos)
}


// Funciones externas: 	[5.3] ParseEXMLs ()
function CreaComboEXML(sSelectName,sFuncion,sTitulo,sArrayBase,sEXMLtexto,sEXMLvalor,vValorSelected,sCampoOrden,sCampoDistinct) { 		//7.2
var nFilas,sCombo,i,nOption,sValor
var a_sOptions = new Array()
var a_vOrden = new Array()
var a_nPos = new Array()

	nFilas = sArrayBase.f_getRegsNum()
	if (nFilas==0) return ("")
	if (sEXMLvalor=="") sEXMLvalor=sEXMLtexto

	sCombo ='<SELECT NAME="'+sSelectName+'"'
	if (sFuncion) sCombo+= " " +sFuncion
	sCombo+='>'

	if (sTitulo!=""){
		sCombo += "<OPTION value=''"
		sCombo += ">" + sTitulo + "</OPTION>"
	}

	if (sCampoDistinct){
		a_nPos = DistinctMArray(sArrayBase,sCampoDistinct,1)
		nFilas = a_nPos.length
		if (nFilas==0) return ("")
	}
	
	for (i=0;i<nFilas;i++){
		nOption = i
		if (sCampoDistinct) nOption = a_nPos[i]
		sOption = "<option "
		sValor = ParseEXMLs (sEXMLvalor,"",sArrayBase,nOption)
		sOption += 'value="' + sValor + '"'
		if (sValor==vValorSelected)  sOption +=" SELECTED"
		if (sEXMLvalor==sEXMLtexto) sTexto=sValor			
		else sTexto = ParseEXMLs (sEXMLtexto,"",sArrayBase,nOption)
		sOption +=  ">" + sTexto + "</option>"

		a_sOptions[i] = sOption
		if (sCampoOrden) {
			a_vOrden[i] = BuscaMultiarray (sCampoOrden,sArrayBase,nOption)
		}
	}
	if (sCampoOrden) {
		a_vOrden = OrdenarArray(a_vOrden,1,0)
	}
	for (f=0;f<nFilas;f++){
		nOption = f		
		if (sCampoOrden) nOption = a_vOrden[f]
		sCombo+= a_sOptions[nOption]		
	}
	sCombo+='</SELECT>'
	return sCombo
}


function SubMArray(sJSarrayBase,a_sArrayD,a_nPos){		//3.5 Crea un subarray de otro array
var nRegs,nCampos,nPos,g=0,a_sArray1,a_sArray2
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_sArray2 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_sArray2 = eval ("a_v"+sArrayBase)		
	}

	nCampos = a_sArray1.length
	for (var f = 0; f < a_nPos.length ; f++){
		nPos = a_nPos[f]*nCampos
		for (h=0;h<nCampos;h++){			//Copia todo el registro
			a_sArrayD[g++]=a_sArray2[nPos++]
		}
	}
}


function BuscarSubMArray(sArrayBase,sCampo,sTexto,bIndices,bCaseDependiente,bExact,bAcentoDependiente){
var a_sArray1,a_sArray2,a_sArrayDatos,nCampos, nPos,f
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_sArray2 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_sArray2 = eval ("a_v"+sArrayBase)		
	}
	a_sArrayDatos = new Array()

	nRegs = sArrayBase.f_getRegsNum()
	nCampos = a_sArray1.length
	nPos = BuscaEnArray (a_sArray1,sCampo)
	for (f=0;f<nRegs;f++){
		a_sArrayDatos[f]= a_sArray2[(f*nCampos)+nPos]
	}
	return BuscarSubArray(a_sArrayDatos,sTexto,bIndices,bCaseDependiente,bExact,bAcentoDependiente)
}




function BuscarSubArray(a_vArray,sTexto,bIndices,bCaseDependiente,bExact,bAcentoDependiente){			//3.14 Crea un array con los datos que contienen el texto
var a_vFinal,nFinal,f,sDato,nFind
	a_vFinal= new Array()
	nFinal=0

	if (!bCaseDependiente) sTexto = sTexto.toUpperCase()
	if (!bAcentoDependiente) sTexto = FixAcentos (sTexto)

	for (f=0;f<a_vArray.length;f++){
		sDato = "" + a_vArray[f]
		if (!bCaseDependiente) sDato = sDato.toUpperCase()
		if (!bAcentoDependiente) sDato = FixAcentos (sDato)
		if (bExact){
			nFind= -1
			if (sDato==sTexto) nFind=1			
		}
		else{
			nFind = sDato.indexOf(sTexto)
		}
		if  (nFind!=-1){
			if (bIndices){
				a_vFinal[nFinal++]= f
			}
			else{
				a_vFinal[nFinal++]= sDato			
			}			
		}
	}
	return a_vFinal;
}


//Permita a_vMArray de Jonas (Valgan: sMArrayBase / a_vMArray )
//Anadir param para: bCaseInd
//sLogic = AND / OR
function MAcountMatches (sMArrayBase,a_sCampos,a_vValues,sLogic){
var f,g;
var sEXML=""
var sCampoAND = ""
var vValueAND = ""
var nMatches =0;

	if (sLogic=="AND" && a_sCampos.length>1) {
		for (f=0;f<a_sCampos.length;f++){
			sEXML += "<BD>"+ a_sCampos[f] + "</BD>"  
			sCampoAND += a_sCampos[f]
			vValueAND += ("" + a_vValues[f])
		}
		AddCampo2Multiarray (sMArrayBase,sCampoAND,sEXML)
		a_sCampos = [sCampoAND]
		a_vValues = [vValueAND]
	}
	nRegs = sMArrayBase.f_getRegsNum()
	for (f=0;f<nRegs;f++){
		for (g=0;g<a_sCampos.length;g++){
			if (a_vValues[g]==GetMArray(sMArrayBase,a_sCampos[g],f)){
				nMatches++
				break
			}
		}
	}	
	return (nMatches)
}

// bPos : 0=array de Datos 1=array de Pos
// BUG: No devuelve ordenados el array de Pos (el otro si)
function DistinctMArray(sArrayBase,sCampo,bPos){					//3.22
var f,i,nCampos,nRegs,bDistinct 
var j=0 
var a_vDatos = new Array();
var a_vDatosPos = new Array();

	if(IsArray(sArrayBase)){
		a_sElementosT = sArrayBase[0];
		a_vElementosT = sArrayBase[1];
	}
	else{
		a_sElementosT = eval ("a_s"+sArrayBase)
		a_vElementosT = eval ("a_v"+sArrayBase)		
	}

	var	nIndiceColumna = BuscaEnArray (a_sElementosT,sCampo)
 
	if(nIndiceColumna!=-1){
		nCampos = a_sElementosT.length
		nRegs = sArrayBase.f_getRegsNum()

		for(var i=0;i<nRegs;i++){
			vValor = a_vElementosT[(i*nCampos)+nIndiceColumna];
			bDistinct=1
			for (f=0;f<j;f++){			
				if (a_vDatos[f]==vValor) {
					bDistinct=0
					break
				}
			}
			if (bDistinct) {
				a_vDatos[j] = vValor;				
				a_vDatosPos[j++] = i;				
			}
		}
  		a_vDatos = OrdenarArray(a_vDatos);  
		if (bPos) a_vDatos = a_vDatosPos;
		return(a_vDatos);
	}
}

function OrdenarMultiarray(sArrayBase,sCampo,bCual,nDireccion){
var a_sArray1,a_sArray2,a_sArrayDatos,a_sOrdenado,nCampos, nPos,f
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_sArray2 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_sArray2 = eval ("a_v"+sArrayBase)		
	}
	a_sArrayDatos = new Array()

	nRegs = sArrayBase.f_getRegsNum()
	nCampos = a_sArray1.length
	nPos = BuscaEnArray (a_sArray1,sCampo,1)
	if (nPos!=-1) {	
		for (f=0;f<nRegs;f++){
			a_sArrayDatos[f]= a_sArray2[(f*nCampos)+nPos]
		}
		a_sOrdenado = OrdenarArray(a_sArrayDatos,bCual,nDireccion)
	}
	else{
		ErrorTabla ("no se puede ordenar por el campo ["+sCampo+"] inexistente de '.f_createOrden' de ["+sArrayBase+"]","",1)
	}
	return (a_sOrdenado)
}

// aMatriz: nombre del array con los valores a ordenar
// [bIndices]			Devuelve array con valores/indices				0/1
// [bOrdenacion]		Ordenado creciente/decreciente					0/1
// [nOrden]				""=auto 0=numerica 1=alfabetica 2=fecha
// [bCaseDependiente]	0=AaBb		1=AaBb	
function OrdenarArray(a_vArray,bIndices,bOrdenacion,nOrden,bCaseDependiente){
var a_vArrayOrdenado,vValor,vValorT,sCifrasF,nCifrasF	
	var nLength = a_vArray.length				//elementos
	if (nLength==0) return (a_vArray)

	var a_vArrayWork = new Array()
	var a_vArrayWork = a_vArrayWork.concat(a_vArray)
	var a_vArrayDest = new Array()
	var a_vArrayDest = a_vArrayDest.concat(a_vArray)
	
	var nCifras = nLength.toString().length		// cifras
	var sBase = "000000"						

	if (nOrden==null || nOrden==""){			// determinamos el tipo de datos
		nOrden=0						//Numeros
		var f=0

		while (nOrden==0 && f<nLength){				//buscamos algun texto
			vValor = a_vArrayWork[f++].toString()
			vValor = vValor.replace(/[,]/g,".")				// cambio comas por puntos
			if (vValor!=parseFloat(vValor)) nOrden=1		//Texto
		}

		vValorT= Fecha2Date(vValor)		//Para ordenar fechas en formato texto
		if (!isNaN(vValorT) && typeof(vValorT)=="object" && vValorT.constructor==Date){
			for (f=0;f<nLength;f++){
				a_vArrayWork[f] = FechaHoraEXML("<ANYO/><MESXX/><DIAXX/>",a_vArrayWork[f],"") 
			}
			nOrden=2
		}
	}

	for (f=0;f<nLength;f++){
		sCifrasF = f.toString()
		nCifrasF = sCifrasF.length
		a_vArrayWork[f] = a_vArrayWork[f] + "" + sBase.substring(0,nCifras-nCifrasF) + sCifrasF 
	}

	switch (nOrden){
	case 1:					//Alfabetica
		for (f=0;f<nLength;f++){
			if (!bCaseDependiente) a_vArrayWork[f] = a_vArrayWork[f].toLowerCase()
			a_vArrayWork[f] = FixAcentos (a_vArrayWork[f])
		}		
		a_vArrayOrdenado = a_vArrayWork.sort()
		break	
	case 2:					//Fecha
		a_vArrayOrdenado = a_vArrayWork.sort()
		break	
	default:				//Numerica
		a_vArrayOrdenado = a_vArrayWork.sort(OrdenNumerico)
	}

	if (bIndices){								//Indices
		for (f=0;f<nLength;f++){
			vValor = a_vArrayOrdenado[f]
			a_vArrayDest[f] = parseInt (vValor.substr(vValor.length-(nCifras)),10)
		}
	}
	else{										//Valores
		for (f=0;f<nLength;f++){
			vValor = a_vArrayOrdenado[f]
			a_vArrayDest[f] = a_vArray [parseInt (vValor.substr(vValor.length-(nCifras)),10)]
		}	
	}
	if (bOrdenacion) a_vArrayDest=a_vArrayDest.reverse()		//Orden Descendiente

	return (a_vArrayDest)
}



function OrdenNumerico(nValor1,nValor2){	//paso del caso de igualdad para q sea mas rapido
	if (parseFloat(nValor1)==parseFloat(nValor2)) return (0)
	if (parseFloat(nValor1)<parseFloat(nValor2)) return (-1)
	return (1)
}

// sEXML	<DIA/> <DIAXX/> <DIATEXTO/> <MES/> <MESXX/> <MESTEXTO/> <ANYO/> <HORAS/> <MINUTOS/> <SEGUNDOS/>
// (sEXML,[dFecha],[sSinFecha])
// [sSinFecha] (si dFecha es nula): [0/string] : devuelve la fecha de hoy(por defecto)/devuelve la cadena sSinFecha
function FechaHoraEXML(sEXML,dFecha,sSinFecha){			
var a_mes=new Array (0,"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio","Agosto","Septiembre", "Octubre", "Noviembre", "Diciembre")
var a_dia=new Array ("Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado")
var dia,diaxx,diatexto,mes,mesxx,mestexto,anyo,horas,minutos,segundos
var sTag,sTagValue

	if (dFecha) {
		if (typeof(dFecha)!="object" || dFecha.constructor!=Date){
			dFecha = CambiaFecha(dFecha)	//Paso fecha a formato USA
			dFecha = new Date(dFecha); 		//Fecha que le pasamos
		}
	}
	else {
		if (typeof(sSinFecha)!="undefined") return (sSinFecha)
		dFecha = new Date(); 			//Fecha de hoy
	}

	if (isNaN(dFecha)) return ("")		//Fecha invalida

	dia		= dFecha.getDate()
	diaxx	= dia
	if (diaxx<10) diaxx="0" + dia
	diatexto= a_dia[dFecha.getDay()]
	mes 	= dFecha.getMonth() + 1
	mesxx	= mes
	if (mesxx<10) mesxx="0" + mes
	mestexto= a_mes[mes]
	anyo 	= dFecha.getFullYear()		//En NS3 getYear() !!!

	horas 	= dFecha.getHours()
	minutos = dFecha.getMinutes()	
	if (minutos<10) minutos="0" + minutos
	segundos = dFecha.getSeconds()
	if (segundos<10) segundos="0" + segundos

	sTag = BuscaTagEXML (sEXML,1)
	while (sTag){
		if ( eval("typeof("+sTag.toLowerCase()+")") != "undefined") {
			sTagValue = eval(sTag.toLowerCase())
		}
		else {			
			sTagValue = "<"+sTag+">"
		}
		sEXML= SetTagEXML (sEXML,sTag,sTagValue,1)					
		sTag = BuscaTagEXML (sEXML,1)
	}
	return (sEXML)
}


function CambiaFecha(sFecha) {				//1.6 Cambia entre dd/mm/aa y mm/dd/aa
	nBarra1 = sFecha.indexOf("/")
	nBarra2 = sFecha.lastIndexOf("/")

	if (nBarra1!=-1 || nBarra2!=-1){	
		sDia= sFecha.substring(0,nBarra1)
		sMes= sFecha.substring(nBarra1+1,nBarra2)
		sAno= sFecha.substring(nBarra2+1)

		sFecha = sMes + "/" + sDia + "/" + sAno
	}
	return sFecha
}

function Fecha2Date(sFecha,cSeparador){		//1.9
var nBarra1,nBarra2,nEspacio,sDia,sMes,sAno,dFecha
var nDosPuntos1,nDosPuntos1,sHora="",sMins="",sSecs=""
	
	if (!cSeparador) {
		cSeparador = sFecha.substr (1,1)
		if (!isNaN(cSeparador)) cSeparador = sFecha.substr (2,1)
		if (!isNaN(cSeparador)) cSeparador="/"
	}

	nBarra1 = sFecha.indexOf(cSeparador)
	nBarra2 = sFecha.lastIndexOf(cSeparador)

	if (nBarra1!=-1 && nBarra2!=-1){	
		sDia= sFecha.substring(0,nBarra1)
		sMes= sFecha.substring(nBarra1+1,nBarra2)
		nEspacio= sFecha.indexOf(" ")				//Por si tiene hora
		if (nEspacio==-1){
			sAno= sFecha.substring(nBarra2+1)
		}
		else{
			sAno= sFecha.substring(nBarra2+1,nEspacio)

			nDosPuntos1 = sFecha.indexOf(":")
			if (nDosPuntos1!=-1){
				sHora = sFecha.substring(nEspacio+1,nDosPuntos1)
				nDosPuntos2 = sFecha.indexOf(":",nDosPuntos1+1)
				if (nDosPuntos2==-1){
					sMins = sFecha.substring(nDosPuntos1+1)			
				}
				else{
					sMins = sFecha.substring(nDosPuntos1+1,nDosPuntos2)
					sSecs = sFecha.substring(nDosPuntos2+1)
				}
			}
		}
		if (ValidaFecha(sDia,sMes,sAno,sHora,sMins,sSecs)) dFecha = new Date(sAno,sMes-1,sDia,sHora,sMins,sSecs)
//alert(sDia+"."+sMes+"."+sAno+" "+sHora+":"+sMins+":"+sSecs+"_"+dFecha)
	}
	return dFecha
}

function ValidaFecha (nDD,nMM,nAAAA){		//1.7 0/1  Invalida/Valida
	if (!nDD || !nMM || !nAAAA) return false
	if (isNaN(nDD)|| isNaN(nMM)|| isNaN(nAAAA)) return false
	if (nAAAA < 100) nAAAA+=1900			//Chapucilla
	var dFecha=new Date(nAAAA,nMM-1,nDD)
	if (nDD!=dFecha.getDate()) return false
	if (nMM!=(dFecha.getMonth()+1)) return false
	if (nAAAA!=dFecha.getFullYear()) return false
	return true;
}

// Devuelve sEXML con el TAG reemplazado por su valor
function SetTagEXML (sEXML,sTag,vValor,bSimple) {
var nPosIni,nPosFin

	if (bSimple){
		sTag = "<"+sTag+"/>"
		nPosIni = sEXML.indexOf(sTag)
		if (nPosIni!=-1) sEXML = CambiaTexto(0,sEXML,sTag,vValor,0)	
	}
	else{
		var sTagIni = "<"+sTag
		var sTagFin = "</"+sTag+">"
		var nTagIni=sTagIni.length

		nPosIni	= sEXML.indexOf(sTagIni)
		nPosFin	= sEXML.indexOf(sTagFin,nPosIni+nTagIni)
		if (nPosIni!=-1 && nPosFin!=-1){
			sTag = sEXML.substr(nPosIni,nPosFin+sTagFin.length-nPosIni)
			sEXML = CambiaTexto(0,sEXML,sTag,vValor,0)
		}
	}
	return sEXML
}


// [nModo]
// 0/defecto = Devuelve sTagValue o "" si lo no encuentra
// 1 = Devuelve FullTag o "" si lo no encuentra
function GetTagEXML (sEXML,sTag,nModo) {
var nPosIni,nPosFin,nTagFinA,nTagFinB,nTagFinA2
var nPropEnd = 0
var sTagIni = "<" + sTag
var sTagFin = "</"+ sTag + ">"

var sTagValue=""

	nPosIni	= sEXML.indexOf(sTagIni)
	nPosFin	= sEXML.indexOf(sTagFin)
	if (nPosIni!=-1 && nPosFin!=-1){ 
		if (nModo==1){
			sTagValue =  sEXML.substring(nPosIni,nPosFin+sTagFin.length)
		}
		else{
			nTagFinA= sEXML.indexOf(">")
			nTagFinB= sEXML.lastIndexOf(">",nPosFin)
	
			while (nTagFinA!=nTagFinB) {		//Busco comillas	
				nTagFinA2 = 0
				nPropIni = sEXML.indexOf("=",nPropEnd)
				if (nPropIni!=-1) {
					cChar = sEXML.charAt (++nPropIni)
					while (cChar==" ") cChar = sEXML.charAt (++nPropIni)
					if (cChar=="'" || cChar=='"') {
						nPropEnd = sEXML.indexOf(cChar,nPropIni+1)	
					}
					if (nPropEnd!=-1) nTagFinA2= sEXML.indexOf(">",nPropEnd)
					if (nTagFinA2-nPropEnd<5) nTagFinA2=0		// Por que antes ponia <1 !!!
				}
				if (nTagFinA2==0) nTagFinB = nTagFinA
				else nTagFinA = nTagFinA2
			}					
			nTagFinA++
			sTagValue = sEXML.substr(nTagFinA,nPosFin-nTagFinA)
//			nPosFin	= sEXML.indexOf(sTagFin,nPosIni+nTagIni)
//			if (nPosFin!=-1) sTagValue = sEXML.substr(nPosIni+nTagIni,nPosFin-nPosIni-nTagIni)
		}
	}
	return sTagValue
}


//Devuelve el valor de la Propiedad que le pedimos en el Tag que le damos
//[bPropUnica]
function GetPropEXML(sTag,sPropName,bPropUnica){
var nPropIni,nPropEnd,cChar	
var sPropValue = ""
var cCharEnd = ""
	if (bPropUnica) cCharEnd = ">"
	
	nPropIni = sTag.indexOf(sPropName+"=")
	if (nPropIni!=-1) {
		nPropIni += 1 + sPropName.length
		cChar = sTag.charAt (nPropIni++)
//		while (cChar==" ") cChar = sEXML.charAt (++nPropIni)
		if (cChar=="'" || cChar=='"') {
			nPropEnd1 = sTag.indexOf(cChar+">",nPropIni)	
			nPropEnd2 = sTag.indexOf(cChar+" "+cCharEnd,nPropIni)
			nPropEnd = Math.min (nPropEnd1,nPropEnd2)
			if (nPropEnd==-1) nPropEnd = Math.max (nPropEnd1,nPropEnd2)			
			if (nPropEnd!=-1) sPropValue = sTag.substring (nPropIni,nPropEnd)
		}
	}
	
	return (sPropValue)
}


// Devuelve sTag o "" si no encuentra ninguno
// [bSimple] : Tag unico que se autocierra <Simple/>
// [nPos] : Busca el tag a partir de esa posicion de la cadena (por defecto es 0)
function BuscaTagEXML (sEXML,bSimple,nPos){			//11.3
var sTag=""

	if (!nPos) nPos=0

	if (bSimple){
		var nPosIni,nPosFin,nPosIniCheck
		var sTagSimple1 = "<"
		var sTagSimple2 = "/>"
		var nTagSimple1=sTagSimple1.length

		while (nPos!=-1 && sTag==""){
			nPosIni		= sEXML.indexOf(sTagSimple1,nPos)
			nPosFin		= sEXML.indexOf(sTagSimple2,nPosIni+nTagSimple1)
			nPosIniCheck= sEXML.lastIndexOf(sTagSimple1,nPosFin)
//alert (nPosIni+"_"+nPosFin+"_"+nPosIniCheck)
			if (nPosIni!=-1 && nPosFin!=-1 && nPosIni==nPosIniCheck) sTag = sEXML.substr(nPosIni+nTagSimple1,nPosFin-nPosIni-nTagSimple1)	
			if (nPosIni==-1) nPos=-1
			else nPos = nPosIni+1
		}
	}
	else{
		var nPosIni1,nPosIni1
		var sTagIni1 = "<"
		var sTagIni2 = ">"
		var nTagIni1=sTagIni1.length

		while (nPos!=-1 && sTag==""){
			nPosIni1 = sEXML.indexOf(sTagIni1,nPos)
			nPosIni2 = sEXML.indexOf(sTagIni2,nPosIni1+nTagIni1)
			if (nPosIni1!=-1 && nPosIni2!=-1) {
				nPos = nPosIni1+1
				nPosIni2b = sEXML.indexOf(" ",nPosIni1+nTagIni1)
				if (nPosIni2b!=-1 && nPosIni2b<nPosIni2) nPosIni2 = nPosIni2b		// Caso Tag con propiedades
				sTag = sEXML.substr(nPosIni1+nTagIni1,nPosIni2-nPosIni1-nTagIni1)	
				if (GetTagEXML (sEXML,sTag)=="") sTag=""	// No existe ese tag 
			}
			else{
				nPos = -1
			}	
		}
	}
	return (sTag)
}

// sEXML = <OUT>...<IN>...</IN>..</OUT>
// sInnerFullTag = <IN>...</IN>
// sOuterTag = OUT
function GetOuterTag (sEXML,sInnerFullTag,sOuterTag){
var sOutTagIni = "<" + sOuterTag
var sOuterFullTag= "";

	var nPos = sEXML.indexOf (sInnerFullTag)
	if (nPos!=-1){
		var nPosIni = sEXML.lastIndexOf(sOutTagIni,nPos)
		if (nPosIni!=-1){
			sOuterFullTag = GetTagEXML (sEXML.substr(nPosIni),sOuterTag,1)
		}		 	
	}
	return (sOuterFullTag)	
}

function CambiaTexto(nAccion,sTexto,sBuscado,sNuevo,bMultiple){
	bOnlyOne=1
	if (bMultiple) bOnlyOne=0
	return (sTexto.f_replace (sBuscado,sNuevo,nAccion,bOnlyOne))
}


function BuscaMultiarrayBlock (sCampo,sArrayBase,nRegistro){
var sPre,nBlockPos,a_sArray1,a_vArray1

	if (sCampo.indexOf(".")==2 && typeof(g_a_vBlockFormat)!="undefined"){
		sPre = sCampo.substr(0,2)

		nBlockPos = BuscaEnArray (g_a_vBlockFormat,sPre)
		if (nBlockPos!=-1){
			nBlockPos = g_a_vBlockFormat[nBlockPos+1]
			sCampo = sCampo.substr(3)

			if(IsArray(sArrayBase)){
				a_sArray1 = sArrayBase[0];
				a_vArray1 = sArrayBase[1];
			}
			else{
				a_sArray1 = eval ("a_s"+sArrayBase)
				a_vArray1 = eval ("a_v"+sArrayBase)		
			}

			a_sBlockData = a_sArray1[nBlockPos]
			nBlockPos += a_sArray1.length*nRegistro
			a_vBlockData = a_vArray1[nBlockPos]
			return (BuscaMultiarrayBlock (sCampo,"BlockData",0))
		}
	}
	return (BuscaMultiarray (sCampo,sArrayBase,nRegistro))
}

function BuscaMultiarray (sCampo,sArrayBase,nRegistro){		//3.7 Busca sCampo en CampoArray1 y devuelve el valor que esta en la misma posicion en el nRegistro(0-N) del MultiArray2
	return (GetMArray(sArrayBase,sCampo,nRegistro))
}

function BuscaMArrayValor(sArrayBase,sCampo,vValor){		//3.16	Busca un valor en un MA y devuelve el nReg
var a_sArray1,a_sArray2,a_sArrayDatos,nRegs,nCampos,nPos,nReg,f
a_sArray1 = eval ("a_s"+sArrayBase)
a_sArray2 = eval ("a_v"+sArrayBase)

	nRegs = sArrayBase.f_getRegsNum()
	nCampos = a_sArray1.length
	nPos = BuscaEnArray (a_sArray1,sCampo)
	nReg=-1
	for (f=0;f<nRegs;f++){
		vValorC = a_sArray2[(f*nCampos)+nPos]
		if (vValor==vValorC){
			nReg=f
			break
		}
	}
	return nReg
}


function SetMArray(sArrayBase,sCampo,nRegistro,vValor){	//3.20 Busca sCampo de nRegistro y lo modifica
	var a_sArray1, a_vArray1;
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_vArray1 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_vArray1 = eval ("a_v"+sArrayBase)		
	}
	var f=0
	var nCampos = a_sArray1.length
	sCampo = sCampo.toLowerCase()			//No distingue entre MAY y min
	while (f<nCampos){
		if (typeof(a_sArray1[f])!="object"){
			if (sCampo==a_sArray1[f].toLowerCase()){
				nRegistro = (nRegistro*nCampos) +f
				a_vArray1[nRegistro]=vValor
				break
			}
		}
		f++
	}
}

function GetMArray(sArrayBase,sCampo,nRegistro){
	var a_sArray1, a_vArray1;
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_vArray1 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_vArray1 = eval ("a_v"+sArrayBase)		
	}

	var vValor,f=0
	var nCampos = a_sArray1.length
	sCampo = sCampo.toLowerCase()			//No distingue entre MAY y min
	while (f<nCampos){
		if (typeof(a_sArray1[f])!="object"){
			if (sCampo==a_sArray1[f].toLowerCase()){
				nRegistro = (nRegistro*nCampos) +f
				vValor=a_vArray1[nRegistro]
				break
			}
		}
		f++
	}
	if (typeof(vValor)=="undefined" && nRegistro==0){
		ErrorJS ("[i_exml.js] GetMArray() No esta definido el campo ["+sCampo+"] de ["+sArrayBase+"]","",1)
		vValor=""	
	}  	
	return vValor
}


function AddCampo2Multiarray (sArrayBase,sCampo,sEXML){
var a_sArray1,a_sArray2,nRegistros,nDatos,f,vValor
	var a_sArray1, a_vArray1;
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_sArray2 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_sArray2 = eval ("a_v"+sArrayBase)		
	}
	nRegistros = sArrayBase.f_getRegsNum()

	nDatos = a_sArray1.length

	a_sArray1=InsertArray (a_sArray1,sCampo)
	for (f=0;f<nRegistros;f++){
		vValor = ParseEXMLs(sEXML,"",sArrayBase,f)
		a_sArray2 = InsertArray (a_sArray2,vValor,((f+1)*nDatos)+f)
	}

	var a_sArray1, a_vArray1;
	if(IsArray(sArrayBase)){
		sArrayBase[0]=a_sArray1;
		sArrayBase[1]=a_sArray2;
	}
	else{
		eval ("a_s"+sArrayBase+"=a_sArray1")	
		eval ("a_v"+sArrayBase+"=a_sArray2")
	}

}


//sMArrayFrom,sMArrayTo,sCampoFrom,[sCampoTo],[a_sCamposFrom]
// MArrays con distinto numero de elementos
function JoinMArray(sMArrayTo,sMArrayFrom,sCampoTo,sCampoFrom,a_sCamposFrom){
var nReg,f,g,vValor
var nFromToPos=0

	if (!sCampoFrom) sCampoFrom = sCampoTo	
	if (!a_sCamposFrom) a_sCamposFrom = eval ("a_s"+sMArrayFrom)	//mal para Jonas !!!
	a_sMArrayFromTo = a_sCamposFrom			//MArrayFromTo tiene que ser global !!!
	a_vMArrayFromTo = []
	
	var nRegistrosTo = sMArrayTo.f_getRegsNum()
	var nCamposFrom = a_sCamposFrom.length
	for (f=0;f<nRegistrosTo;f++){
		vValor = GetMArray (sMArrayTo,sCampoTo,f)
		nReg = BuscaMArrayValor(sMArrayFrom,sCampoFrom,vValor)
		if (nReg==-1){	//Campos vacios
			for (g=0;g<nCamposFrom;g++){
				a_vMArrayFromTo[nFromToPos++] = ""		
			}
		}
		else{
			for (g=0;g<nCamposFrom;g++){
				a_vMArrayFromTo[nFromToPos++] = GetMArray (sMArrayFrom,a_sCamposFrom[g],nReg)		
			}
		}		
	}
	for (g=0;g<nCamposFrom;g++){
		AddCampo2Multiarray (sMArrayTo,a_sCamposFrom[g],"<FUN>GetMArray ('MArrayFromTo','"+a_sCamposFrom[g]+"',nRegistro)</FUN>")
	}
}


// MArrays con distinto numero de elementos
function _JoinMArray(sMArrayTo,sMArrayFrom,sCampoTo,sCampoFrom,a_sCamposFrom){
var nReg,f,g,vValor
var nFromToPos=0

	if (!sCampoFrom) sCampoFrom = sCampoTo	
	if (!a_sCamposFrom) a_sCamposFrom = eval ("a_s"+sMArrayFrom)	//mal para Jonas !!!
	a_sMArrayFromTo = a_sCamposFrom			//MArrayFromTo tiene que ser global !!!
	a_vMArrayFromTo = []
	
	var nRegistros = sMArrayTo.f_getRegsNum()
	if (nRegistros!=sMArrayFrom.f_getRegsNum()) {
		ErrorJS ("[i_exml.js] JoinMArray() Hay distinto numero de registros en los MArrays '"+sMArrayTo+"' y '"+sMArrayFrom+"'","",1)
		return
	}
	for (f=0;f<nRegistros;f++){
		vValor = GetMArray (sMArrayTo,sCampoTo,f)
		nReg = BuscaMArrayValor(sMArrayFrom,sCampoFrom,vValor)
		if (nReg==-1){
			ErrorJS ("[i_exml.js] JoinMArray() No coinciden los indices '"+sCampoTo+"' y '"+sCampoFrom+"' de los MArrays '"+sMArrayTo+"' y '"+sMArrayFrom+"'","",1)
			return
		}
		else{
			nCamposFrom = a_sCamposFrom.length
			for (g=0;g<nCamposFrom;g++){
				a_vMArrayFromTo[nFromToPos++] = GetMArray (sMArrayFrom,a_sCamposFrom[g],nReg)		
			}
		}		
	}
	for (g=0;g<nCamposFrom;g++){
		AddCampo2Multiarray (sMArrayTo,a_sCamposFrom[g],"<FUN>GetMArray ('MArrayFromTo','"+a_sCamposFrom[g]+"',nRegistro)</FUN>")
	}
}

function InsertArray (a_vArrayDest,a_vArray,nPosicion){		//3.6 a_vNewArray = InsertArray (a_vArray,"B",2)
var t1,t2;
	if (nPosicion==null){
		t1=a_vArrayDest
		t2=a_vArray
	}
	else{ 
		t1 = a_vArrayDest.slice(0, nPosicion)
		t2 = a_vArrayDest.slice(nPosicion)
		t1[nPosicion]=a_vArray
	}
	return (t1.concat(t2))
}

function BuscaEnArray (a_vArray,vValor,bCaseIndepen){			//3.1 Busca la posicion en el array del ultimo valor que se le pasa (Devuelve -1 si no encuentra ninguna)
var nLen,nPos,vDato
	nLen = a_vArray.length
	nPos=-1
	if (bCaseIndepen) vValor = vValor.toLowerCase()
	while (nPos<--nLen){ 
		vDato = a_vArray[nLen]
		if (bCaseIndepen) vDato = vDato.toLowerCase()
		if (vDato==vValor) {
			nPos=nLen
			break
		}
	}
	return nPos
}

function RegsMultiarray (sArrayBase){			//Para compatibilidad con cosas antiguas
	return (sArrayBase.f_getRegsNum())
}

function _RegsMultiarray (sArrayBase){			//DEPRECATED
var a_sArray1,a_sArray2,nRegs,nRegsInt
	window.onerror = function ErrorTrapJS(sError,sURL,nLinea) { sError="\n\n"+sURL+"\nLinea "+nLinea + " : " + sError;ErrorJS ("[i_exml.js] RegsMultiarray() No existen los arrays con datos 'a_s"+sArrayBase+"' y/o 'a_v"+sArrayBase+"'"+sError,"",1); return (true);}	
	var a_sArray1, a_vArray1;
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_sArray2 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_sArray2 = eval ("a_v"+sArrayBase)		
	}
	window.onerror=g_oOnErrorEvent

	nRegs= (a_sArray2.length / a_sArray1.length)

	nRegsInt = Math.ceil (nRegs)		//Por si el array esta incompleto
	if (nRegsInt!=nRegs){
		a_sArray2 [(nRegsInt*a_sArray1.length)-1] = ""
	}	
	return nRegsInt
}

// [vMArrayBase]	: "sManuel" / a_maJonas  
// [a_sCampos]	: campos a mostrar
function DebugMArray (vMArrayBase,a_sCampos) {
	var sHTML= "[i_exml.js v" + oIEXML.m_nVersion + "]"
	if (!vMArrayBase) vMArrayBase = oIEXML.m_sMArrayBase
	if (!IsArray(vMArrayBase)) {
		if (!vMArrayBase) return ("Error: No ha usado ningun MArray")
		sHTML += "\tMultiArray '"+vMArrayBase+"'"
	}
	sHTML+= "\n" + vMArrayBase.f_maDebug(a_sCampos)
	return (sHTML)
}


function _DebugMArray (vMArrayBase,a_sCampos) {
var f, nRegistrosMax=3
	var sHTML= "[i_exml.js v" + oIEXML.m_nVersion + "]\n\n"

	if (!vMArrayBase) vMArrayBase = oIEXML.m_sMArrayBase
	if (!IsArray(vMArrayBase)) {
		if (!vMArrayBase) return ("Error: No ha usado ningun MArray")
		sHTML += "MultiArray '"+vMArrayBase+"'\n"
		vMArrayBase = vMArrayBase.f_maBArray2MArray()
	}
	var nRegistros = vMArrayBase.f_getRegsNum()
	if (nRegistros<nRegistrosMax) nRegistrosMax = nRegistros

	sHTML += "\tETIQUETAS ("+vMArrayBase[0].length+" etiquetas)\n[" + vMArrayBase[0] + "]\n"
	sHTML += "\tVALORES (" + nRegistros+ " registros)\n"
	for (f=0;f<nRegistrosMax;f++){
		sHTML += DebugMArrayReg (vMArrayBase,a_sCampos,f)
	}
	if (nRegistrosMax<nRegistros){
		sHTML += "\t.....\n\t.....\n\t.....\n"
		sHTML += DebugMArrayReg (vMArrayBase,a_sCampos,nRegistros-1)		
	}

	return sHTML
}

function _DebugMArrayReg (vMArrayBase,a_sCampos,nReg) {
	var nDatos = vMArrayBase[0].length
	var sHTML = "["
	for (var g=0;g<nDatos;g++){
		if (g) sHTML += ","
		if (!a_sCampos || a_sCampos.f_indexOf(vMArrayBase[0][g],0,1)!=-1 ) sHTML += vMArrayBase[1][(nReg*nDatos)+g]
	}
	sHTML += "] (Reg. " + nReg + ")\n"
	return (sHTML)
}

function OperarMultiEXML(sArrayBase,sEXML){		// Ejecuta una funcion de EXML con todos los regs de un Multiarray
var	nRegs
var vValor=0
	if(IsArray(sArrayBase)){
		a_sArray1 = sArrayBase[0];
		a_sArray2 = sArrayBase[1];
	}
	else{
		a_sArray1 = eval ("a_s"+sArrayBase)
		a_sArray2 = eval ("a_v"+sArrayBase)		
	}
	nCampos = a_sArray1.length
	nRegs = (a_sArray2.length) / nCampos
	for (f=0;f<nRegs;f++){ 
		vValor += eval (ParseEXMLs(sEXML,"",sArrayBase,f))
	}
	return (vValor)
}

function ModMultiarray(sArrayBase,sCampo,sFuncion){		// Modifica un campo del MBArray (hay que programar lo que necesitemos y renombrar la funcion) 
var	nPos,nRegs,vValor
var a_sArray1 = eval ("a_s"+sArrayBase)
var a_sArray2 = eval ("a_v"+sArrayBase)

	nPos = BuscaEnArray (a_sArray1,sCampo)
	if (nPos!=-1) {
		nCampos = a_sArray1.length	//+1
		nRegs = (a_sArray2.length) / nCampos
		for (f=0;f<nRegs;f++){ 
			vValor = ParseEXMLs(sFuncion,"",sArrayBase,f)		//vValor1 = ParseCodigo (sJSarrayBase,a_sTDtexto[g+2],nFila)
//			vValor = ParseEXML("BD",sFuncion,sArrayBase,f)		//vValor1 = ParseCodigo (sJSarrayBase,a_sTDtexto[g+2],nFila)
//			vValor = ParseCodigo (sArrayBase,sFuncion,f)
//			if (bEval) vValor = eval (vValor)
			a_sArray2[nPos] = vValor
			nPos = nPos + nCampos
		}
	}
}

function XML2aForm (sXML,sJSarrayBase) {
var sValue
var f=0
var	sVacio = ""

	if (sJSarrayBase) {
		a_sFormNames = eval ("a_s"+sJSarrayBase)
		a_vFormValues = eval ("a_v"+sJSarrayBase)
	}

	sFullTag = GetTagEXML (sXML,"FORM",1)
	while (sFullTag){
		a_sFormNames[f] 	= GetPropEXML(sFullTag,"name")
		sValue = GetTagEXML (sFullTag,"FORM")
		sValue = RemoveIniFin (sValue,"<![CDATA[","]]>")
		a_vFormValues[f]	= sValue
		f++
		sXML = SetTagEXML (sXML,"FORM",sVacio,0)					
		sFullTag = GetTagEXML (sXML,"FORM",1)
	}
}

function RemoveIniFin (sText,sStart,sEnd){		// 9.11 Borra cadena del principio y del final 
	var nPos
	
	if (sStart) {
		nPos = sText.indexOf(sStart)
		if (nPos==0) {
			sText = sText.substring (sStart.length)
		}	
	}
	if (sEnd) {
		nPos = sText.lastIndexOf(sEnd)
		if (nPos+sEnd.length==sText.length) {
			sText = sText.substring (0,nPos)
		}	
	}
	return (sText)
}

function FixAcentos (sTexto){					//9.9
	var a_sOldChar = new Array ("/[á]/g","/[é]/g","/[í]/g","/[ó]/g","/[úü]/g","/[Á]/g","/[É]/g","/[Í]/g","/[Ó]/g","/[ÚÜ]/g")
	var a_sNewChar = new Array ("a","e","i","o","u","A","E","I","O","U")

	for (f=0;f<a_sOldChar.length;f++){
  		sTexto = sTexto.replace (eval(a_sOldChar[f]), a_sNewChar[f]);
	}
	return (sTexto)	
}

