///Librería

function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1) 
      return element;

    elements.push(element);
  }

  return elements;
}

Function.prototype.bind = function(object) {
  var __method = this;
  return function() {
    __method.apply(object, arguments);
  }
}

var NW =
{
	Version: '0.1',
	create: function()
	{
		return function()
		{ 
			this.initialize.apply(this, arguments);
		}
	}
}

var requestObj = null;
NW.Request = {
	xmlsend	: function(url, xml) //[,callback[,args]]]
	{		var request = false;
		var requestCallBack = false;
		// Objeto nativo XMLHttpRequest
		if(window.XMLHttpRequest)
		{
        	try
			{
				request = new XMLHttpRequest();
			}
			catch(e)
			{
				request = false;
			}
		}
		// Versión IE/Windows ActiveX
		else if(window.ActiveXObject)
		{
			try
			{
				request = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch(e)
			{
				try
				{
					request = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch(e)
				{
					request = false;
				}
			}
		}
		if(request)
		{
			if (arguments[2]) { requestCallBack = arguments[2]; };
			request.onreadystatechange = function()
			{
				if( request.readyState == 4 && request.status==200 )
				{
					if( requestCallBack )
					{
						requestCallBack(request.responseXML);
					}
				}
			}
			request.open("POST", url, true);
			request.setRequestHeader("Content-Type","text/xml");
			request.send(xml);
		}
	},
	
	send: function(url, method, params) //[,callback[,args]]]
	{
		//TODO: del alert(url + "?" + params);
		var request = false;
		var requestCallBack = false;
		var functionparams = "";
		// Objeto nativo XMLHttpRequest
		if(window.XMLHttpRequest)
		{
        	try
			{
				request = new XMLHttpRequest();
			}
			catch(e)
			{
				request = false;
			}
		}
		// Versión IE/Windows ActiveX
		else if(window.ActiveXObject)
		{
			try
			{
				request = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch(e)
			{
				try
				{
					request = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch(e)
				{
					request = false;
				}
			}
		}
		if(request)
		{
			if (arguments[3]) { requestCallBack = arguments[3]; };
			if (arguments[4]) { functionparams = arguments[4]; };
			request.onreadystatechange = function()
			{
				if( request.readyState == 4 && request.status==200 )
				{
					if( requestCallBack )
					{
						requestCallBack(request.responseXML, functionparams);
					}
				}
			}
			if(method == "get")
				url += "?" + params;
			request.open(method, url, true);
			if(method == "post")
			{
				request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
				request.send(params);
			}
			else
				request.send(null);
		}
	},

	_send: function(obj, url, method, params) //[,callback[,args]]]
	{
		var request = false;
		var requestCallBack = false;
		
		//alert(url + "?" + params);
		// Objeto nativo XMLHttpRequest
		if(window.XMLHttpRequest)
		{
        	try
			{
				request = new XMLHttpRequest();
			}
			catch(e)
			{
				request = false;
			}
		}
		// Versión IE/Windows ActiveX
		else if(window.ActiveXObject)
		{
			try
			{
				request = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch(e)
			{
				try
				{
					request = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch(e)
				{
					request = false;
				}
			}
		}
		if(request)
		{
			//requestCallBack = obj.onRequest;
			requestObj = obj;
			//if (arguments[3]) { requestCallBack = arguments[3]; };
			request.onreadystatechange = function()
			{
				if( request.readyState == 4 && request.status==200 )
				{
					if( requestObj )
					{
						requestObj.onRequest(request.responseXML);
						//requestCallBack(request.responseXML);
					}
				}
			}
			if(method == "get")
				url += "?" + params;
			request.open(method, url, true);
			if(method == "post")
			{
				request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
				request.send(params);
			}
			else
				request.send(null);
		}
	}
};

NW.Input = NW.create();
NW.Input.prototype =
{
	initialize: function(form, inputId, required, valtype, msg)
	{
		this.input = inputId;
		this.required = required;
		this.valtype = valtype;
		this.msg = msg;
		this.nwform = form;
		this.input.nw = this;
		if( valtype != 0 )
		{
			this.input.onkeyup = function()
			{
				if( this.nw.verify() )
				{
					this.className = "";
					this.nw.nwform.functionMsg("");
				}
				else
				{
					this.className = "error";
					this.nw.nwform.functionMsg(this.nw.msg);
				}
			}
		}
		else if( this.required != 0)
		{
			this.input.onkeyup = function()
			{
				if( this.value != "" )
				{
					this.className = "";
					this.nw.nwform.functionMsg("");
				}
			}
		}
	},
	verify: function()
	{
		//Verifica valor numerico numeNW
		if( this.valtype == 1 && this.input.type == 'text')
		{
			for(var i = 0; i < this.input.value.length; i++)
			{
//				alert((this.input.value.charAt(i) <> '-' || i <> 0));
				if( (this.input.value.charAt(i) < '0' || this.input.value.charAt(i) > '9') 
					&& (this.input.value.charAt(i) != '-' || i != 0) )
				{
					return false;
				}
			}
		}
		return true;
	},
	validate: function()
	{
		if( this.required )
		{
			switch(this.input.nodeName)
			{
				case 'INPUT':
					if ((this.input.type.match(/(submit|image|cancel|reset)/)) || (this.input.type.match(/(checkbox|radio)/) && !this.input.checked)) { break; };
					if( this.input.value.length == 0 )
					{
						return false;
					}
					//valida formato
					if(this.valtype == 2 && !this.checkdateformat(this.input.value) )
					{
						return false;
					}
					break;
				case 'SELECT':
					if( this.input.options[this.input.selectedIndex].value.length == 0 )
					{
						return false;
					}
					break;
			}
		}
		return true;
	},

	checkdateformat: function (fecha)
	{
		var dia, mes, ano;
		var dias_mes = new Array(13);
		var pos = fecha.indexOf("/");
		var pos1 = fecha.indexOf("/", pos + 1);

		dias_mes[0]="0";
		dias_mes[1]="31";
		dias_mes[2]="28";
		dias_mes[3]="31";
		dias_mes[4]="30";
		dias_mes[5]="31";
		dias_mes[6]="30";
		dias_mes[7]="31";
		dias_mes[8]="31";
		dias_mes[9]="30";
		dias_mes[10]="31";
		dias_mes[11]="30";
		dias_mes[12]="31";

		if( pos >= 0 && pos1 >= 0)
		{
			dia = fecha.substring( 0, pos);
			mes = fecha.substring( pos + 1, pos1);
			ano = fecha.substring( pos1 + 1, fecha.length);
			if( isNaN(dia) || isNaN(mes) || isNaN(ano) )
			{
				return false;
			}
			else
			{
				if ( (ano % 4 == 0) && (( ano % 100 ) != 0 || ( ano % 400 ) == 0)   ) 
				{ 
					dias_mes[2] = "29"; 
				}
				if(dia > dias_mes[parseInt(mes,10)])
				{
					return false;
				}
				if(mes > 12 || mes < 1)
				{
					return false;
				}
			}
		}
		else
			return false;
		return true;
	}

}

NW.Form = NW.create();
NW.Form.prototype =
{
	initialize: function(formId, functionOnSubmit, functionMsg, msgError)
	{
		if( document.getElementById )
		{
			this.form = document.getElementById(formId);
			this.functionMsg = functionMsg;
			this.msgError = msgError;
			if( this.form != null && this.form.tagName == 'FORM')
			{
				this.form.nw = this;
				this.form.onsubmit = function()
					{
						if( this.nw.validate() )
						{
							//Borra caja de mensaje
                            this.nw.functionMsg("");
							//Ejecuta función externa OnSubmit
							if( this.nw.functionOnSubmit )
							{
								return this.nw.functionOnSubmit(this);
							}
							return true;
						}
						else
						{
							this.nw.functionMsg(this.nw.msgError);
							return false;
						}
					}
				this.inputs = new Array();
				this.functionOnSubmit = functionOnSubmit;
			}
		}
	},
	addinput: function(inputId, required, valtype, msg)
	{
		if( this.form != null )
		{
			for (var i=0; i<this.form.elements.length;i++)
			{
				if (this.form.elements[i].name == inputId)
				{
					this.inputs.push(new NW.Input(this, this.form.elements[i], required, valtype, msg));
				};
			};
		}
	},
	validate: function()
	{
		var errors = 0;
		//Valida formularios requeridos
		for(var i = 0; i < this.inputs.length; i++)
		{
			if( !this.inputs[i].validate() )
			{
				this.inputs[i].input.className = 'error';
				errors++;
			}
		}
		if( errors > 0 )
			return false;
		return true;
	},
	formtoxml: function()
	{
		var xml = "";
		
		for (var i=0; i<this.form.elements.length;i++)
		{
			var e = this.form.elements[i];
			if (e.name!='')
			{ 
				switch(e.nodeName)
				{
					case 'INPUT':
						if ((e.type.match(/(submit|image|cancel|reset)/)) || (e.type.match(/(checkbox|radio)/) && !e.checked)) { continue; };
						xml += '<' + escape(e.name) + '>' + escape(e.value) + '</' + escape(e.name) + '>' + '\n';
						break;
					case 'SELECT':
						xml += '<' + escape(e.name) + '>' + escape(e.options[e.selectedIndex].value) + '</' + escape(e.name) + '>' + '\n';
						break;
				};
			};
		};
		return xml;
	}
}

///////////////////////////////////////////////////////////////////////////////
// GridScroller
// Implemnetación de grilla
NW.GridScroller = NW.create();

NW.GridScroller.prototype = {
	initialize: function(grid)
	{
		this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
		this.grid = grid;
		this.createScrollBar();
		this.scrollTimeout = false;
		this.lastScrollPos = 0;
		this.rows = new Array();
	},

	sizeIEHeaderHack: function()
	{
		if ( !this.isIE ) return;
		var headerTable = $(this.grid.tableId + "_header");
		if ( headerTable )
			headerTable.rows[0].cells[0].style.width = (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
	},

	createScrollBar: function()
	{
		var visibleHeight = this.grid.table.parentNode.offsetHeight;
		// crea el div externo del scroll...
		this.scrollerDiv  = document.createElement("div");
		var scrollerStyle = this.scrollerDiv.style;
		scrollerStyle.borderRight = '1px solid #ababab';
		scrollerStyle.position    = "relative";
		scrollerStyle.left        = this.isIE ? "-6px" : "-3px";
		scrollerStyle.width       = "19px";
		scrollerStyle.height      = visibleHeight + "px";
		scrollerStyle.overflow    = "auto";

		// create el div interno del scroll...
		this.heightDiv = document.createElement("div");
		this.heightDiv.style.width  = "1px";

		this.heightDiv.style.height = parseInt(visibleHeight * this.grid.totalRows/this.grid.visibleRows) + "px" ;
		this.scrollerDiv.appendChild(this.heightDiv);
		this.scrollerDiv.nw = this;
		this.scrollerDiv.onscroll = function ()
		{
			this.nw.handleScroll();
		}
		//Inserta el div
		var table = this.grid.table;
		table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
		//TODO evento de mousewheel

	},

	updateSize: function()
	{
		var table = this.grid.table;
		var visibleHeight = this.grid.table.parentNode.offsetHeight;
		this.heightDiv.style.height = parseInt(visibleHeight * this.grid.totalRows/this.grid.visibleRows) + "px";
	},

	rowToPixel: function(rowOffset)
	{
		return (rowOffset / this.grid.totalRows) * this.heightDiv.offsetHeight
	},
   
	moveScroll: function(rowOffset)
	{
		if( !this.scrollTimeout )
		{
			this.scrollTimeout = true;
			this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
			this.scrollTimeout = false;
		}
		//TODO
		//if ( this.metaData.options.onscroll )
		//	this.metaData.options.onscroll( this.liveGrid, rowOffset );
   },

	handleScroll: function()
	{
		if( ! this.scrollTimeout )
		{
		//	clearTimeout( this.scrollTimeout );

		//alert(this.lastScrollPos + "-" + this.scrollerDiv.scrollTop);
		var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
		if (scrollDiff != 0.00)
		{
			var r = this.scrollerDiv.scrollTop % (this.grid.table.offsetHeight/this.grid.table.rows.length);
			if (r != 0)
			{
				this.scrollerDiv.onscroll = null;
				if ( scrollDiff < 0 )
				{
					this.scrollerDiv.scrollTop += ((this.grid.table.offsetHeight/this.grid.table.rows.length)-r);
				}
				else
				{
					this.scrollerDiv.scrollTop -= r;
				}
				this.scrollerDiv.onscroll = function ()
				{
					this.nw.handleScroll();
				}
			}
		}
		var contentOffset = parseInt(this.scrollerDiv.scrollTop / (this.grid.table.offsetHeight/this.grid.table.rows.length));
		
		this.grid.requestContentRefresh(contentOffset);
		this.scrollTimeout = true;
		this.lastScrollPos = this.scrollerDiv.scrollTop;
		setTimeout(this.scrollIdle.bind(this), 200 );
		}
   },

	scrollIdle: function()
	{
		this.scrollTimeout = false;
		//TODO
		//if ( this.metaData.options.onscrollidle )
		//	this.metaData.options.onscrollidle();
	}
};

NW.Grid = NW.create();
NW.Grid.prototype =
{
	// tableId - identificador de la tabla
	// url - dirección desde donde rescatar los datos
	initialize: function(tableId, visibleRows, totalRows, url, requests_params, onscroll)
	{
		this.tableId = tableId;
		this.url = url;
		this.table = document.getElementById(tableId);
		this.visibleRows = visibleRows;
		this.totalRows = totalRows;
		this.scroller  = new NW.GridScroller(this);
		this.sortCol = null;	//Columna por la cual ordenar
		this.sortDir = 'asc';	//Orden ascendete por defecto (asc,desc)
		this.params = requests_params;	//Parametros adiconales de llamado
		this.offset = 0; //Posicion de los datos
		this.onscroll = onscroll;
		this.isOnRequest = false;
	},

	requestContentRefresh: function(contentOffset)
	{
		if( this.isOnRequest )
			return;
		//Arma consulta
		var queryString = '';
		if( this.params )
		{
			queryString = this.params + "&";
		}
		queryString  = queryString + 'offset=' + contentOffset + '&size=' + this.visibleRows;
		if (this.sortCol)
			queryString = queryString + '&sort_col=' + escape(this.sortCol) + '&sort_dir=' + this.sortDir;
		NW.Request._send(this, this.url, "get", queryString);
		this.isOnRequest = true;
	},
	
	onRequest: function(responseXML)
	{
		this.isOnRequest = false;
		var response = responseXML.getElementsByTagName('response')[0];
		if (response == null )
			return;
		//Respuesta de grilla
		if( response.getAttribute("type") != "grid" )
			return;

		//Total de datos
		var total = response.getAttribute("total");
		if( total != this.totalRows )
		{
			this.totalRows = total;
			this.scroller.updateSize();
		}
		//Offser de Scroll
		var offset = response.getAttribute("offset");
		this.scroller.moveScroll(offset);
		
		//Carga los datos
		var nodeRows = response.getElementsByTagName('rows')[0];
		if( nodeRows != null )
		{
			this.loadRows(nodeRows);
			//Llama función externa
			if( this.onscroll )
			{
				this.onscroll(responseXML);
			}
		}
	},
	
	loadRows: function(nodeRows)
	{
		var trs = nodeRows.getElementsByTagName("tr");
		for ( var i=0 ; i < trs.length; i++ )
		{
			//Setea un identificador para la fila
			var id = trs[i].getAttribute("id");
			if( id )
			{
				this.table.rows[i].id = id;
			}
			//Setea un estilo para la fila
			var style = trs[i].getAttribute("style");
			if( style )
			{
				this.table.rows[i].className = style;
			}
			else
			{
				this.table.rows[i].className = '';
			}
			var cells = trs[i].getElementsByTagName("td");
			for ( var j=0; j < cells.length ; j++ )
			{
				var value = NWUtil.getContentAsString(cells[j]);
				if( !value )
				{
					this.table.rows[i].cells[j].innerHTML = "&nbsp;";
				}
				else
				{
					this.table.rows[i].cells[j].innerHTML = value;
				}
			}
		}
		for (var i = trs.length; i < this.visibleRows; i++)
		{
			for(var j = 0; j < this.table.rows[i].cells.length; j++)
			{
				this.table.rows[i].cells[j].innerHTML = "&nbsp;";
				this.table.rows[i].id = '';
				this.table.rows[i].className = '';
			}
		}
	}
}

var NWUtil =
{
	//Función copiada de Rico
	getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS)
	{
		if ( arguments.length == 2 )
			mozillaEquivalentCSS = cssProperty;
		var el = $(htmlElement);
		if ( el.currentStyle )
			return el.currentStyle[cssProperty];
		else
        	return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
	},

	getContentAsString: function( parentNode )
	{
		return parentNode.xml != undefined ? 
			this._getContentAsStringIE(parentNode) :
			this._getContentAsStringMozilla(parentNode);
	},

	_getContentAsStringIE: function(parentNode)
	{
		var contentStr = "";
		for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
		{
			var n = parentNode.childNodes[i];
			if (n.nodeType == 4)
			{
				contentStr += n.nodeValue;
			}
			else
			{
				contentStr += n.xml;
			}
		}
		return contentStr;
	},

	_getContentAsStringMozilla: function(parentNode)
	{
		var xmlSerializer = new XMLSerializer();
		var contentStr = "";
		for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
		{
			var n = parentNode.childNodes[i];
			if (n.nodeType == 4)
			{ // CDATA node
				contentStr += n.nodeValue;
			}
			else
			{
				contentStr += xmlSerializer.serializeToString(n);
			}
		}
		return contentStr;
	}
}
