/**
 *	Engine Library
 *
 *		Conjunto de funciones generales para el Engine
 */
/*	© 2007 GOT.VERTIGO. Protected by copyright laws.
 *	Unauthorized copy or usage forbidden.
 */

var aDaysPerMonth 	= new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var aDeferredInits	= new Array();



/**
 * Funciones generales
 */
function isUndefined( val )
{
	return (typeof(val)=="undefined");
}


function isNumeric( val ) 
{
	if (typeof(val)=="number") return true;
	if (!isNaN(parseFloat(val))) return true;
	return false;
}


function isNumber( val ) 
{
	return (typeof(val)=="number");
}


function isInteger( val ) 
{
	if (typeof(val)=="undefined" || val==="" || val===null)
		return false;
		
	val = val.toString();
	var c;
    for (var i=0; i<val.length; i++){   
        c = val.charAt(i);
        if ((c<"0" || c>"9") && ((c!="+" && c!="-") || i>0))
        	return false;
    }
    return true;
}


function isBoolean( val ) 
{
	return (typeof(val)=="boolean");
}


function isObject( obj )
{
	return (typeof(obj)=="object" && obj!==null);
}


/**
 * Analiza un objeto y determina si es instancia de una clase dada o, alternativamente, 
 * si cumple con la implementación de la interfaz dada. Esta función puede considerarse
 * una expansión del operador instanceof nativo de JavaScript.
 * 	@param object obj	Objeto a evaluar como instancia de una clase o interfaz
 * 	@param object classOrInterface	Función constructora de clase u objeto-interfaz
 * 	@return boolean true	Si obj es instancia de la clase o interfaz classOrInterface,
 *			false en caso contrario
 */
function instanceOf( obj, classOrInterface ) 
{
	if (!obj || !classOrInterface) return false;
	var type = typeof(classOrInterface);
	
	if (type=="function" && (obj instanceof classOrInterface)) return true;
	
	if (classOrInterface && type=="object") {
		for (var x in classOrInterface) {
			if (typeof(classOrInterface[x])=="function" && typeof(obj[x])!="function")
				return false;
		}
	}
	return true;
}


function varDefault( varValue, varDefault )
{
	return (typeof(varValue)=="undefined" || varValue===null || varValue==="") ? varDefault : varValue;
}


function intVal( varValue )
{
	var v = parseInt(varValue, 10);
	if (isNaN(v))
		v = 0;
	return v;
}


function floatVal( varValue )
{
	var v = parseFloat(varValue);
	if (isNaN(v))
		v = 0;
	return v;
}


function bitMask( value, mask )
{
	return ((value & mask)==mask);
}

function cssToJs( propName )
{
	if (!propName)
		return null;

	var arr = propName.split("-"), str="", word="";
	for (var i=0; i<arr.length; i++) {
		word = arr[i].toString();
		if (i>0)
			str += (word.charAt(0).toUpperCase() + word.substr(1));
		else
			str += word;
	}
	return str;
}


function nl2br( str )
{
	return str.replace(/\r?\n/g, "<br>");
}


function arraySearch( arr, val )
{
	for (var i in arr) {
		if (arr[i]==val) return i;
	}
	return null;
}


function inArray( value, arr, ignoreCase )
{
	if (typeof(value)=="undefined") return null;

	if (typeof(value)=="string" && ignoreCase) {
		var val = value.toLowerCase();
		for (var i in arr) {
			if (arr[i].toLowerCase()==val) return true;
		}
	}
	else {
		for (var i in arr) {
			if (arr[i]==value) return true;
		}
	}
	return false;
}


function arrayMerge( arr1, arr2 )
{
	var res = new Array();
	for (var i=0; i<arguments.length; i++) {
		if (!arguments[i] || typeof(arguments[i])!="object")
			throw "arrayMerge: el argumento nº "+(i+1)+" no es un array";
		for (var k in arguments[i]) {
			if (isInteger(k))
				res.push(arguments[i][k]);
			else
				res[k] = arguments[i][k];
		}
	}
	return res;
}


