/**
 * @version		commutils.js 0.0
 * @copyright	Copyright (C) 2009 Communico.
 */

// Exclusive global vars
var mousex, mousey;

jQuery.noConflict();
jQuery(document).mousemove( function(e) { mousex = e.clientX; mousey = e.clientY; } );

function isarray(variable) { return ( variable.constructor == Array); }
function isdate(variable) { return ( variable.constructor == Date); }
function isnum(variable) { return ( typeof( variable ) === "number" ); }
function isbool(variable) { return ( typeof( variable ) === "boolean" ); }
function isstr(variable) { return ( typeof( variable ) === "string" ); }
function isfunc(variable) { return ( typeof( variable ) === "function" ); }
function isobj(variable) { return ( typeof( variable ) === "object" ); }
function isempty(variable) { return ( variable === "" ); }
function isnull(variable) { if ( typeof( variable ) === "undefined" ) { return true; } if ( variable === null ) { return true; } return false; }
function isundef(varname) { return typeof( window[varname] ) === "undefined"; }
function eq(var1, var2) { if ( typeof( var1 ) != typeof( var2 ) ) { throw new Error("Error", "Incorrect variable types"); } return var1 === var2; }
function neq(var1, var2) { if ( typeof( var1 ) != typeof( var2 ) ) { throw new Error("Error", "Incorrect variable types"); } return var1 !== var2; }
function gt(var1, var2) { if ( typeof( var1 ) != typeof( var2 ) ) { throw new Error("Error", "Incorrect variable types"); } return var1 > var2; }
function gte(var1, var2) { if ( typeof( var1 ) != typeof( var2 ) ) { throw new Error("Error", "Incorrect variable types"); } return var1 >= var2; }
function lt(var1, var2) { if ( typeof( var1 ) != typeof( var2 ) ) { throw new Error("Error", "Incorrect variable types"); } return var1 < var2; }
function lte(var1, var2) { if ( typeof( var1 ) != typeof( var2 ) ) { throw new Error("Error", "Incorrect variable types"); } return var1 <= var2; }
function exist(item) { if ( isnull(item) || (!isstr(item) && !isobj(item) ) ) { return false; } return jQuery(item).size() > 0; }
function count(list) { if ( isnull(list) || !isarray(list) ) { return 0; } return list.length; }

/**
 * Elimina un item de la lista.
 * @param	list	[array]		Lista de elementos comparables.
 * @param	item	[any]		Elemento a retirar.
 * @return	[boolean]	Cierto si se borró al menos un elemento.
 */
function listdelete(list, item)
{
	if ( isnull(list) || !isarray(list) || isnull(item) ) { throw new Error("Error", "Invalid parameter"); }		
	
	var deleted = false;
	for (var i = 0; i < count(list); i ++) { if ( eq(list[i], item) ) { list.splice( i, 1 ); deleted = true; } }
	return deleted;
}

/**
 * Encuentra un item en la lista.
 * @param	list	[array]		Lista de elementos comparables.
 * @param	item	[any]		Elemento a encontrar.
 * @return	[boolean]	Cierto si se encontró al menos un elemento.
 */
function listfind(list, item)
{
	if ( isnull(list) || !isarray(list) || isnull(item) ) { throw new Error("Error", "Invalid parameter"); }		
	
	for (var i = 0; i < count(list); i ++) { if ( eq(list[i], item) ) { return true; } }
	return false;
}

/**
 * Convierte un array disperso en un array compacto, eliminando los indices
 * de contenido nulo, y generando items cuyos indices son correlativos.
 * @param	list	[array]		Array disperso.
 * @return	[array]		Array compacto.
 */
function listpack(list)
{
	if ( isnull(list) || !isarray(list) ) { throw new Error("Error", "Invalid parameter"); }		
	
	var pack = [ ];
	for (var i = 0; i < count(list); i ++ ) { if ( !isnull(list[i]) ) { pack.push( list[i] ); } }
	return pack;
}

/**
 * Cuenta el número de elementos de un array disperso. Equivale al número de elementos
 * no-nulos. Equivale a la llamada count(listpack(list)), sin crear objetos intermedios.
 * @param	list	[array]		Array disperso.
 * @return	[number]	Número de elementos.
 */
function listcount(list)
{
	if ( isnull(list) || !isarray(list) ) { throw new Error("Error", "Invalid parameter"); }		
	
	var counter = 0;
	for ( var i = 0; i < count(list); i ++ ) { if ( !isnull(list[i]) ) { counter ++; } }
	return counter;
}

/**
 * Enrolla un array de valores en un array de intervalos, eliminando los valores intermedios
 * correlativos.
 * @param	list	[array]		Array de valores.
 * @param	step	[number]	Cantidad de salto correlativo.
 * @return	[array]		Array de intervalos.
 */
function listroll(list, step)
{
	if ( isnull(list) || !isarray(list) ||
		 isnull(step) || !isnum(step) ) { throw new Error("Error", "Invalid parameter"); }		
	if ( eq(count(list), 0) ) { return [ ]; }
	
	var roll = [ ];
	var start = list[0];
	var last = list[0];
	var current;
	for ( var i = 1; i < count(list); i ++ )
	{
		current = list[i];
		if ( neq(last + step, current) ) { roll.push( { start: start, end: last } ); start = current; }
		last = current;		
	}
	current = list[i-1];
	roll.push( { start: start, end: current } );
	
	return roll;
}

/**
 * Desenrolla un array de intervalos en un array de valores, generando los valores 
 * intermedios correlativos.
 * @param	roll	[array]		Array de intervalos.
 * @param	step	[number]	Cantidad de salto correlativo.
 * @return	[array]		Array de valores.
 */
function listunroll(roll, step)
{
	if ( isnull(roll) || !isarray(roll) ||
		 isnull(step) || !isnum(step) ) { throw new Error("Error", "Invalid parameter"); }		
	if ( eq(count(roll), 0) ) { return [ ]; }
	
	var list = [ ];
	for ( var i = 0; i < count(roll); i ++ )
	{	for ( var j = roll[i].start; j <= roll[i].end; j += step ) { list.push( j ); } }
	
	return list;
}	
		
/**
 * Finaliza un mensaje de proceso.
 * Depende de jQuery.
 * @param	prefix	[string]	Prefijo de componente.
 */
