// Constructor de la clase dibAjax
function dibAjax()
{
	this.xmlHttp = false;
	try
	{
		// Intentamos crear el objeto Msxml2.XMLHTTP
		this.xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
	}
	catch(exception)
	{
		try
		{
			// Intentamos crear el objeto Microsoft.XMLHTTP
			this.xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch(exception)
		{
			// Creamos el objeto XMLHttpRequest
			this.xmlHttp = new XMLHttpRequest();
		}
	}
}

// Realizar una peticion
// @param url			Url donde realizar la peticion
// @param values		Valores a pasar a la url
// @param loadingCtrl	Control que indica que se esta realizando la peticion, puede ser null
dibAjax.prototype.sendRequest = function(url, values, loadingCtrl)
{
	// Actualizar los valores de la clase
	this.loadingCtrl = loadingCtrl;
	// Truco para acceder a la clase ajax dentro de la funcion de xmlHttp
	var ajax = this;
	this.xmlHttp.onreadystatechange = function()
	{
		switch(ajax.xmlHttp.readyState)
		{
			case 0:
			{
				// Se aborto
				break;
			}
			case 1:
			{
				// Comienza a obtener el valor
				if(ajax.loadingCtrl != null)
				{
					ajax.loadingCtrl.style.display = "inline";
				}
				break;
			}
			case 4:
			{
				// Se ha obtenido una respuesta
				switch(ajax.xmlHttp.status)
				{
					case 0:
					{
						// No hacer nada, se ha abortado
						break;
					}
					case 200:
					{
						// Se debe de actualizar el control
						if(ajax.loadingCtrl != null)
						{
							ajax.loadingCtrl.style.display = "none";
						}
						var tempAjaxXmlHttp = ajax.xmlHttp;
						ajax.xmlHttp = null;
						ajax.updateControls(tempAjaxXmlHttp);
						break;
					}
					case 12029:
					{
					}
					case 12030:
					{
					}
					case 12031:
					{
					}
					case 12152:
					{
					}
					case 12159:
					{
						// Realizar peticion de nuevo
						this.xmlHttp.open("POST", url, true);
						this.xmlHttp.setRequestHeader("Content-Type","text/xml");
						this.xmlHttp.setRequestHeader("Cache-Control", "no-cache");
						this.xmlHttp.setRequestHeader("Connection", "close");
						this.xmlHttp.send(values);
						break;
					}
					default:
					{
						// Ha ocurrido un error, lo mostramos
						var msgError = "Error: " + ajax.xmlHttp.statusText + "(" + ajax.xmlHttp.status + ")";
						alert(msgError);
						break;
					}
				}
				ajax.xmlHttp = null;
				break;
			}
		}
	};
	// Realizar peticion
	this.xmlHttp.open("POST", url, true);
	this.xmlHttp.setRequestHeader("Content-Type","text/xml");
	this.xmlHttp.setRequestHeader("Cache-Control", "no-cache");
	this.xmlHttp.setRequestHeader("Connection", "close");
	this.xmlHttp.send(values);
};

// Miembros privados ***


// Actualizar todos los controles de la pagina web
// @param xmlHttp	Respuesta XML
dibAjax.prototype.updateControls = function(xmlHttp)
{
	var xmlCtrl = new dibXMLToCtrl(xmlHttp.responseXML);
	xmlCtrl.updateControls();
};

//Crear la clase que permite crear datos XML indicando el control y su tipo
function dibCtrlToXML()
{
	this.xmlWriter = new dibXMLWriter();
	this.xmlWriter.addNode("controls");
}

// Cerrar la clase para poder obtener su cuerpo xml al completo
// Se puede obtener el cuerpo desde el atributo this.Body
dibCtrlToXML.prototype.close = function()
{
	this.xmlWriter.endNode("controls");
	this.Body = this.xmlWriter.Body;
};

// Agregar un control al XML
// @param ctrl	Identificador del control
dibCtrlToXML.prototype.add = function(ctrl)
{
	if(ctrl == null)
	{
		return;
	}
	this.xmlWriter.addNode("control", null);
		// Atributos generales
		this.addValue("abbr", ctrl.abbr);
		this.addValue("action", ctrl.action);
		this.addValue("accept", ctrl.accept);
		this.addValue("accept-charset", ctrl.getAttribute("accept-charset"));
		this.addValue("accesskey", ctrl.accesskey);
		this.addValue("align", ctrl.align);
		this.addValue("alt", ctrl.alt);
		this.addValue("archive", ctrl.archive);
		this.addValue("axis", ctrl.axis);
		this.addValue("border", ctrl.border);
		this.addValue("cellspacing", ctrl.cellspacing);
		this.addValue("cellpadding", ctrl.cellpadding);
		this.addValue("char", ctrl.char);
		this.addValue("charset", ctrl.charset);
		this.addValue("charoff", ctrl.charoff);
		this.addValue("class", ctrl.getAttribute("class"));
		this.addValue("classname", ctrl.className);
		this.addValue("checked", ctrl.checked);
		this.addValue("cite", ctrl.cite);
		this.addValue("classid", ctrl.classid);
		this.addValue("codebase", ctrl.codebase);
		this.addValue("codetype", ctrl.codetype);
		this.addValue("cols", ctrl.cols);
		this.addValue("colspan", ctrl.colspan);
		this.addValue("coords", ctrl.coords);
		this.addValue("content", ctrl.content);
		this.addValue("data", ctrl.data);
		this.addValue("datetime", ctrl.datetime);
		this.addValue("declare", ctrl.declare);
		this.addValue("defer", ctrl.defer);
		this.addValue("disabled", ctrl.disabled);
		this.addValue("dir", ctrl.dir);
		this.addValue("enctype", ctrl.enctype);
		this.addValue("frames", ctrl.frames);
		this.addValue("headers", ctrl.headers);
		this.addValue("for", ctrl.getAttribute("for"));
		this.addValue("frameborder", ctrl.frameborder);
		this.addValue("height", ctrl.height);
		this.addValue("href", ctrl.href);
		this.addValue("hreflang", ctrl.hreflang);
		this.addValue("http-equiv", ctrl.getAttribute("http-equiv"));
		this.addValue("id", ctrl.id);
		this.addValue("ismap", ctrl.ismap);
		this.addValue("label", ctrl.label);
		this.addValue("lang", ctrl.lang);
		this.addValue("longdesc", ctrl.longdesc);
		this.addValue("marginheight", ctrl.marginheight);
		this.addValue("marginwidth", ctrl.marginwidth);
		this.addValue("maxlength", ctrl.maxlength);
		this.addValue("media", ctrl.media);
		this.addValue("method", ctrl.method);
		this.addValue("multiple", ctrl.multiple);
		this.addValue("name", ctrl.name);
		this.addValue("nohref", ctrl.nohref);
		this.addValue("noresize", ctrl.noresize);
		this.addValue("profile", ctrl.profile);
		this.addValue("readonly", ctrl.readonly);
		this.addValue("rel", ctrl.rel);
		this.addValue("rev", ctrl.rev);
		this.addValue("rows", ctrl.rows);
		this.addValue("rowspan", ctrl.rowspan);
		this.addValue("rules", ctrl.rules);
		this.addValue("scope", ctrl.scope);
		this.addValue("scrolling", ctrl.scrolling);
		this.addValue("shape", ctrl.shape);
		this.addValue("size", ctrl.size);
		this.addValue("span", ctrl.span);
		this.addValue("scheme", ctrl.scheme);
		this.addValue("selected", ctrl.selected);
		this.addValue("src", ctrl.src);
		this.addValue("standby", ctrl.standby);
		//this.addValue("style", ctrl.style);
		this.addValue("summary", ctrl.summary);
		this.addValue("tabindex", ctrl.tabindex);
		this.addValue("target", ctrl.target);
		this.addValue("title", ctrl.title);
		this.addValue("type", ctrl.type);
		this.addValue("usemap", ctrl.usemap);
		this.addValue("valign", ctrl.valign);
		this.addValue("valuetype", ctrl.valuetype);
		this.addValue("width", ctrl.width);
		this.addValue("innerhtml", "<![CDATA[" + ctrl.innerHTML + "]]>");
		// Atributos de un select
		if(ctrl.multiple)
		{
			var options = ctrl.options;
			if(options != null)
			{
				// Es un select ya que tiene options
				this.xmlWriter.closeNodeWithAttributes();
				var n;
				for(n = 0; n < options.length; n++)
				{
					var option = options[n];
					// Agregar este valor
					this.xmlWriter.addNodeWithAttributes("option");
						this.xmlWriter.addAttribute("value", option.value);
						if(option.selected)
						{
							this.xmlWriter.addAttribute("selected", "true");
						}
						else
						{
							this.xmlWriter.addAttribute("selected", "false");
						}
					this.xmlWriter.closeNodeWithAttributes();
					this.xmlWriter.endNode("option");
				}
			}
		}
		else
		{
			// Valor individual
			this.addValue("value", "<![CDATA[" + ctrl.value + "]]>");
			this.xmlWriter.closeNodeWithAttributes();
		}
	this.xmlWriter.endNode("control");
};

// Agregar un control al XML
// @param ctrl	Identificador del control
dibCtrlToXML.prototype.addById = function(idCtrl)
{
	// Tratar el control
	this.add(document.getElementById(idCtrl));
};

// Miembros privados ***

// Agregar un atributo al XML
// @param name	Nombre
// @param value	Valor
dibCtrlToXML.prototype.addValue = function(name, value)
{
	if(value != null && value != "" && value != "undefined")
	{
		this.xmlWriter.addNode(name, value);
	}
};

//Clase para poder enviar peticiones ajax de forma rapida y sencilla
function dibPageAjax()
{
	this.xml = new dibCtrlToXML();
}

// Agregar un control de tipo dib:Grid 
// @param id Identificador de la rejilla
dibPageAjax.prototype.addGridById = function(id)
{
	var row = 0, col = 0, retrycol = 0; 
	var ctrlid = document.getElementById(id + "_" + row + "_" + col);
	while(ctrlid != null)
	{
		while(ctrlid != null || (ctrlid == null && retrycol < 20))
		{
			if(ctrlid != null)
			{
				// Agregarlo
				this.xml.addById(id + "_" + row + "_" + col);
				// Mirar subctrls
				var subctrlidx = 1;
				ctrlid = document.getElementById(id + "_" + row + "_" + col + "_" + subctrlidx);
				while(ctrlid != null)
				{
					this.xml.addById(id + "_" + row + "_" + col + "_" + subctrlidx);
					subctrlidx++;
					ctrlid = document.getElementById(id + "_" + row + "_" + col + "_" + subctrlidx);
				}
			}
			else
			{
				retrycol++;
			}
			// Siguiente columna
			col++;
			ctrlid = document.getElementById(id + "_" + row + "_" + col);
		}
		// Siguiente file
		col = retrycol = 0;
		row++;
		ctrlid = document.getElementById(id + "_" + row + "_" + col);
	}
};

// Agregar un control al xml que se enviara mediante su id
// @param id Identificador del control
dibPageAjax.prototype.addById = function(id)
{
	this.xml.addById(id);
};

// Agregar un control al xml que se enviara
// @param ctrl Control
dibPageAjax.prototype.add = function(ctrl)
{
	this.xml.add(ctrl);
};

// Enviar la peticion ajax
// @param url			Url donde enviar el xml
// @param lodingCtrl	Control que se hara visible mientras se realiza la peticion
dibPageAjax.prototype.sendRequest = function(url, loadingCtrl)
{
	// Cerrar el xml
	this.xml.close();
	// Enviar peticion
	if(ajaxGlobal == null || (ajaxGlobal != null && ajaxGlobal.xmlHttp == null))
	{
		ajaxGlobal = new dibAjax();
		ajaxGlobal.sendRequest(url, this.xml.Body, loadingCtrl);
	}
};

// Clase que permite actualizar los controles de una pagina web mediante un xml
// @param xml	XML origen
function dibXMLToCtrl(xml)
{
	this.xml = xml;
}

// Actualizar todos los controles de la pagina web
dibXMLToCtrl.prototype.updateControls = function()
{
	var controls = this.xml.getElementsByTagName("control");
	var n;
	for(n = 0; n < controls.length; n++)
	{
		// Obtener el nodo XML
		var xmlCtrl = controls[n];
		if(xmlCtrl != null)
		{
			// Obtener su identificador
			var idCtrl = xmlCtrl.getAttribute("id");
			if(idCtrl != null)
			{
				if(idCtrl != "script")
				{
					// Obtener el control html
					var htmlCtrl = document.getElementById(idCtrl);
					if(htmlCtrl != null)
					{
						// Actualizar el control
						this.updateControl(idCtrl, xmlCtrl, htmlCtrl);
					}
				}
				else
				{
					// Ejecutamos un script
					var script = this.findChildNode(xmlCtrl, "code");
					eval(script);
				}
			}
		}
	}
};

// Miembros privados ***

// Buscar un nodo hijo
// @param xmlCtrl	Codigo XML del control
// @param nodeName	Nombre del nodo a buscar
// @return Valor del nodo indicado o null si no existe este nodo
dibXMLToCtrl.prototype.findChildNode = function(xmlCtrl, nodeName)
{
	// Tratar todos los nodos hijos
	var childs = xmlCtrl.childNodes;
	if(childs != null)
	{
		// Recorrer todos los hijos para buscar el nombre del nodo indicado
		var n;
		for(n = 0; n < childs.length; n++)
		{
			var child = childs[n];
			// Comprobar el nombre de este nodo hijo
			if(child.nodeName == nodeName)
			{
				// Nodo encontrado, retornar este valor
				return child.firstChild.nodeValue;
			}
		}
	}
	// Mirar si es un atributo
	return xmlCtrl.getAttribute(nodeName);
};

// Actualizar un control
// @param idCtrl	Identificador del control
// @param xmlCtrl	Codigo XML del control
// @param htmlCtrl	Control HTML
dibXMLToCtrl.prototype.updateControl = function(idCtrl, xmlCtrl, htmlCtrl)
{
	// Mirar si tiene innerHTML
	this.updateControl_innerHTML(xmlCtrl, htmlCtrl);
	// Mirar atributos dinamicos
	this.updateControl_dynamicAttributes(xmlCtrl, htmlCtrl);
	// Mirar atributos corregidos
	this.updateControl_fixedAttributes(xmlCtrl, htmlCtrl);
	// Tratar el control contra subnodos
	if(xmlCtrl.hasChildNodes)
	{
		// Mirar si tiene options
		this.updateControl_Options(xmlCtrl, htmlCtrl);
	}
};

// Actualizar el control si tiene el innerhtml
// @param xmlCtrl	Codigo XML del control
// @param htmlCtrl	Control HTML
dibXMLToCtrl.prototype.updateControl_innerHTML = function(xmlCtrl, htmlCtrl)
{
	// Mirar si se quiere cambiar el contenido del control al completo
	var innerHTML = this.findChildNode(xmlCtrl, "innerhtml");
	if(innerHTML != null)
	{
		htmlCtrl.innerHTML = innerHTML;
	}
};

// Actualizar el control con sus atributos dinamicos
// @param xmlCtrl	Codigo XML del control
// @param htmlCtrl	Control HTML
dibXMLToCtrl.prototype.updateControl_dynamicAttributes = function(xmlCtrl, htmlCtrl)
{
	// Atributos
	var attributes = new Array(
		"abbr", "action", "accept", "accept-charset", "accesskey", "align", "alt",
		"archive", "axis", "border", "cellspacing", "cellpadding", "char", "charset",
		"charoff", /*"class",*/ "checked", "cite", "classid", "codebase", "codetype", "cols",
		"colspan", "coords", "content", "data", "datetime", "declare", "defer",
		/*"disabled",*/ "dir", "enctype", "frames", "headers", "for", "frameborder", "height",
		"href", "hreflang", "http-equiv", "id", "ismap", "label", "lang", "longdesc",
		"marginheight", "marginwidth", "maxlength", "media", "method", "multiple",
		"name", "nohref", "noresize", "profile", "readonly", "rel", "rev", "rows", 
		"rowspan", "rules", "scope", "scrolling", "shape", "size", "span", "scheme",
		"selected", "src", "standby", /*"style",*/ "summary", "tabindex", "target", "title",
		"type", "usemap", "valign", "value", "valuetype", "width"
	);
	var n;
	for(n = 0; n < attributes.length; n++)
	{
		var attributeName = attributes[n];
		var value = this.findChildNode(xmlCtrl, attributeName);
		if(value != null)
		{
			htmlCtrl.setAttribute(attributeName, value);
		}
	}
};

// Actualizar el control con sus atributos dinamicos
// @param xmlCtrl	Codigo XML del control
// @param htmlCtrl	Control HTML
dibXMLToCtrl.prototype.updateControl_fixedAttributes = function(xmlCtrl, htmlCtrl)
{
	// Indicar nombre de la clase
	var className = this.findChildNode(xmlCtrl, "classname");
	if(className != null)
	{
		htmlCtrl.className = className;
	}
	else
	{
		var disabled = this.findChildNode(xmlCtrl, "disabled");
		if(disabled != null)
		{
			if(disabled == 'false')
			{
				htmlCtrl.disabled = false;
			}
			else
			{
				htmlCtrl.disabled = true;
			}
		}
	}
};

// Actualizar el control si tiene el innerhtml
// @param xmlCtrl	Codigo XML del control
// @param htmlCtrl	Control HTML
dibXMLToCtrl.prototype.updateControl_Options = function(xmlCtrl, htmlCtrl)
{
	// Tratar todos los nodos hijos
	var childs = xmlCtrl.childNodes;
	if(childs != null)
	{
		var options = htmlCtrl.options;
		// Eliminar todos los options si se indica en el nodo padre
		var removeOptions = this.findChildNode(xmlCtrl, "removeoptions");
		if(removeOptions == "true")
		{
			options.length = 0;
		}
		// Recorrer todos los hijos para tratar los options
		var n, option;
		for(n = 0; n < childs.length; n++)
		{
			// Obtener los valores del nodo del option
			var child = childs[n];
			if(child.nodeName == "option")
			{
				var optionText = child.getAttribute("text");
				var optionValue = child.getAttribute("value");
				var optionIndex = child.getAttribute("index");
				if(optionText == null)
				{
					// Indicar que el nombre y su valor son iguales
					optionText = optionValue; 
				}
				if(optionIndex == null)
				{
					// Si no se especifica el indice del option indicamos que es el ultimo
					optionIndex = options.length;
				}
				// Agregar el option con los valores y en su posicion correcta
				options[optionIndex] = new Option(optionText, optionValue);
			}
		}
	}
};

// Crear un escritor de XML
// El atributo Body es el que contiene el XML resultante
function dibXMLWriter()
{
	this.Body = "<?xml version='1.0' encoding='UTF-8'?>\r\n";
}

// Agregar un nodo sin atributos
// @param name	Nombre del nodo
// @param value	Valor del nodo, puede ser null, si no es null se cierra automaticamente
dibXMLWriter.prototype.addNode = function(name, value)
{
	if(value != null)
	{
		this.Body += "<" + name + ">" + value + "</" + name + ">";
	}
	else
	{
		this.Body += "<" + name + ">";
	}
};

// Agergar un nodo con atributos, se debe de llamar a "closenodewithattributes"
// @param name	Nombre del nodo
// @param value	Valor del nodo
dibXMLWriter.prototype.addNodeWithAttributes = function(name)
{
	this.Body += "<" + name;
};

// Agregar un atributo al nodo 
// @param name	Nombre del atributo
// @param value	Valor del atributo
dibXMLWriter.prototype.addAttribute = function(name, value)
{
	this.Body += " " + name + "=\"" + value + "\"";
};

// Cerrar un nodo con atributos
dibXMLWriter.prototype.closeNodeWithAttributes = function()
{
	this.Body += ">";
};

// Cerrar un nodo
// @param name	Nombre del nodo
dibXMLWriter.prototype.endNode = function(name)
{
	this.Body += "</" + name + ">";
};

// Objeto ajax global
var ajaxGlobal = null;