function arrayIntersect( arr1, arr2 )
{
	if ((typeof(arr1)!="object" || arr2.constructor!=Array) 
				|| (typeof(arr2)!="object" || arr2.constructor!=Array)) 
		return false;
	var index = 0;
	var intersection = new Array();
	for (var k1 in arr1) {
		for (var k2 in arr2) {
			if (arr1[k1]==arr2[k2])
				intersection[index++] = arr1[k1];
		}		
	}
	return intersection;
}


function concatArray( arr, rowGlue, keyValueGlue )
{
	if (typeof(arr)!="object")
		return false;

    res = "";
    for (var k in arr) {
		res += k+keyValueGlue+arr[k]+rowGlue;
	}
	return res.trim(rowGlue);
}


function arrayInsertAt( arr, element, position )
{
	if (typeof(arr)!="object" || arr.constructor!=Array)
		throw "arrayInsertAt: el primer parámetro debe ser un Array";
		
	if (typeof(position)=="undefined" || position>arr.length) {
		arr.push(component);
		return arr;
	}
	else {
		var aux = arr.slice(0, position);
		return aux.concat([element], arr.slice(position, arr.length));
	}
}


function arrayRemove( arr, element )
{
	var aux = new Array();
	for (var i=0; i<arr.length; i++)
	{
		if (arr[i]!==element)
			aux.push(arr[i]);
	}
	return aux;
}


function arrayRemoveAt( arr, index )
{
	var aux = new Array();
	for (var i=0; i<arr.length; i++)
	{
		if (i!=index)
			aux.push(arr[i]);
	}
	return aux;
}


/**
 * Funciones de control lógico de objetos y elementos html
 */
function includeOnce( includeFile, constantName )
{
    var isIncluded = false;

    /*
    try {
        isIncluded = (window[constantName]!=null);
    }
    catch (e) { }
    */

    if (!isIncluded)
        document.writeln('<'+'script language="javascript" src="'+includeFile+'"></'+'script>');
    else
    	alert(includeFile+" ya está incluido");
}


function cloneObject( obj, deep )
{
	if (!isObject(obj)) throw "cloneObject: Debe proporcionar un objeto a clonar";
	
	var aux = new Object();
	if (typeof(obj)=="function")
		aux.prototype.constructor = obj.constructor;
    for (var k in obj) {
        if (isObject(obj[k]) && deep==true) 
            aux[k] = cloneObject(obj[k], deep);
        else
            aux[k] = obj[k];
    }
    return aux;
}


function getElem( id, context )
{
	var obj = null;

	if (isObject(id))
		return id;

	if (typeof(context)!="object")
		context = document;

	if (context.getElementById)
		obj = context.getElementById(id);
	else
		obj = context.all[id];

	return obj;
}


function getTag( obj, tag )
{
    for (var i=0; i<obj.childNodes.length; i++) {
    	if (obj.childNodes[i].tagName==tag)
    		return obj.childNodes[i];
    }
    return null;
}


function getAllTags( tagName, context )
{
	var obj = null;

	if (typeof(context)!="object")
		context = document;

	if (context.getElementsByTagName)
		obj = context.getElementsByTagName(tagName);
	else
		obj = context.all.tags[tagName];

	return obj;
}


function getAttrib( elm, attrib )
{
	if (attrib==null)
		return false;

	if (typeof(elm)=="string")
		elm = getElem(elm);

    var att = elm.attributes[attrib];

	if (att!=null && typeof(att)!="undefined")
		return att.value;
	else
		return null;
}


function getStyle( elm )
{
	if (typeof(elm)=="string")
        elm = getElem(elm);

	if (elm==null || typeof(elm)!="object")
		return null;

	return (elm.style) ? elm.style : elm;
}


function getCurrentStyle( elm )
{
	if (typeof(elm)=="string")
        elm = getElem(elm);

	if (elm==null || typeof(elm)!="object")
		return null;

    if (elm.currentStyle)
    	return elm.currentStyle;
    else if (elm.style)
    	return document.defaultView.getComputedStyle(elm, null);
    else
    	return elm;
}