function msg_end(prefix) 
{
	if ( isnull(prefix) ) { throw new Error("Error", "Invalid parameter"); }
	 
	var msgs = jQuery("#msg_2 div[name='" + prefix + "']:last");
	jQuery(msgs).slideUp("normal", function() { jQuery(msgs).remove(); }); 
}

/**
 * Establece un mensaje de aviso.
 * Depende de jQuery.
 * @param	type	[number]	Tipo de mensaje:
 * 								0 - Temporal (Autodisipa)
 * 								1 - Permanente (Botón de cerrar)
 * 								2 - Proceso (Lo cierra el sistema)
 * @param	prefix	[string]	Prefijo de componente.
 * @param	[text]	[string]	Mensaje de aviso
 */
function msg(type, prefix, text)
{	
	if ( isnull( type )   || !isnum( type )   ||
	     isnull( prefix ) || !isstr( prefix ) ) { throw new Error("Parameter error", "Invalid parameter"); }		 
	if ( isnull( text )   || !isstr( text ) ) { text = status.NOTRANSLATION; }
	
	var newmsg = jQuery("<div name='" + prefix + "'>" + text + "</div>");
	jQuery("#msg_" + type).append(newmsg);
	
	if ( eq(type, 0) ) 
	{
		jQuery(newmsg).slideDown("normal");
		jQuery(newmsg).animate( { opacity: 1.0 }, 2000);
		jQuery(newmsg).slideUp("normal");
	}
	else if ( eq(type, 1) )
	{
		jQuery(newmsg).append("<button onclick='msg_close(this)'>X</button>");
		jQuery(newmsg).slideDown("normal");
	}
	else if ( eq(type, 2) )
	{
		msg_end(prefix);
		jQuery(newmsg).slideDown("normal");
	}
}

/**
 * Cierra un mensaje de aviso.
 * Depende de jQuery.
 * @param	msg					Elemento DOM.
 */
function msg_close(msg) 
{ 
	if ( isnull( msg ) ) { throw new Error("Parameter error", "Invalid parameter"); }
		
	jQuery(msg).parent().slideDown("normal", function() { jQuery(this).remove(); } ); 
}

/**
 * Selecciona una fila. La fila seleccionada tiene class "rowselected".
 * Almacena el identificador del objeto de la fila seleccionada.
 * Requiere filas identificadas por "row" + número fila.
 * Requiere elemento identificado por "panel".
 * Depende de jQuery.
 * @param	prefix	[string]	Prefijo de componente
 * @param	nrow	[number]	Número de fila seleccionada
 * @param	idsel	[number]	Identificador de obj de fila seleccionada
 */