function getCurrentStyleProp( elm, propName )
{
	if (typeof(elm)=="string")
        elm = getElem(elm);

	if (elm==null || typeof(elm)!="object" || propName=="")
		return null;

    if (elm.currentStyle) { // IE
    	return elm.currentStyle[cssToJs(propName)];
    }
    else { // Mozilla
    	var prop = null;
    	try {
    		prop = elm.style[propName];
    	} catch (e) { }
    	if (prop) return prop;
    	else
			return document.defaultView.getComputedStyle(elm, null).getPropertyValue(propName);
	}
}


function getFrameDoc( iframe )
{
	if (typeof(iframe)=="string")
		iframe = getElem(iframe);

	if (typeof(iframe)!="object")
		return null;

	if (document.all)
		return iframe.document.frames[iframe.id].document;
	else
		return iframe.contentDocument;
}


function getXY( htmlNode, relativeTo )
{
	if (!htmlNode) throw "Debe proporcionar un elemento HTML";
	if (!htmlNode.tagName) throw htmlNode+" no es un elemento HTML";
	if (!relativeTo) relativeTo = document.body;
	var x=0, y=0, aux;
	do {
		x += intVal(htmlNode.offsetLeft);
		y += intVal(htmlNode.offsetTop);
		if (!htmlNode.parentNode) break;
			htmlNode = htmlNode.offsetParent;
		if (htmlNode) {
			x += intVal(htmlNode.style.paddingLeft);
			y += intVal(htmlNode.style.paddingTop);
		}
	}
	while (htmlNode && htmlNode.parentNode && htmlNode.offsetParent!=relativeTo);
	return [x, y];
}


function getDimensions( htmlNode)
{
	if (!htmlNode) throw "Debe proporcionar un elemento HTML";
	if (!htmlNode.tagName) throw htmlNode+" no es un elemento HTML";
	var w = htmlNode.offsetWidth;
	var h = htmlNode.offsetHeight;
	return [intVal(w), intVal(h)];
}


function insertHTML( node, html )
{
	if (!node) throw "Debe proporcionar un nodo HTML en el cual insertar el contenido";
	if (!html) return;
	if (document.all) {
		node.insertAdjacentHTML("beforeEnd", html);
	}
	else {
		var r = document.createRange();
		r.selectNode(node);
		var df = r.createContextualFragment(html);
		node.appendChild(df);
	}
}


function createText( text )
{
	return document.createTextNode(text);
}


function removeAllChildren( node )
{
	if (!node || !node.childNodes) 
		throw "Debe proporcionar un nodo HTML";
	for (var i=node.childNodes.length-1; i>=0; i--) {
		node.removeChild(node.childNodes[i]);
	}
}


/**
 * Funciones de manejo de acciones y contenidos de elementos html
 */
function openLocation( url, width, height, name, scrollbar, returnHandle )
{
	if (name!="") {
        var winHandle = openPopup(url, width, height, name, scrollbar, true, true);
	    if (returnHandle)
	        return winHandle;
	}
	else
		document.location = url;
}


function openPopup( url, width, height, name, scrollbar, resizable, returnHandle )
{
    params = "width="+width+", height="+height+", menubar=0, status=0";
    params += ', scrollbars=' + ((scrollbar==true) ? "1" : "0");
    params += ', resizable=' + ((resizable==true) ? "1" : "0");
    try {
	    winHandle = window.open(url, name, params);
	    if (winHandle) {
		    winHandle.focus();
		    winHandle.onblur = new Function("this.close();");
	    }
    } catch (e) { }
    if (returnHandle) return winHandle;
}


function createButton( name, text, width, height, clickEvent )
{
	var sHTML = '<button id="'+name+'" type="button" style="height:'+height+'; width:'+width+'" ';
	sHTML += ' onClick="'+clickEvent+'">'+text;
	sHTML += '</button>';
	return sHTML;
}


function createSelect( id, name, objectName, width, changeEvent, styleClass )
{
	var sHTML = '<select id="'+id+'" name="'+name+'" \n';
	sHTML += ' class="'+styleClass+'" style="height:18px; width:'+width+'px"\n';
	if (changeEvent)
		sHTML += ' onChange="'+objectName+'.'+changeEvent+'()"';
	sHTML += '></select>\n';
	return sHTML;
}