function select(prefix, nrow, idsel) 
{ 
	if ( isnull( prefix ) || !isstr( prefix ) ||
	     isnull( nrow )   || !isnum( nrow )   ||
	     isnull( idsel )  || !isnum( idsel ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	jQuery("tr").removeClass("rowselected");
	jQuery("tr").css( { background: "white" } );
	jQuery("#" + prefix + "_content button.onselect").attr( { "disabled" : "disabled" } );
	
	if ( neq(nrow, 0) ) 
	{
		jQuery("#" + prefix + "_row" + nrow).addClass("rowselected");
		jQuery("#" + prefix + "_row" + nrow).css( { background: "#CCCCCC" } );		
		jQuery("#" + prefix + "_content button.onselect").attr( { "disabled" : "" } );
		jQuery("#" + prefix + "_id").val(idsel);
	}	
}

/**
 * Efectúa una petición AJAX a Joomla. La respuesta depende del controlador
 * del componente actual.
 * Depende de jQuery.
 * @param	values	[object]	Mapa asociativo "variable: valor" con los parámetros a pasar.
 * @param	prefunc	[function]	Función que se llamará durante la petición.
 * @param	func	[function]	Función que se llamará si hay respuesta.
 */
function dorequest(values, prefunc, func)
{		
	if ( isnull( values )   || !isobj( values ) ||
	     isnull( prefunc ) || !isfunc( prefunc ) || 
		 isnull( func)     || !isfunc( func ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	var datasend = { };
	
	// Values cleaning
	for ( var v in values )
	{
		if ( isnull( values[v] ) ) { continue; }
		else if ( isfunc( values[v] ) ) { continue; }
		else if ( isobj( values[v] ) ) 
		{
			if ( isarray( values[v] ) ) { datasend[v] = values[v].join(LS); }
							       else { datasend[v] = values[v].id; }
		}
		else { datasend[v] = values[v]; }
	}
	
	// Null cleaning		
	for ( var ds in datasend ) 
	{
		if ( isnull( datasend[ds] ) ) { delete datasend[ds]; }
		else if ( isobj( datasend[ds] ) ) { delete datasend[ds]; }
		else if ( isfunc( datasend[ds] ) ) { delete datasend[ds]; }
	}
	
	alert(echo(datasend));
	
	jQuery.ajax(
	{
		async: true,
		dataType: "text",
		type: "POST",
		url: "index.php",
		data: datasend,
		beforeSend: prefunc,
		dataFilter: function (data, type) { return jQuery.trim(data); },
		success: func
	});
}

/**
 * Efectúa una petición AJAX a Joomla de redirección de contenidos. La función
 * sustitute el contenido de la página por el devuelto por la redirección.
 * Requiere elemento identificado por "content" y elemento de indice.
 * Depende de jQuery.
 * @param	prefix		[string]		Prefijo de componente.
 * @param	component	[string]		Componente que es llamado.
 * @param	task		[string]		Tarea que es solicitada.
 * @param	[id]		[number]		Identificador de objeto que se usará
 * @param	[callback]	[function]		Función que se llama si se carga correctamente.
 */
function dotask(prefix, component, task, id, callback) 
{ 	
	if ( isnull( prefix )    || !isstr( prefix ) ||
	     isnull( component ) || !isstr( component ) ||
		 isnull( task )      || !isstr( task ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	if ( !isnull( callback ) && !isfunc( callback ) ) { throw new Error("Parameter error", "Invalid parameter"); }		 
	
	if ( isnull( id ) ) { id = 0; }
	else if ( !isnum( id ) ) { throw new Error("Parameter error", "Invalid parameter"); }	
	
	var data = 
	{ 
		callType: OP_EMBED, 
		option: component, 
		task: task, 
		id: id
	};

	jQuery.ajax(
	{
		async: true,
		dataType: "text",
		type: "POST",
		url: "index.php",
		data: data,
		beforeSend: function() { msg(2, prefix, status.LOADING); },
		dataFilter: function (data, type) { return jQuery.trim(data); },
		success: function(data) 
			{ 				
				msg_end(prefix);
				
				var htmlcontent = jQuery(data);
				
				var islogin = htmlcontent.children("#non_login");
				if ( exist(islogin) ) 
				{ 
					window.location.href = 'index.php'; 
					window.location.reload();
					return;
				}

				jQuery("#" + prefix + "_content").fadeOut("normal", function() 
				{ 
					jQuery("#" + prefix + "_content").hide(); 
					jQuery("#" + prefix + "_content").empty();
					jQuery("#" + prefix + "_content").append(htmlcontent);
					if ( isnull(callback) ) { jQuery("#" + prefix + "_content").fadeIn("normal"); }
									   else { jQuery("#" + prefix + "_content").fadeIn("normal", callback); }
				});					
			}
	});
}

/**
 * Efectúa una petición AJAX a Joomla de guardado de objeto.
 * Depende de jQuery.
 * @param	prefix		[string]	Prefijo de componente.
 * @param	component	[string]	Componente que es llamado.
 * @param	object		[object]	Objeto que se almacenara.
 * @param	[callback]	[function]	Función que se llama si se guarda correctamente.
 */
function dosave(prefix, component, object, callback)
{
	if ( isnull( prefix )    || !isstr( prefix ) ||
	     isnull( component ) || !isstr( component ) || 
		 isnull( object )    || !isobj( object ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	if ( !isnull( callback ) && !isfunc( callback ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	object.option = component;
	object.task = "save";
	object.callType = OP_AJAX;

	dorequest(	object,
				function() { msg(2, prefix, status.SAVING); },
				function(iderror)
				{ 
					msg_end(prefix);
					if ( isnull(iderror) ) { msg(1, prefix, status.ERROR_SAVE); return; }
					if ( !isnull(iderror) && eq(Number(iderror),  0) ) { msg(1, prefix, status.ERROR_SAVE); return; }
					if ( !isnull(iderror) && eq(Number(iderror), -1) ) { msg(1, prefix, status.INVALID_INPUT); return; }
					if ( !isnull(iderror) && eq(Number(iderror), -2) ) { msg(1, prefix, status.DUPLICATE_INPUT); return; }
					if ( !isnull(iderror) && eq(Number(iderror), -3) ) { msg(1, prefix, status.DUPLICATE_CHILD); return; }
					if ( !isnull(iderror) && eq(Number(iderror), -4) ) { msg(1, prefix, status.NO_CHILD); return; }
					else 
					{ 
						msg(0, prefix, status.SAVED);
						if ( !isnull(callback) ) { callback(object); }						
					}
				} );
}

/**
 * Efectúa una petición AJAX a Joomla de borrado de objeto.
 * Depende de jQuery.
 * @param	prefix		[string]	Prefijo de componente.
 * @param	component	[string]	Componente que es llamado.
 * @param	id			[number]	Identificador de objeto que se borrará.
 * @param	[callback]	[function]	Función que se lanzará cuando el borrado sea correcto.
 */
function doremove(prefix, component, id, callback)
{
	if ( isnull( prefix )    || !isstr( prefix ) ||
	     isnull( component ) || !isstr( component ) || 
		 isnull( id )        || !isnum( id ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	if ( !isnull( callback ) && !isfunc( callback ) ) { throw new Error("Parameter error", "Invalid parameter"); }

	dorequest(	{ 
					id: id,
					option: component,
					task: "remove",
					callType: OP_AJAX
				},
				function() { msg(2, prefix, status.REMOVING); },
				function(data) 
				{ 
					msg_end(prefix);
					msg(0, prefix, status.REMOVED); 
					jQuery("#" + prefix + "_content table.item_list tbody tr.selected").remove();
					jQuery("#" + prefix + "_content table.item_list tbody").removeClass("selected");
					if ( !isnull(callback) ) { callback(id); }
				} );
}

/**
 * Efectúa una redirección con los parámetros establecidos.
 * Depende de jQuery.
 * @param	options		[object]	Objeto de parámetros de la URL.
 */
function doredirect(options)
{
	if ( isnull( options ) || !isobj( options ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	var params = ["callType=-1"]; for ( var field in options ) { params.push(field + "=" + options[field]); }	
	window.location = "index.php?" + params.join('&');
}

/**
 * Efectúa un filtrado y paginado de un listado de objetos.
 * Depende de jQuery.
 * @param	prefix	[string]	Prefijo de componente.
 * @param	objects	[array]		Listado de objetos.
 * @param	fields	[array]		Campos a filtrar.
 * @param	npage	[number]	Pagina actual.
 * @return	[number]	Elementos filtrados (aunque esten fuera de pagina)
 */
function dolistfilter(prefix, objects, fields, npage)
{
	if ( isnull( prefix )  || !isstr( prefix )    ||
	     isnull( objects ) || !isarray( objects ) || 
		 isnull( fields )  || !isarray( fields )  || 
		 isnull( npage )   || !isnum( npage ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	var i;
	var nshow = 0;
	var nfilt = 0;

	var list = [ ];
	for ( i = 0; i < count(objects); i++ ) { if ( !isnull( objects[i] ) ) { list.push( objects[i] ); } } 
	
	for ( i = 0; i < count(list); i++ )
	{
		var nmatch = 0;		
		for (var k = 0; k < count(fields); k ++)
		{					
			var value =  String(list[i][fields[k]]);
			var filter = String(jQuery("#" + prefix + "_" + fields[k]).val());
			
			if ( isempty( value ) || isempty( filter ) ) { nmatch ++; continue; }
			else if ( neq( value.toUpperCase().indexOf(filter.toUpperCase()), -1 ) ) { nmatch ++; }
		}

		var row = jQuery("#" + prefix + "_itemid_" + list[i].id);
		row.hide();
		if ( eq( nmatch, count(fields) ) && gte( (nfilt ++), (npage * MAXPAGE) ) && lt( (nshow ++), MAXPAGE ) ) { row.show(); }		
	}
	
	return nfilt;
}

/**
 * Evalua el estado de la paginacion y desactiva / activa los elementos
 * de navegación segun el caso.
 * Depende de jQuery.
 * @param	prefix	[string]	Prefijo de componente.
 * @param	npass	[number]	Numero de elementos actualmente listados.
 * @param	npage	[number]	Numero de pagina actual.
 * @return	[number]	Cantidad de páginas.
 */
function dolistinfo(prefix, npass, npage)
{		
	if ( isnull( prefix ) || !isstr( prefix )   ||
	     isnull( npass )  || !isnum( npass ) || 
		 isnull( npage )  || !isnum( npage ) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	var lastpage = Math.floor(npass / MAXPAGE);
	if ( eq( (npass % MAXPAGE), 0 ) ) { lastpage--; }

	if ( gt( npage, 0) ) { jQuery("#" + prefix + " button.prevpage").attr({ disabled: ""}); }
				    else { jQuery("#" + prefix + " button.prevpage").attr({ disabled: "disabled"}); }

	if ( lt( npage, lastpage) ) { jQuery("#" + prefix + " button.nextpage").attr({ disabled: ""}); }
					       else { jQuery("#" + prefix + " button.nextpage").attr({ disabled: "disabled"}); }
					   
	return lastpage;
}

/**
 * Devuelve cierto si los rangos introducidos se solapan.
 * @param	x1	[number]	Inicio de primer rango 
 * @param	x2	[number]	Fin de primer rango
 * @param	y1	[number]	Inicio de segundo rango
 * @param	y2	[number]	Fin de segundo rango
 * @return	[boolean]	Cierto si los rangos se solapan.
 */
function collide(x1, x2, y1, y2)
{
	if ( isnull(x1) || !isnum(x1) ||
	     isnull(x2) || !isnum(x2) ||
		 isnull(y1) || !isnum(y1) ||
		 isnull(y2) || !isnum(y2) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	return ( (x1 < y2 && x2 > y2) ||
			 (x1 < y1 && x2 > y1) ||
			 (x1 >= y1 && x2 <= y2) );
}

/**
 * Devuelve la longitud en dias, del mes segun el año
 * @param	idmon	[number]	Mes gregoriano (mes + año * 12)
 * @return	[number]	Dias del mes.
 */
function monLen(idmon)
{
	if ( isnull(idmon) || !isnum(idmon) ) { throw new Error("Parameter error", "Invalid parameter"); }
		 	
	var year = Math.floor(idmon / 12);
	var mon = idmon % 12;
	return (mon===1? (year%4===0? 29 : 28) : (mon<=6? (mon%2===0? 31 : 30) : (mon%2===0? 30 : 31)));
}

/**
 * Representa en string una estampilla de tiempo.
 * @param	time	[number]	Estampilla de tiempo.
 * @return	[string]	Representacion de cadena.
 */
function strftime(time)
{
	if ( isnull(time) || !isnum(time) ) { throw new Error("Parameter error", "Invalid parameter"); }		
		 
	var date = new Date(time *1000);
	var str = JDF;
	str = str.replace(/dd/, date.getDate());
	str = str.replace(/mm/, date.getMonth()+1); // 0-11 a 1-12
	str = str.replace(/yy/, date.getFullYear());
	
	return str;
}

/**
 * Convierte a estampilla de tiempo UTC un string.
 * @param	time	[string]	Cadena de tiempo.
 * @return	[number]	Estampilla de tiempo UTC.
 */
function strptime(time)
{
	if ( isnull(time) || !isstr(time) ) { throw new Error("Parameter error", "Invalid parameter"); }	
	
	var vals = time.split("/");
	for ( var v = 0; v < count(vals); v ++ ) { if ( eq(vals[v].length, 1) ) { vals[v] = "0" + vals[v]; } }
	
	time = vals.join("/");
	var format = JDF;
	var year = Number(time.substr(format.indexOf("yy"), 4));
	var month = Number(time.substr(format.indexOf("mm"), 2))-1;
	var day = Number(time.substr(format.indexOf("dd"), 2));
	
	var utc = Date.UTC(year, month, day, 0, 0, 0);	
	return Math.floor( utc /1000);
}

/**
 * Trunca las estampillas de hora a una hora concreta.
 * @param	time	[number/array]	Estampilla(s) de tiempo.
 * @param	[hour]	[number]		Desplazamiento en horas.
 * @return	[number/array]	Estampilla(s) de tiempo truncadas.
 */
function truncatetime(time, hour)
{
	if ( isnull(time) || (!isnum(time) && !isarray(time) ) ) { throw new Error("Parameter error", "Invalid parameter"); } 
	if ( !isnull(hour) && !isnum(hour) ) { throw new Error("Parameter error", "Invalid parameter"); } 
	if ( isnum(time) ) { time = [ time ]; }
	if ( isnull(hour) ) { hour = 0; }

	for ( var t = 0; t < count(time); t ++ )
	{	
		var date = new Date(time[t] *1000);		
		var utc = Date.UTC( date.getFullYear(), date.getMonth(), date.getDate(), hour, 0, 0);
		time[t] = Math.floor( utc /1000 );
	}
	
	return (count(time) == 1? time[0] : time);
}

/**
 * Genera un completo calendario de año, dividido en meses.
 * Cada dia del año es identificable por "day" seguido de nº de dia del año.
 * Requiere elemento identificado por "calendar".
 * Depende de jQuery.
 * @param	prefix	[string]	Prefijo de componente
 * @param	year	[number]	Año a mostrar.
 */
function makecal_short(prefix, year)
{
	if ( isnull(prefix) || !isstr(prefix) ||
		 isnull(year) || !isnum(year) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	jQuery("#" + prefix + "_calendar table").remove();	
	for (var m = 0; m < 12; m ++ )
	{
		jQuery("#" + prefix + "_calendar").append("<table style='border-collapse: collapse'><thead></thead><tbody></tbody></table>");
	}
		
	jQuery("#" + prefix + "_calendar thead").each(function(i) 
	{	jQuery(this).append("<tr class='monthlabel'><th colspan='7'>" + months[i] + "</th></tr>"); 
		jQuery(this).append("<tr class='weeklabel'><th>" + days[1].substring(0,2) + "</th><th>" + days[2].substring(0,2) + "</th><th>" + days[3].substring(0,2) + "</th><th>" + days[4].substring(0,2) + "</th><th>" + days[5].substring(0,2) + "</th><th>" + days[6].substring(0,2) + "</th><th>" + days[0].substring(0,2) + "</th></tr>");
	} );
			
	for (var w = 0; w < 6; w ++ )
	{
		jQuery("#" + prefix + "_calendar tbody").append("<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>");
	}
	
	jQuery("#" + prefix + "_calendar table tbody").each(function(mon)
	{		
		var day = new Date(year, mon, 1, 0, 0, 0);
		var dayoffset = (eq( day.getDay(), 0 )? 7 : day.getDay())-1;
		var md = 1 - dayoffset;
		
		jQuery(this).children("tr").each(function(week)
		{	jQuery(this).children("td").each(function(wday)
			{	
				var day = new Date(year, mon, md, 0, 0, 0);
				if ( eq( day.getMonth(), mon ) )
				{
					var utc = Date.UTC(year, day.getMonth(), day.getDate(), 0, 0, 0);
					var time = Math.floor( utc /1000 );
					jQuery(this).text( day.getDate() );
					jQuery(this).attr("id", prefix + "_" + time);
				}
				md ++;
			} ); 
		} );		
	} );
}	

/**
 * Genera un completo calendario del año, dividido en meses.
 * Cada dia tiene nombre "day" seguido del dia del mes.
 * Cada fila tiene nombre "room" seguido del id de habitacion.
 * Requiere elemento identificado por "calendar".
 * Depende de jQuery.
 * @param	prefix		[string]	Prefijo de componente
 * @param	curryear	[number]	Año a mostrar
 * @param	currmon		[number]	Mes a mostrar
 * @param	makemode	[number]	Opcion de creacion: 0 - Nuevo, 1 - Agregar la izq, 2 - Agregar la der.
 */
function makecal_long(prefix, curryear, currmon, makemode)
{
	if ( isnull(prefix)   || !isstr(prefix) ||
		 isnull(curryear) || !isnum(curryear) ||
	     isnull(currmon)  || !isnum(currmon) ||
		 isnull(makemode) || !isnum(makemode) ) { throw new Error("Parameter error", "Invalid parameter"); }

	var i;	
	var list = listpack(rooms);
	
	curryear += Math.floor(currmon / 12);
	currmon = currmon % 12;
	
	if ( eq( makemode, 0 ) )
	{
		jQuery("#" + prefix + "_calendar").empty();
		jQuery("#" + prefix + "_calendar").empty();
		jQuery("#" + prefix + "_calendar").append("<div class='left' style='float: left'><div class='monthlabel' /><div class='weeklabel' /><div class='daylabel' /></div><div class='container' style='overflow:auto; overflow-y:hidden; width:621px; position: relative'><div class='layout'></div></div>");
		for (i = 0; i < count(list); i ++) { jQuery("#" + prefix + "_calendar div.left").append("<div class='room'><span>" + list[i].number + "</span>" + list[i].title + "</div>"); }		
	}

	var month = currmon;
	var idmon = month + (curryear*12);
	var monhtml = "<div id='" + prefix + "_month" + idmon + "' class='month' style='display: hidden; float: left; width: " + (monLen(month)*21) + "px; position: relative'><div class='monthlabel'>" + months[month] + "</div><div class='weeklabel' /><div class='daylabel' /></div>";
	
	if ( eq( makemode, 0 ) ) { jQuery("#" + prefix + "_calendar div.container div.layout").append(monhtml); }
	else if ( eq( makemode, 1 ) ) { jQuery("#" + prefix + "_month" + (idmon+1)).before(monhtml); }
	else if ( eq( makemode, 2 ) ) { jQuery("#" + prefix + "_month" + (idmon-1)).after(monhtml); }
	jQuery("#" + prefix + "_month" + idmon).data("monlen", monLen(idmon));
	
	var totaldays = 0;
	jQuery("#" + prefix + "_calendar div.container div.layout div.month").each( function() { totaldays += Number(jQuery(this).data("monlen")); } );		
	jQuery("#" + prefix + "_calendar div.container div.layout").width(totaldays*21);
	jQuery("#" + prefix + "_calendar div.container").height((count(list)+4) * 20);
	
	for (i = 0; i < count(list); i ++) { jQuery("#" + prefix + "_month" + idmon).append("<div class='room' />"); }	

	var current_month = month;
	var day = new Date(curryear, month, 1, 0, 0, 0);
	while ( eq( current_month, day.getMonth() ) )
	{
		var utc = Date.UTC(curryear, month, day.getDate(), 0, 0, 0);
		var time = Math.floor( utc /1000 );
		jQuery("#" + prefix + "_month" + idmon + " div.weeklabel").append("<div class='day day" + day.getDay() + "' style='float: left'>" + days[day.getDay()%7].substring(0, 2) + "</div>");
		jQuery("#" + prefix + "_month" + idmon + " div.daylabel").append( "<div class='day day" + day.getDay() + "' style='float: left'>" + day.getDate() + "</div>");
		jQuery("#" + prefix + "_month" + idmon + " div.room").each( function(r)
		{	
			jQuery(this).append("<div id='" + prefix + "_AM_" + list[r].id + "_" + time + "' class='day" + day.getDay() + "' style='cursor: crosshair; float: left; width: 10px; height: 19px; border-bottom: solid 1px black; display:block;' onclick='onrackleft(this)' oncontextmenu='onrackright(this); return false'><img src='components/com_commbase/lib/blank.png' style='width: 10px; height: 19px;' /></div>");
			jQuery(this).append("<div id='" + prefix + "_PM_" + list[r].id + "_" + time + "' class='day" + day.getDay() + "' style='cursor: crosshair; float: left; width: 10px; height: 19px; border-right: solid 1px black; display:block; border-bottom: solid 1px black' onclick='onrackleft(this)' oncontextmenu='onrackright(this); return false'><img src='components/com_commbase/lib/blank.png' style='width: 10px; height: 19px;' /></div>");
		} );
		
		day.setDate( day.getDate() + 1 );		
	}			
	
	jQuery(".monthlabel div.day").width(19);
	jQuery(".monthlabel").height(19);	
	jQuery(".weeklabel div.day").width(19);
	jQuery(".weeklabel").height(19);
	jQuery(".daylabel div.day").width(19);
	jQuery(".daylabel").height(19);		
	jQuery(".room").height(20);		
}	

/**
 * Genera un codigo HTML de color claro al azar.
 * @return	[string]	Cadena con codigo rgb().
 */
function randColor()
{
	return "rgb(" + (128 + Math.floor(Math.random() * 128)) + "," + 
					(128 + Math.floor(Math.random() * 128)) + "," + 
					(128 + Math.floor(Math.random() * 128)) + ")";
}

/**
 * Genera una estructura XML a partir de una clave y una variable.
 * @param	[key]	[string]	Clave, por defecto "root".
 * @param	[value]	[any]		Valor.
 * @return	[string]	Cadena XML.
 */
function xmlexport(key, value)
{
	if ( isnull( value ) ) { value = key; key = "root"; }	
	if ( (isnull(key) && isnull(value)) ) { throw new Error("Parameter error", "Invalid parameter: Key and value null"); }
	if ( (!isnull(key) && !isstr(key)) ) { throw new Error("Parameter error", "Invalid parameter: Key is not string"); }
	
	var outl;
	if ( isarray( value ) )
	{
		outl = [ ];
		for (var i = 0; i < count(value); i ++)  { outl.push(xmlexport(key, value[i])); }
		
		return outl.join("");
	}
	else if ( isobj( value ) )
	{
		outl = [ ];
		for (var field in value) { if ( !isfunc( value[field] ) ) { outl.push(xmlexport(field, value[field])); } }
		
		return "<" + key + ">" + outl.join("") + "</" + key + ">";			
	}	
	else 
	{
		return "<" + key + ">" + String(value) + "</" + key + ">";
	}
}

/**
 * Produce un objeto o array de objetos jscript a partir de una estructura XML
 * Depende de jQuery.
 * @param	xml		[string / object]	Estructura XML de los datos.
 * @return	[array / string]	Objetos javascript correspondientes o literal.
 */
function xmlimport(xml)
{		
	if ( isnull(xml) || (!isstr(xml) && !isobj(xml)) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	var data = { };	
	var jxml = jQuery(xml);	
	
	jxml.children().each( function() 
	{ 
		var jsub = jQuery(this);
		var fname = String(this.nodeName).toLowerCase();
		if ( isnull(data[fname]) ) { data[fname] = xmlimport(jQuery(this)); }
		else if ( !isarray(data[fname]) ) { data[fname] = [ data[fname], xmlimport(jQuery(this)) ]; }
		else { data[fname].push( xmlimport(jQuery(this)) ); }
	} );
	
	if ( eq(jxml.children().size(), 0) ) { return jxml.text(); }
									else { return data; }
}


/**
 * Enlaza un objeto JScript a un formulario.
 * Los datos del formulario corresponden a los campos del objeto.
 * Los cambios en el formulario afectan a los campos del objeto.
 * Depende de jQuery.
 * @param	prefix		[string]	Prefijo de componente.
 * @param	object		[object]	Objeto de datos para mapear.
 */
function linkobject(prefix, object) 
{ 	
	if ( isnull(prefix) || !isstr(prefix) ||
		 isnull(object) || !isobj(object) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	object.update = [ ];
	for ( var field in object ) 
	{		
		var input = jQuery("#" + prefix + "_" + field);
		if ( !exist(input) ) { continue; }
		
		input.data("object", object);
		input.data("field", field);		
		
		if ( !isnull( object[field] ) ) 
		{
			if ( !isarray( object[field] ) ) 
			{ 
				input.val( object[field] ); 
				if ( !isnull( input.attr("src") ) ) { input.attr("src", object[field] ); }
			}
			else
			{
				var selection = [ ];
				for ( var i = 0; i < count(object[field]); i ++ ) { selection.push( String(object[field][i]) ); }
				input.val( selection );
			}
		}
		else { if ( !isempty( input.val() ) ) { object[field] = input.val(); }  }
		
		if ( input.hasClass("color") ) { input.colorPicker( { color: input.val() } );  }
		if ( input.hasClass("sid") ) { parseSid(prefix); }
		
		input.change( function() 
		{ 
			var input = jQuery(this);
			var object = input.data("object");
			var field  = input.data("field");
			var istext = input.hasClass("text");
			var isnumb = input.hasClass("numeric");
			var value  = input.val();
			
			object[field] = (istext? String(value) :
							(isnumb? Number(value) : value ));
			if ( !isnull( object.update[field] ) ) { object.update[field](); }
		} );
	}
}

/**
 * Enlaza una lista de objetos JScript a una tabla y la rellena.
 * Requiere tbody dentro de table con clase item_list.
 * Depende de jQuery.
 * @param	prefix		[string]	Prefijo de componente.
 * @param	objects		[array]		Objetos de datos para mapear.
 * @param	fields		[array]		Campos del objeto a mostrar en la tabla.
 */
function linklist(prefix, objects, fields)
{
	if ( isnull(prefix)  || !isstr(prefix) ||
		 isnull(objects) || !isarray(objects) ||
		 isnull(fields)  || !isarray(fields) ) { throw new Error("Parameter error", "Invalid parameter"); }
		 
	var i;
	var tbody = jQuery("#" + prefix + "_content table.item_list tbody");
	tbody.empty();
	
	var list = listpack(objects);	
	for ( i = 0; i < count(list); i ++ )
	{
		var row = jQuery("<tr />");
		row.data("id", list[i].id );			
		row.attr("id", prefix + "_itemid_" + list[i].id );
		row.click( function() 
		{
			var id = jQuery(this).data("id");
			jQuery("#" + prefix + "_content .onselect:disabled").attr("disabled", "").show().removeClass("disabled");
			if ( !isundef("onlistselect") ) { if ( isfunc(onlistselect) ) { onlistselect(prefix, id); } }
			jQuery("#" + prefix + "_content table.item_list tbody tr.selected").removeClass("selected");
			jQuery(this).addClass("selected");
		} );
			
		for ( var f = 0; f < count(fields); f ++ )
		{
			var cell = jQuery("<td />");
			var value = list[i][fields[f]];
			row.append(cell);
						
			if ( isnull( value ) ) { continue; } else { value = String(value); }
			if ( eq( value.indexOf('#'), 0 ) ) { cell.css( { backgroundColor: value } ); }
									      else { cell.text( value ); }
		}
		
		tbody.append(row);
	}	
}

/**
 * Obtiene el identificador de la selección actual del componente.
 * @param	prefix		[string]	Prefijo de componente
 * @return	[number]	Identificador de objeto seleccionado.
 */
function getselected(prefix)
{
	if ( isnull(prefix) || !isstr(prefix) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	var sel = jQuery("#" + prefix + "_content table.item_list tbody tr.selected");	
	return sel.data("id");
}

/**
 * Prepara los campos y los label asociados según las clases asociadas:
 * - fecha: Asocia un selector de fechas al campo.
 * - color: Asocia un selector de color al campo.
 * - disabled: Desactiva el elemento
 * - tab: Asocia un grupo de pestañas al elemento, requiere estructura de pestañas.
 * - multiple: Permite selector multiple
 * - range: Establece un intervalo de opciones para un selector según valor en name.
 * - external: Establece un conjunto de opciones para un selector según name.
 * - expand: Para un selector, muestra todas las opciones posible (expande).
 * - collapse: Para un selector, sólo muestra la opción seleccionada (colapsa).
 * - label: Traduce automáticamente el texto de la etiqueta.
 * - numeric: Fuerza a valor entero un campo
 * - text: Fuerza a texto un campo
 * - sid: Fuerza a identificación personal un campo (agrega información de código y país)
 * - upload: Modifica el campo para que permita la subida de archivos inmediata.
 * - autohide: Estilo hidden si no hay opciones en el selector o no hay valor en el campo.
 * @param	prefix	[string]	Prefijo de componente.
 * Depende de jQuery.
 */
function setup(prefix)
{
	if ( isnull(prefix) || !isstr(prefix) ) { throw new Error("Parameter error", "Invalid parameter"); }
	
	jQuery("#" + prefix + "_content .fecha").each( function() { jQuery(this).datepicker( { dateFormat: JDF } ); } );
	jQuery("#" + prefix + "_content .disabled").attr( "disabled", "disabled" );
	jQuery("#" + prefix + "_content .tab").tabs({active: 0, selected: 0});	

	jQuery("#" + prefix + "_content select.multiple").each( function() { jQuery(this).attr( "multiple", "multiple" ); } );			
	jQuery("#" + prefix + "_content select.range").each( function()
	{
		jQuery(this).children("option.range").remove();
		
		var params = jQuery(this).attr("name");
		var pairs = params.split(":");
		
		var i;
		var range = [ ];
		for ( i = 0; i <= 1; i ++ )
		{			
			if ( eq(pairs[i].indexOf('.'),-1) ) 
			{
				if ( isnull(window[pairs[i]]) ) { range[i] = Number(pairs[i]); } 
										   else { range[i] = Number(window[pairs[i]]); }
			}
			else
			{
				var parts = pairs[i].split('.');
				range[i] = Number(window[parts[0]][parts[1]]);
			}
		}
		
		for ( i = range[0]; i <= range[1]; i++ ) { jQuery(this).append("<option class='range' value=" + i + ">" + i + "</option>"); }
	} );
	
	jQuery("#" + prefix + "_content select.external").each( function()
	{
		jQuery(this).children("option.external").remove();
		
		var params = jQuery(this).attr("name");
		var pairs = params.split(":");

		var external = [ ];
		var i;
		for (i = 0; i <= 1; i ++)		
		{
			external[i] = { };
			var parts = pairs[i].split('.');		
			external[i].variable = parts[0];
			if ( !isnull(parts[1]) ) { external[i].field = parts[1]; }
		}
			
		var values = listpack(window[external[0].variable]);
		var options = listpack(window[external[1].variable]);		
		
		for (i = 0; i < count(values); i++ ) 
		{				
			var value = (!isnull(values[i][external[0].field])? values[i][external[0].field] : values[i]);
			var option = (!isnull(options[i][external[1].field])? options[i][external[1].field] : options[i]);
			
			jQuery(this).append("<option class='external' value=" + value + ">" + String(option) + "</option>");			
		}	
	} );
	
	jQuery("#" + prefix + "_content select.expand").each( function() { 	jQuery(this).attr("size", jQuery(this).children().size()); } );	
	jQuery("#" + prefix + "_content select.collapse").each( function() { jQuery(this).attr("size", 1); } );	
	
	jQuery("#" + prefix + "_content .label").each( function() 
	{ 
		var idtext = jQuery(this).text();
		
		if ( isnull( text[idtext] ) ) { jQuery(this).text( idtext ); }
		else { jQuery(this).text( text[idtext] ); }
	} );

	jQuery("#" + prefix + "_component .label").each( function() 
	{ 
		var idtext = jQuery(this).text();
		
		if ( isnull( text[idtext] ) ) { jQuery(this).text( idtext ); }
		else { jQuery(this).text( text[idtext] ); }
	} );

	jQuery("#" + prefix + "_content label").each( function()  
	{ 
		var idtext = jQuery(this).attr("for");		
		
		if ( isnull( text[idtext] ) ) { jQuery(this).text( idtext ); }
		else { jQuery(this).text( text[idtext] ); }
	} );		
	
	jQuery("#" + prefix + "_content .numeric:input").each( function() 
	{
		var input = jQuery(this);
		if ( isnull(input.val()) || !isnum(Number(input.val())) ) { input.val(0); }
	} );
	
	jQuery("#" + prefix + "_content .text:input").each( function() 
	{
		var input = jQuery(this);
		if ( isnull(input.val()) || !isstr(input.val()) ) { input.val(""); }
	} );
	
	jQuery("#" + prefix + "_content input.sid").each( function()
	{
		var input = jQuery(this);
		input.change( function() { parseSid(prefix); } );
		input.after("<input id='" + prefix + "_sid_cod' class='sid_cod' disabled='disabled' />");
		input.after("<input id='" + prefix + "_sid_src' class='sid_src' disabled='disabled' />");
		input.after("<input id='" + prefix + "_sid_num' style='display: none' />");		
	} );
	
	jQuery("#" + prefix + "_content input.upload").each( function()
	{
		var form = jQuery("<form />");
		form.attr({	method:	'POST', 
					enctype:'multipart/form-data', 
					action:	'index.php',
					target: 'hideframe'
				  });
		
		jQuery(this).wrap(form);
		jQuery(this).after("<iframe style='display: none' name='hideframe' />");
		jQuery(this).after("<input type='hidden' name='task' value='upload' />");
		jQuery(this).after("<input type='hidden' name='option' value='" + COMPONENT + "'/>");
	} );
	
	jQuery("#" + prefix + "_content select.autohide").each( function() 
	{ 
		var select = jQuery(this);
		var label = select.prev("label");
		var noptions = select.children("option").size();
		
		if ( eq( noptions, 0 ) )
		{
			select.css( "display", "none"); 
			label.css( "display", "none");
		}
	} );
		
	jQuery("#" + prefix + "_content input.autohide").each( function() 
	{ 
		var input = jQuery(this);
		var label = input.prev("label");
		
		if ( isnull(input.val()) || eq( Number(input.val()), 0 ) )
		{
			input.css( "display", "none"); 
			label.css( "display", "none");
		}
	} );
	hide_publicidad(prefix);		
}
/**
 * muestra un componente que esta oculto por plantilla mientras se carga y se ve la publicidad
 * @param	prefix		[string]	Prefijo de componente
 */

function display_component(prefix)
{
	
	jQuery("#" + prefix + "_component").fadeIn("fast");
}
/**
 * oculta la publicidad en componente 
 * @param	prefix		[string]	Prefijo de componente
 */

function hide_publicidad(prefix)
{
	jQuery("#publicidad_componente").fadeOut("fast",display_component(prefix));
}
/**
 * Devuelve una cadena formateada con el contenido del valor, objeto,
 * definición de función o array de objetos jscript
 * @param	data	[any]	Variable a leer.
 * @return	[string]	Cadena formateada.
 */
function echo(data)
{
	if ( isnull(data) ) { return "(null)"; }
	
	var outl = [ ];
	if ( isdate(data) ) { return "(date) " + data.toString(); }
	else if ( isarray(data) ) 
	{
		for ( var i = 0; i < count(data); i ++ ) { outl.push( echo(data[i]) ); }			
		return "[\n" + outl.join("\n") + "\n]";
	}
	else if ( isobj(data) )
	{
		for ( var field in data ) 
		{
			if ( !isfunc(data) ) { outl.push( field + ": " + echo(data[field]) ); }
							else { outl.push( echo(data[field]) ); }
		}		
		return "{\n" + outl.join("\n") + "\n}";
	}
	else { return "(" + typeof(data) + ") " + String(data); }	
}

/**
 * Devuelve una cadena formateada con los identificadores de los 
 * elementos de la página y en caso de inputs, su valor.
 * @return	[string]	Cadena formateada.
 */
function identifiers()
{
	var list = [ ];
	jQuery("*").each( function() { var id = jQuery(this).attr("id"); if ( !isnull(id) ) { list.push(id); } } );
	return echo(list);
}

/**
 * Devuelve una cadena formateada con el contenido de todas las variables
 * globales definidas en el entorno de ejecución JScript.
 * @return	[string]	Cadena formateada.
 */
function globals()
{
	var outl = [ ];
	for ( var item in window ) { if ( !isnull(window[item]) ) { outl.push("&lt;" + typeof(window[item]) + "&gt;" + item + "\n" ); } }
	return "{ " + outl.join(LS) + " }";
}

/**
 * Inserta una consola de depuración E/S. Se insertará como a nivel
 * de documento raiz. 
 * Requiere jQuery.
 */
function showconsole()
{
	var console = 
	{ 
		main: jQuery("<div />"), 
		caption: jQuery("<div />"),
		input: jQuery("<textarea id='Console' />"),
		control: jQuery("<div />"),
		execute: jQuery("<button />"),
		globals: jQuery("<button />"),
		identifiers: jQuery("<button />"),
		toggle: jQuery("<button />")
	};
	
	console.main.addClass("console");
	
	console.caption.css( { backgroundColor: "red", fontWeight: "bold" } );
	console.input.css( { backgroundColor: "black", color: "white", width: "640px", height: "100px" } );
	console.main.css( { position: "fixed", right: "0px", bottom: "0px", zIndex: "1000", borderColor: "black", borderWidth: "1px", borderStyle: "solid" } );
	console.control.css( { height: "20px" } );
	console.execute.css("float", "right");
	console.globals.css("float", "right");
	console.identifiers.css("float", "right");
	console.toggle.css("float", "right");
	
	console.caption.text("CONSOLE DEBUG");
	console.execute.text("EXE");
	console.globals.text("VAR");
	console.identifiers.text("IDS");
	console.toggle.text("X");

	console.execute.click( function() 
	{ 
		var result = "<pre>" + eval( jQuery("#Console").val() ) + "</pre>";		
		
		var output = window.open(this.href, this.target, 'width=475,height=775,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes');
 		output.document.write( result );
		output.document.close();
	} );
	
	console.globals.click( function() 
	{ 
		var output = window.open(this.href, this.target, 'width=475,height=775,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes');
 		output.document.write("<pre>" + globals() + "</pre>");
		output.document.close();
	} );

	console.identifiers.click( function() 
	{ 
		var output = window.open(this.href, this.target, 'width=475,height=775,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes');
 		output.document.write("<pre>" + identifiers() + "</pre>");
		output.document.close();
	} );
	
	console.toggle.click( function() { jQuery("#Console").toggle("normal"); } );
	
	console.control.append(console.toggle);
	console.control.append(console.identifiers);	
	console.control.append(console.globals);
	console.control.append(console.execute);
	
	console.main.append(console.caption);
	console.main.append(console.input);
	console.main.append(console.control);
	
	jQuery("*:first").prepend(console.main);
}

function MoneyFormat(amount) {
	
	var val = parseFloat(amount);
	var sign = 1;
		
	if (isNaN(val)) { return "0.00"; }
	
	val = Math.round(val*100)/100;
	
	if (val <= 0) { 
		var sign = -1;
	}
	
	val = val + "";
	
	if (val.indexOf('.') == -1) { 
		val=parseInt(val);
		return val+".00"; }
	else { 
		if (sign == 1){
			 val = val.substring(0,val.indexOf('.')+3);
			 val = (val == Math.round(val)) ? val + '.00' : ((val*10 == Math.round(val*10)) ? val + '0' : val); }
		else if (sign == -1) {
			 val = val.substring(1,val.indexOf('.')+3);
			 val = (val == Math.round(val)) ? '-'+ val + '.00' : ((val*10 == Math.round(val*10)) ? '-' + val + '0' : val); }
	}
		
	
	return val;
} 