function populateSelectInterval( target, min, max, sel, nullEntry, keepOld )
{
	var currIndex, count;

	if (!target)
		throw "populateSelectInterval: Debe proporcionar un elemento SELECT";

	//borro las opciones preexistentes, a menos que keepOld sea verdadero
	if (keepOld!=true)
		target.options.length = 0;
	//si se especificó un valor para nullEntry, creo un item en la lista con valor ""
	if (typeof(nullEntry)!="undefined" && nullEntry!==null)
		target.options[target.options.length] = new Option(nullEntry, "", false, (""==sel));
	//cargo el intervalo de valores
	for (var i=min; i<=max; i++) {
		count = target.options.length;
        target.options[count] = new Option(i, i, false, (i==sel));
        if (i==sel) currIndex = count;
	}
	target.selectedIndex = currIndex;
}


function getSelectedValue( targetSel )
{
	if (typeof(targetSel)=="string")
		targetSel = getElem(targetSel);
	if (typeof(targetSel)!="object" || targetSel==null)
		return false;

	var i = targetSel.selectedIndex;
	if (i<0)
		return null;
	else
	    return targetSel.options[i].value;
}


function selectToArray( obj )
{
    if (!obj)
    	return false;

    if (!obj.options)
    	return false;

	var arr = new Array();

    for (var i=0; i<obj.options.length; i++) {
        arr[i] = new Array(obj.options[i].value, obj.options[i].text);
    }

	return arr;
}


function selectToCSV( obj )
{
    if (!obj)
    	return false;

    if (!obj.options)
    	return false;

	var arr = new Array();

    for (var i=0; i<obj.options.length; i++) {
		arr[i] = obj.options[i].value;
	}
	return arr.join(",");
}


function getRadioValue( targetRadio )
{
	if (typeof(targetRadio)!="object" || targetRadio==null)
		return false;

	for (var i=0; i<targetRadio.length; i++) {
		if (targetRadio[i].checked)
			return targetRadio[i].value;
	}
	return null;
}


function setRadioValue( targetRadio, value )
{
	if (typeof(targetRadio)!="object" || targetRadio==null)
		return false;

	for (i=0; i<targetRadio.length; i++) {
		targetRadio[i].checked = (targetRadio[i].value==value);
	}
}


function getCheckedOptions( obj )
{
	var arr = new Array(), c=0;

	if (typeof(obj)!="object" || obj==null)
		return false;

	for (var i=0; i<obj.length; i++) {
		if (obj[i].checked==true)
			arr[c++] = obj[i].value;
	}
	return arr;
}


function pixelsToPoints( pixels )
{
	return pixels/4*3;
}


function pointsToPixels( points )
{
	return points/3*4;
}


function ld_error( msg, returnValue )
{
	alert(msg);
	return (typeof(returnValue)!="undefined") ? retValue : false;
}


function doDeferredInits( objId )
{
    if (objId)
        aDeferredInits[objId].init();
    else
        for (var k in aDeferredInits) {
            aDeferredInits[k].init();
        }
}



/**
 * Métodos agregados para el objeto Function (herencia, etc)
 */

/**
 * Extiende el prototipo de una función constructora (clase) a partir de un constructor 
 * u objeto base, agregando las propiedades superClass (referencia al prototipo de
 * la clase base) y superConstructor (referencia al constructor de la clase base).
 *
 * sintaxis: 
 *		ConstructorDerivado.extend(ConstructorPadre)
 */
Function.prototype.extend = function( baseClassOrObject ) 
{
	// creo un constructor ad-hoc para evitar llamar implícitamente 
	// al constructor de la clase base al duplicar el prototipo
	var myConstructor = this;
	inheritAllButConstructor = function () { }
	inheritAllButConstructor.prototype = baseClassOrObject.prototype;
	this.prototype = new inheritAllButConstructor();
	this.prototype.constructor = myConstructor;
	this.superConstructor = baseClassOrObject;
	this.superClass = baseClassOrObject.prototype;
}


/**
 * Verifica que el prototipo de una función constructora ("clase") implemente todos
 * los métodos incluidos en uno o más objetos ("interfaces") dados.
 * En caso de que el prototipo de la función-clase no implemente alguno de los métodos
 * definidos en alguno de los objetos-interfaces, lanza una excepción informando
 * el método faltante.
 *
 * NOTA: A diferencia de Function.extend(), este método debe invocarse DESPUES de la 
 * definición de métodos agregados de la función-clase en cuestión.
 *
 * sintaxis: 
 *		ConstructorImplementador.implement(objetoInterfaz[, objetoInterfaz ...])
 */
Function.prototype.assertInterface = function( interfaceObject1, interfaceObjectN ) 
{
	var theInterface, missing = new Array();
	for (var i=0; i<arguments.length; i++) {
		theInterface = arguments[i];
		if (theInterface && typeof(theInterface=="object")) {
			for (var x in theInterface) {
				if (typeof(theInterface[x])=="function" 
							&& typeof(this.prototype[x])!="function")
					missing.push(x);
			}
		}
	}
	if (missing.length>0) 
		throw "La clase "+this.getName()+" no implementa los siguientes métodos:\r\n"+
					missing.join(", ");+
					"\r\n--------\r\n"+this.toString();
}


Function.prototype.getName = function () 
{
	var code = this.toString();
	var re = new RegExp("^\\s*function\\s+(\\w+)\\b", "i");
	res = code.match(re);
	return res[1];
}


/**
 * Métodos agregados para el objeto String
 */
String.prototype.trim = function ( charset, caseInsensitive )
{
	charset = (charset==null) ? "[\\s]+" : "["+charset+"\\s]+";
	var re = new RegExp("(^"+charset+")|("+charset+"$)", "g"+((caseInsensitive) ? "i" : ""));
	return this.replace(re, "");
}


String.prototype.lTrim = function ( charset, caseInsensitive )
{
	charset = (charset==null) ? "[\\s]+" : "["+charset+"\\s]+";
	var re = new RegExp("^"+charset, "g"+((caseInsensitive==true) ? "i" : ""));
	return this.replace(new RegExp("^"+charset, "g"+((caseInsensitive) ? "i" : "")), "");
}


String.prototype.rTrim = function ( charset, caseInsensitive )
{
	charset = (charset==null) ? "[\\s]+" : "["+charset+"\\s]+";
	var re = new RegExp(charset+"$", "g"+((caseInsensitive==true) ? "i" : ""));
	return this.replace(re, "");
}


String.prototype.stripChars = function ( charset, replaceWith, caseInsensitive )
{
	if (charset==null)
		return this;

	var re = new RegExp("["+charset+"]+", "g" + ((caseInsensitive==true) ? "i" : ""));
	return this.replace(re, replaceWith);
}


String.prototype.repeat = function ( loops )
{
	var result = "";
	for (var i=0; i<loops; i++) {
		result += this.toString();
	}
	return result;
}


String.prototype.padLeft = function ( length, filler )
{
	filler = varDefault(filler, "");
	var result = ""+this;
	while (result.length<length) {
		result = filler+result;
	}
	return result.substr(result.length-length);
}


String.prototype.padRight = function ( length, filler )
{
	filler = varDefault(filler, "");
	var result = ""+this;
	while (result.length<length) {
		result = result+filler;
	}
	return result.substr(0, length-1);
}


String.prototype.htmlSpecialChars = function ()
{
	var aux = this;
	aux = aux.replace(new RegExp("&", "g"), "&amp;");
	aux = aux.replace(new RegExp("<", "g"), "&lt;");
	aux = aux.replace(new RegExp(">", "g"), "&gt;");
	return aux;
}


String.prototype.unHtmlSpecialChars = function ()
{
	var aux = this;
	aux = aux.replace(new RegExp("&lt;", "g"), "<");
	aux = aux.replace(new RegExp("&gt;", "g"), ">");
	aux = aux.replace(new RegExp("&amp;", "g"), "&");
	return aux;
}

