//==================================================================
// 
// 
//
//
//
//
//
//  
//  JSRTF v1.5 (06/10/2011 02:24:16)
// 
//  © 2008 - "Lucas Fonzalida" <contacto@lucasfonzalida.com.ar>
//==================================================================




// -------------------- IMPLEMENTACION DE HERENCIA --------------------------


function addMethod(){
    this.prototype.inherits = inherits;
}
            
Function.prototype.addMethod = addMethod;
Function.addMethod();

function inherits(clase){
    this.prototype = new clase();
}




/**
* Imprime todos los atributos y métodos del objeto
* NOTA: Esta función es una herramienta de trabajo
*
* @version 1.0 (15/06/2008 16:36:36)
* @param   Object myObj   Objeto a analizar
* @author  Lucas Fonzalida <contacto@lucasfonzalida.com.ar>
*/
function Reflection(myObj){
    var debug = "";
    for(var i in myObj){
        debug += i + " -> " + myObj[i] + "\n";
    }
    alert(debug);
    //document.write(debug);
}


/**
* Helper para operar con tiempos (Crónometro)
*
* METODOS PUBLICOS:
* -----------------
* + get
* + get
* @aparm   int  time Unix Timestamp en milisegundos
* @version 1.0  (10/11/2008 19:54:45)
* @author  Lucas Fonzalida <contacto@lucasfonzalida.com.ar>
*/
function Timing(time){

    // Atributos
    this.time        = time;
    
    // Métodos
    this.toSeconds   = toSeconds;
    this.toMinutes   = toMinutes;
    this.toHours     = toHours;
    this.toDays      = toDays;
    
    this.getSeconds  = getSeconds;
    this.getMinutes  = getMinutes;
    this.getHours    = getHours;
    this.getDays     = getDays;

    /**
    * 
    *
    *
    *
    */
    function toString(format){
            //
            // Hacer
            //
            return "%d %h %m %s";
    }
    
    /**
    * Convierte 'time' a "total de segundos" sin fracción
    * NOTA: Siempre devuelve un entero positivo
    *
    * @access public
    * @return int           Positivo siempre
    */
    function toSeconds(){
        // Convierte a segundos
        seconds = this.time / 1000;
        // Elimina el signo
        seconds *= seconds < 0 ? -1 : 1;
        // Retorna siempre positivo
        return seconds;
    }
    
    /**
    * Convierte 'time' a "total de minutos" sin fracción
    * NOTA: Siempre devuelve un entero positivo
    *
    * @access public
    * @return int           Positivo siempre
    */
    function toMinutes(){
        // A segundos
        seconds = this.toSeconds(this.time); // Positivo
        // A minutos sin fracción
        return Math.floor(seconds / 60);
    }
    
    /**
    * Convierte 'time' a "total de horas" sin fracción
    * NOTA: Siempre devuelve un entero positivo
    *
    * @access public
    * @return int           Positivo siempre
    */
    function toHours(){
        // A segundos
        minutes = this.toMinutes(this.time); // Positivo
        // A horas sin fracción
        return Math.floor(minutes / 60);
    }

    /**
    * Convierte 'time' a "total de días" sin fracción
    * NOTA: Siempre devuelve un entero positivo
    *
    * @access public
    * @return int
    */
    function toDays(){
        // A horas
        hours = this.toHours(this.time); // Positivo
        // A días sin fracción
        return Math.floor(hours / 24);
    }
    
    
    // --------------------------------------------
  
    
    /**
    * Obtiene los segundos de 'time'
    *
    *
    * @access public
    * @return int           Positivo siempre
    */
    function getSeconds(){        
        // A segundos totales
        seconds = this.toSeconds(this.time);
        // Retorna
        return Math.floor(seconds % 60);
    }

    /**
    * Obtiene los minutos de 'time'
    *
    * @access public
    * @return int     Positivo siempre
    */
    function getMinutes(){
        // A minutos totales
        minutes = this.toMinutes(this.time);
        // A minutos excedentes
        return Math.floor(minutes % 60);
    }
    
    
    /**
    * Obtiene la hora de 'time'
    *
    * @access public
    * @return int     Positivo siempre
    */
    function getHours(){
        // A horas
        hours = this.toHours(this.time);
        // A horas excedentes
        return Math.floor(hours % 24);
    }
    
    /**
    * Obtiene los días de 'time'
    *
    * @access public
    * @param  int     msec  Milisegundos
    * @return int           Positivo siempre
    */
    function getDays(){
        // A días sin fracción
        return this.toDays(this.time);
    }
}


/**
* Busca las coordenadas X e Y de un objeto
*
* METODOS PUBLICOS:
* -----------------
* + getPosition(Object obj) : Position
* + getCursorPosition(Event evnt) : Position
*
* @version 1.0
* @author  Lucas Fonzalida <contacto@lucasfonzalida.com.ar>
*/
function PositionFinder(){

    // Métodos
	this.getPosition        = getPosition;
	this.getCursorPosition  = getCursorPosition;
	this.getMousePosition   = getMousePosition;
		
    /**
    * Retorna un objeto Position con las coordenadas del objeto
    * relativas al documento.
    * 
    * NO FUNCIONA MAS
    *
    * @access public
    * @param  Object   obj  Objeto DOM
    * @return Position
    */
    function getPosition(obj){
        // Define e inicializa variables XY
    	var curX = 0;
    	var curY = 0;
        // Mientras exista un offsetParent
        while(obj.offsetParent){
    		curX += obj.offsetLeft;
    		curY += obj.offsetTop;
    		obj   = obj.offsetParent;
    	}
    	// Crea y retorna un objeto Position
    	return new Position(curX,curY);
    }

    /**
    *   BETA 01/11/2008 18:14:24
    *
    *   http://www.quirksmode.org/js/events_properties.html
    *
    *
    */
    function getMousePosition(e){
    	var posx = 1;
    	var posy = 1;
    	if (!e) var e = window.event;
    	if (e.pageX || e.pageY) 	{
    		posx = e.pageX;
    		posy = e.pageY;
    	}
    	else if (e.clientX || e.clientY) 	{
    		posx = e.clientX + document.body.scrollLeft
    			+ document.documentElement.scrollLeft;
    		posy = e.clientY + document.body.scrollTop
    			+ document.documentElement.scrollTop;
    	}
    	// Crea y retorna un objeto Position
    	return new Position(posx,posy);
    }
    
    /**
    * Retorna la posición del cursor del momento en el que ocurrió el evento
    * pasado como parámetro.
    * Probada en IE7 y Gecko/20080829 Firefox/2.0.0.17
    * 
    *
    * @access public
    * @param  Event   evnt  Objeto Event DOM
    * @return Position
    */
    function getCursorPosition(evnt){
        // Crea y retorna un objeto Position con la posición del cursor.
        return new Position(evnt.screenX, evnt.screenY);
    }

    /**
    * CLASE INTERNA
    * Almacena un par de coordenadas X e Y
    *
    * @param int x Coordenada X
    * @param int y Coordenada Y
    */
    function Position(x,y){

        // Atributos
    	this.x = x;
    	this.y = y;

    	// Métodos
    	this.getX = getX;
    	this.getY = getY;
    	
    	/**
    	* Retorna el valor de X
    	*
    	* @access public
    	* @return int
    	*/
    	function getX(){
    	    return this.x;
    	}
    	
    	/**
    	* Retorna el valor de Y
    	*
    	* @access public
    	* @return int
    	*/
    	function getY(){
    	    return this.y;
    	}
    }
}


/**
* Emula la implementación HashMap de Java
* NOTA: Se puede mejorar
*
*
* METODOS:
* --------
* + get(Object key) : Object
* + put(Object key, Object value) : Object
* + remove(Object key) : Object
* + size() : int
* + containsKey(Object key) : boolean
* - getIndex(Object key) : int
*
*
*
*
* @version 1.0
* @author Lucas Fonzalida <contacto@lucasfonzalida.com.ar>
*/
function HashMap(){

    // Atributos
    this.data = new Array();
    
    // Metodos
    this.get          = get;
    this.put          = put;
    this.remove       = remove;
    this.size         = size;
    this.containsKey  = containsKey;
    this.getIndex     = getIndex;

          
    /**
    * Returns the value to which the specified key is mapped in this
    * identity hash map, or null if the map contains no mapping for this key. 
    *
    * @access public
    * @param  Object  key    
    * @return Object
    */ 
    function get(key){
        // Obtiene el index del key
        var i = this.getIndex(key);
        // Si el key no existe retorna null
        if(i == -1){
            return null;
        }
        // Retorna el valor para el key indicado
        return this.data[i][1];
    }  
    
    /**
    * Associates the specified value with the specified key in this map. 
    * If the map previously contained a mapping for this key, the old value is replaced. 
    * Returns: previous value associated with specified key, or null if there was no mapping for key.
    *
    * @access public
    * @param  Object  key    Objeto clave
    * @param  Object  value  Objeto valor
    * @return Object
    */    
    function put(key, value){
        // Obtiene el index del key
        var i = this.getIndex(key);
        // Si el key no existe se agrega un elemento al final
        if(i == -1){
            // Agrega un nuevo item al final del array
            this.data.push(new Array(key,value));
        }else{
            // Obtiene el objeto actual
            var obj = this.get(key);
            // Sobreescribe el key actual
            this.data[i] = new Array(key,value);
            // Retorna el valor asociado al key anterior
            return obj;
        }
        return null;
    }

    /**
    * Associates the specified value with the specified key in this map.
    * Returns: previous value associated with specified key, or null if
    * there was no mapping for key.
    *
    * @access public
    * @param  Object  key    
    * @return Object
    */    
    function remove(key){
        // Obtiene el index del key
        var i = this.getIndex(key);
        if(i == -1){
            return null;
        }
        // Obtiene el objeto actual
        var obj = this.get(key);
        // Elimina el elemento actual
        this.data.splice(i,1);
        // Retorna el valor asociado al key anterior
        return obj;
    }

    /**
    * Returns the number of key-value mappings in this map.
    *
    * @access public
    * @return int
    */    
    function size(){
        return this.data.length;
    }

    /**
    * Returns true if this map contains a mapping for the specified key.
    *
    * @access public
    * @param  Object 
    * @return boolean
    */ 
    function containsKey(key){
        // Obtiene el index del key
        var i = this.getIndex(key);
        // Comprueba el index obtenido
        if(i > -1){
            // Retorna: El key existe
            return true;
        }
        // Retorna: El key no existe
        return false;
    }

    /**
    * Retorna el index que corresponde al key especificado.
    * Si el key no existe retorna -1
    * NOTA: Este método no existe en la implementación original de Java
    *
    * @access private
    * @param  Object  key
    * @return int
    */    
    function getIndex(key){
        // Recorre el array en busca del objeto key
        for(var i = 0; i < this.data.length; i++){
            if(this.data[i][0] == key){
                return i;
            }
        }
        return -1;
    }
}


/**
* Facilita la manipulación de objetos de formulario.
* Esta clase es la base de todos los formularios de tiempo real  (RTFs)
*
* METODOS PUBLICOS:
* -----------------
* + setStringDisplay(String display_id, String val) : void
* + setIntegerDisplay(String display_id, int val): void
* + setFloatDisplay(String display_id, float val, int precision) : void
* + setCurrencyDisplay(String display_id, float val, int precision) : void
* + setObjectVisibility(String object_id, boolean visible) : void
* + setImageSrc(String image_id, String src_value) : void
* + setFieldValue(String field_id, String val) : void
*
* + getObject(String field_id) : Node
* + getObjectVisibility(String object_id) : bool
* + getFieldValue(String field_id) : Node
*
*
* @author  Lucas Fonzalida <contacto@lucasfonzalida.com.ar>
* @version 1.2 (23/11/2006 17:25)
*/
function FormObjectsManager(){

    // Métodos
    this.setStringDisplay           = setStringDisplay;
    this.setIntegerDisplay          = setIntegerDisplay;
    this.setFloatDisplay            = setFloatDisplay;
    this.setCurrencyDisplay         = setCurrencyDisplay;
    this.setObjectVisibility        = setObjectVisibility;
    this.setImageSrc                = setImageSrc;
    this.setFieldValue              = setFieldValue;
    
    this.getObject                  = getObject;
    this.getObjectVisibility        = getObjectVisibility;
    this.getFieldValue              = getFieldValue;

    //
    // Setters
    //

    /**
    * Muestra un string
    *
    * @access public
    * @param  String  display_id  Id del objeto span o div
    * @param  String  val         Cadena a mostrar
    * @return void
    */
    function setStringDisplay(display_id, val){
        this.getObject(display_id).innerHTML = val;
    }

    /**
    * Muestra un valor entero
    *
    * @access public
    * @param  String  display_id  Id del objeto span o div
    * @param  int     val         Valor entero
    * @return void
    */
    function setIntegerDisplay(display_id, val){
        this.setStringDisplay(display_id, val);
    }

    /**
    * Muestra un valor decimal, si el valor no es un numero decimal
    * se ignora la precisión y se muestra como String
    *
    * @access public
    * @param  String  display_id  Id del objeto span o div
    * @param  float   val         Valor decimal
    * @param  int     precision   Precisión decimal
    * @return void
    */
    function setFloatDisplay(display_id, val, precision){
        num = new Number(val);
        // Si el valor es numérico se lo formatea
        if(!isNaN(num)){
            val = num.toFixed(precision);
        }
        this.setStringDisplay(display_id, val);
    }

    /**
    * Muestra un valor decimal, si el valor no es un numero decimal
    * se ignora la precisión y se muestra como String
    *
    * @access public
    * @param  String   display_id  Id del objeto span o div
    * @param  numeric  val         Valor numérico (entero o decimal)
    * @param  float    precision   Precisión decimal
    * @return void
    */
    function setCurrencyDisplay(display_id, val, precision){
        num = new Number(val);
        // Si el valor es numérico se lo formatea
        if(!isNaN(num)){
            val = "$" + num.toFixed(precision).replace(".",",");
        }
        this.setStringDisplay(display_id, val);
    }
    
    /**
    * Oculta o desoculta un objeto de formulario.
    * IMPORTANTE: Esta operación, modifica el valor de la propiedad CSS 'visibility'
    * especificada en el atributo de objeto XHTML 'style='.
    * Para que funcione correctamente la desocultación de objetos (ocultos vía CSS),
    * se debe especificar 'visibility: none' en el atributo style="" del objeto XHTML
    * y NO en la clase CSS. 13/11/2008 12:57:46
    *
    * @access public
    * @param  String   object_id  Id del objeto
    * @param  boolean  visible    true | false
    * @return void
    */
    function setObjectVisibility(object_id, visible){
        // Se obtiene una referencia al objeto
        obj = this.getObject(object_id);
        // Oculta o desoculta el objeto
        if(visible){
            obj.style.display = "";
        }else{
            obj.style.display = "none";
        }
    }
    
    /**
    * Cambia el atributo src de un objeto IMG
    * NOTA: Es recomendable realizar una precarga de
    * las imágenes antes de ejecutar esta operación.
    *
    * @access public
    * @param  String   image_id   Id del objeto IMG
    * @param  String   src_value  Valor del atributo src
    * @return void
    */
    function setImageSrc(image_id, src_value){
        // Se obtiene una referencia al objeto
        obj = this.getObject(image_id);
        // Si el ojeto es del tipo IMG
        if(obj.nodeName == "IMG"){
            obj.src = src_value;
        }
    }
    
    /**
    * Modifica el valor del campo especificado
    *
    * @access public
    * @param  String  field_id   Id del objeto
    * @param  String  val        String con el nuevo valor
    * @return void
    */
    function setFieldValue(field_id, val){
        this.getObject(field_id).value = val;
    }
    
    //
    // Getters
    //
    
    
    /**
    * Retorna una referencia al objeto especificado o null si el
    * objeto no existe.
    *
    * @param  string  field_id String con el id del objeto
    * @return Node
    */
    function getObject(field_id){
        return document.getElementById(field_id);
    }

    /**
    * Obtiene el estado de visibilidad de un objeto de formulario
    *
    * @access  public
    * @param   String   object_id  Id del objeto
    * @return  bool
    *
    * @version 1.0 (23/11/2006 17:31)
    * @since   1.2
    */
    function getObjectVisibility(object_id){
        // Se obtiene una referencia al objeto
        obj = this.getObject(object_id);
        // Verifica el estado actual
        if(obj.style.display != "none"){
            // Retorna 'visible'
            return true;
        }
        // Retorna 'invisible'
        return false;
    }

    /**
    * Retorna el valor actual para el campo especificado. 
    *
    *
    * @param  string  field_id  String con el id de campo
    * @return String
    */
    function getFieldValue(field_id){
        return this.getObject(field_id).value;
    }
}




/**
* WindowsManager
* Facilita la manipulación de ventanas
*
*
* METODOS PUBLICOS:
* -----------------
* + openWindow(String url, String n, WindowFeatures featObj) : void
* + openModalWindow(String url, String n, WindowFeatures featObj) : void
* + openModelessWindow(String url,String n, WindowFeatures featObj) : void
* + closeWindow(String n) : void
*
*
*
*
* @author  Lucas Fonzalida <contacto@lucasfonzalida.com.ar>
* @version 1.1 (16/03/2008 03:12:06)
*/
function WindowsManager(){

    // Propiedades
    this.windows                       = Array();

    // Métodos
    this.pfinder                       = new PositionFinder();

    this.openWindow                    = openWindow;
    this.openModalWindow               = openModalWindow;
    this.openModelessWindow            = openModelessWindow;
    this.closeWindow                   = closeWindow;
    this.registerWindow                = registerWindow;
    this.unregisterWindow              = unregisterWindow;
    this.getRegisteredWindow           = getRegisteredWindow;
    this.createFeatures                = createFeatures;
    this.createModalFeatures           = createModalFeatures;
    this.closeAllWindows               = closeAllWindows;
    this.isClosed                      = isClosed;

    /**
    * Para abrir una nueva ventana común
    *
    * @access   public
    * @version  1.1             18/12/2008 14:11:09
    * @param    String          url      Url
    * @param    String          n        Nombre
    * @param    WindowFeatures  featObj  Objeto WindowFeatures
    * @return   void
    */
    function openWindow(url,n,featObj){
        // Obtiene la ventana registrada utilizando el nombre
        var openedWindow = this.getRegisteredWindow(n);
        // Si la ventana ya está instanciada
        if(openedWindow != null){
            // Obtiene la URI de la ventana instanciada      
            uri = openedWindow.document.location.href;
            // Verifica si la URL solicitada está contenida en la URI de la ventana instanciada
            if(uri.indexOf(url) > -1){
                // Focaliza la ventana
                openedWindow.focus();
            }else{
                // Carga la URL en la ventana instanciada
                openedWindow.document.location.href = url;
            }
        }else{ // Instancia una nueva ventana
            // Crea el string con los features para ventanas de IE6+ & Gecko
            var sFeat = this.createFeatures(featObj);
            // Abre una nueva ventana y conserva la referencia
            var openedWindow = window.open(url,n,sFeat);
            // Almacena una referencia a la nueva ventana creada
            this.registerWindow(openedWindow);
        }
        // Focaliza la ventana
        openedWindow.focus();
    }
    
    /**
    * Abre una nueva ventana modal de IE6+ o Gecko (según el contexto).
    *
    * @access public
    * @param  String          url      Url
    * @param  String          n        Nombre de la ventana (no se usa)
    * @param  WindowFeatures  featObj  Objeto WindowFeatures
    * @return void
    */
    function openModalWindow(url,n,featObj){
        // Crea el string con los features para ventanas modal según el navegador actual
        var sFeat = this.createModalFeatures(featObj);
        // Debug
        // alert(sFeat);
        // IE6+ 
        if(window.showModalDialog){
            // Abre una nueva ventana modal al modo IE6+
            window.showModalDialog(url,self,sFeat);
        }else{
            // Abre una nueva ventana modal al modo Gecko
            newWindow = window.open(url,n,sFeat);
            // Crea una variable similar a la de IE conteniendo una referencia al parent
            newWindow.dialogArguments = self;
        }
    }

    /**
    * Abre una nueva ventana Modeless de IE6+ o Gecko (según el contexto).
    *
    * @access public
    * @param  String          url      Url
    * @param  String          n        Nombre de la ventana
    * @param  WindowFeatures  featObj  Objeto WindowFeatures
    * @return void
    */
    function openModelessWindow(url,n,feat){
        // no implementado
    }  

    /**
    * Crea un string con el set de features que requieren las ventanas modal 
    * de IE6+ y Gecko.
    *
    *
    * @access private
    * @param  WindowFeatures  featObj  Objeto WindowFeatures con los parámetros
    *                                  para crear el string.
    * @return String
    * @version 1.1 (16/03/2008 03:11:59)
    */
    function createModalFeatures(featObj){
        // Define sFeat
        var sFeat;
        // Si es IE6+ o compatible
        if(window.showModalDialog){
            // Crea un string con los features que aceptan los modal dialogs de IE6+
            sFeat = "dialogLeft:" + featObj.posX + ";dialogTop:" + featObj.posY + 
                    ";dialogHeight:" + featObj.height + "px;dialogWidth:" + featObj.width + 
                    "px;center:" + featObj.center + ";edge:" + featObj.edge + ";scroll:" + featObj.scrollbars +
                    ";status:" + featObj.status + ";help:" + featObj.help + ";resizable:" + featObj.resizable;
        }else{
            // Crea un string de Features común a IE6+ & Gecko
            sFeat = this.createFeatures(featObj);
            // Se le adiciona el indicador de modal para Gecko
            sFeat += ",modal=1";
        }
        // Retorna
        return sFeat;
    }

    /**
    * Crea un string con el set de features que requieren las ventanas
    * de IE6+ y Gecko.
    *
    * @access private
    * @param  WindowFeatures  featObj  Objeto WindowFeatures con los parámetros
    *                                  para crear el string.
    *
    * @access private
    * @return String 
    */
    function createFeatures(featObj){
        // Features para ventanas al modo IE+ & Gecko
        return "left=" + featObj.posX + ",top=" + featObj.posY +
                ",height=" + featObj.height + "px,width=" + featObj.width +
                "px,menubar=" + featObj.menubar + ",scrollbars=" + featObj.scrollbars +
                ",status=" + featObj.status + ",resizable=" + featObj.resizable +
                ",titlebar=" + featObj.titlebar;
    }
    
    /**
    * Para cerrar una ventana
    *
    * @access public
    * @param  String  n    Nombre
    * @return void
    */
    function closeWindow(n){

    }    

    /**
    * Almacena una referencia a una ventana satélite o hija
    *
    * @access public
    * @param  Window  childW  Objeto window
    * @return void
    */
    function registerWindow(win){
        // Almacena una referencia al objeto Window
        return this.windows.push(win);
    }
    
    /**
    * Elimina la referencia de la ventana satélite indicada
    *
    * @access public
    * @param  Window  childW  Objeto window
    * @return void
    */
    function unregisterWindow(win){

    }    

    /**
    * Retorna una referencia a la ventana indicada o null si la ventana
    * no esta registrada o fue cerrada.
    *
    * @access public
    * @param  String   n  Nombre de la ventana
    * @return Window
    */
    function getRegisteredWindow(n){
        // Recorre todas las ventanas
        for(i=0; i < this.windows.length; i++){
            // Verifica si la ventana esta cerrada
            if(this.windows[i].closed){
                // Elimina la referencia
                this.windows.splice(i,1);
            }else{
                // Verifica si coincide el nombre de la ventana
                if(this.windows[i].name == n){
                    // Retorna
                    return this.windows[i];
                }
            }
        }
        // Retorna
        return null;
    }

    /**
    * Cierra todas las ventanas registradas
    *
    * @access public
    * @return void
    */
    function closeAllWindows(){    
        // Recorre todas las ventana satélites
        for(i=0; i < this.windows.length; i++){
            // Verifica si la ventana esta cerrada
            if(!this.isClosed(this.windows[i])){
                // Cierra la ventana
                this.windows[i].close();
            }
        }
    }
    
    /**
    * Verifica si la ventana está cerrada
    * Utiliza una técnica extraida de experts-exchange.com
    *
    *
    * @see    http://www.experts-exchange.com/Web/Web_Languages/JavaScript/Q_20926025.html
    * @access public
    * @param  Window  win Ventana
    * @return boolean
    */
    function isClosed(win){
        // Verifica si la ventana esta fuera de cuadro
        // Técnica extraida de 
        if(win.screenTop > 9000){
            return true;
        }
        return false;
    }
}

/**
* WindowFeatures
* Objeto contenedor de datos de configuración (features) para ventanas
* Proporciona una forma universal para configurar las propiedades
* de las ventanas popup y modal
*
* @param  String  params  Parámetros de inicialización de las propiedades
* @access public
* @version 1.0
* @author Lucas Fonzalida <sistemas@maxmedia.com.ar>
*/
function WindowFeatures(str){    
    
    /**
    * Se inicializan atributos utilizando el string
    * pasado como parámetro al instanciar el objeto.
    * Si no se especifica algún atributo, se inicializa utilizando un
    * valor por default.
    */
    this.posX       = finder("posX", str) ? finder("posX", str) : 0;               // IE6+ & Gecko 1.7+
    this.posY       = finder("posY", str) ? finder("posY", str) : 0;               // IE6+ & Gecko 1.7+
    this.center     = finder("center", str) ? finder("center", str) : 0;           // IE6+
    this.width      = finder("width", str) ? finder("width", str) : 0;             // IE6+ & Gecko 1.7+
    this.height     = finder("height", str) ? finder("height", str) : 100;         // IE6+ & Gecko 1.7+
    this.resizable  = finder("resizable", str) ? finder("resizable", str) : 0;     // IE6+ & Gecko 1.7+
    this.scrollbars = finder("scrollbars", str) ? finder("scrollbars", str) : 0;   // IE6+ & Gecko 1.7+
    this.status     = finder("status", str) ? finder("status", str) : 0;           // IE6+ & Gecko 1.7+
    this.titlebar   = finder("titlebar", str) ? finder("titlebar", str) : 0;       // IE6+ & Gecko 1.7+
    this.menubar    = finder("menubar", str) ? finder("menubar", str) : 0;         // IE6+ & Gecko 1.7+
    this.edge       = finder("edge", str) ? finder("edge", str) : "raised";        // IE6+
    this.help       = finder("help", str) ? finder("help", str) : 0;               // IE6+ & Gecko 1.7+
    
    /**
    *
    *
    *
    *
    *
    */
    function finder(p, str){
        // Crea una nueva expresion regular
        var re = new RegExp("(\\,|^)" + p + "=(\\w+)(\\,|$)");
        // Si hay coincidencias
        if(str.search(re) > -1){
            // Obtiene el valor
            var result = str.match(re);
            // Debug
            // alert(p + "=" + result[2]);
            // Retorna
            return result[2];
        }else{
            return false;
        }
    }
}


/**
* Implementación de EventTarget (Abstracta)
* Las clases concretas deben extender esta clase abstracta con: <ClassName>.inherits(DOMEventTarget)
*
*
*
* @version v1.1 04/10/2011 11:34:30
*/
function DOMEventTarget(){
    
    //
    // Atributos
    //
    
    /**
    * Holder de EventListeners
    * Si la misma clase derivada se va a instanciar varias veces, este member DEBE redefinirse
    * en dicha clase, porque sino todas las instancias de esa clase concreta almacenarán
    * en el mismo lugar (un singleton) los listeners y puede obtenerse un efecto no deseado.
    * 
    * Para evitar esto, redeclarar e inicializar este atributo en la clase concreta hará que
    * este atributo funcione como un almacén local (perteneciente sólo a esa instancia).
    *
    * @access protected
    */
    this.listeners           = new Array();  // Se debe redefinir en clase derivada

    //
    // Métodos
    //
    this.addEventListener    = addEventListener;
    this.removeEventListener = removeEventListener;
    this.dispatchEvent       = dispatchEvent;
    
    /**
    * Implementación de EventTarget.addEventListener()
    * http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
    *
    * @access public
    * @param  String         type
    * @param  EventListener  listener   http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
    * @param  boolean        useCapture
    * @return void
    */
    function addEventListener(type, listener, useCapture){
        if(listener.handleEvent){
            // Agrega una referencia al almacen de EventListeners
            this.listeners.push(listener);
        }else{
            //throw new Exception();
            alert("EventTarget.addEventListener(): El objeto que intenta registrar no es un EventListener o no implementa el método handleEvent(). El objeto es: " + listener);
        }
    }
    
    /**
    * Implementación de EventTarget.removeEventListener()
    * http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
    *
    * @access public
    * @param  String         type
    * @param  EventListener  listener   http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
    * @param  boolean        useCapture
    * @return void
    */
    function removeEventListener(type, listener, useCapture){
            /* NO IMPLEMENTADO (NO LO NECESITO TODAVIA) */
    }

    /**
    * Implementación de EventTarget.dispatchEvent()
    * http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
    *
    *
    * @access public
    * @param  Event   evt   Objeto Event
    * @return bool
    */    
    function dispatchEvent(evt){
        // Por cada EventListener almacenado
        for(i=0; i < this.listeners.length; i++){
            // Ejecuta EventListener.handleEvent(evt)        
            this.listeners[i].handleEvent(evt);
        }
    }
}


// -------------------- IMPLEMENTACIONES GENERICAS DE JSRTF FormObjectWrapper --------------------------

/**
* ClickeableTarget (JSRTF FormObjectWrapper)
* Clase que encapsula todas las operaciones asociadas a un objeto Clickeable
*
*  De FormObjectWrapper:
*      + init() : void
*      + destroy() : void
*
*  De EventTarget:
*      + addEventListener(String type,EventListener listener,boolean useCapture) : void
*      + removeEventListener(String type,EventListener listener,boolean useCapture) : void
*      + dispatchEvent(Event evt) : boolean
*
*
* @version     v2.0  03/10/2011 11:18:41
* @implements  FormObjectWrapper
* @implements  EventTarget
* @author      "Lucas Fonzalida" <contacto@lucasfonzalida.com.ar>
*/
function ClickeableTarget(elementId){
    //
    // Variables objeto globales 
    //
    var thisInstance = this; // global this JSRTF

    //
    // Declara e inicializa atributos
    //
    // this.elementId = elementId;
    this.fom         = new FormObjectsManager();
    this.listeners   = new Array();  // Hace local DOMEventTarget.listeners

    //
    // Declaraciones de métodos
    //
    // De JSRTF
    this.init                          = init;

    /** 
    * JSRTF Inicializa el objeto
    *
    * @access public
    * @return void
    */
    function init(){
        // Inicializa o crea el objeto
        this.obj = this.fom.getObject(elementId);
        // Registra handler estático DOM0
        this.obj.onclick = onClick;
    } this.init();
   
    // 
    // Métodos estáticos (Para los eventos DOM0)
    //

    /**
    * Static EventHandler (DOM0)
    * 
    * @version 1.0
    * @static
    * @access  private
    * @param   Event    evt   Un evento 
    * @return  void
    */
    function onClick(evt){
        // Si al evento lo recibe mediante métodos DOM0
        evt = (evt || window.event);
        // Si el atributo 'target' no esta definido
        if(!evt.target){
            // Lo inicializa para compatibilizar con IE 7 y 8
            evt.target = thisInstance.obj;
        }
        // Dispara evento
        thisInstance.dispatchEvent(evt);
    }

} ClickeableTarget.inherits(DOMEventTarget);



// ----- Experimental ------- 


/**
* JSRTF ActiveObject
* Clase que encapsula todas las operaciones asociadas a un elemento DXHTML
*
*  De ActiveObject:
*      + init() : void
*      + setId(String newId) : void
*      + setSrc(String newSrc) : void
*      + setClass(String newClass) : void
*
*  De EventTarget:
*      + addEventListener(String type,EventListener listener,boolean useCapture) : void
*      + removeEventListener(String type,EventListener listener,boolean useCapture) : void
*      + dispatchEvent(Event evt) : boolean
*
*
* @param       String  objType
* @version     v0.1    05/10/2011 09:15:25
* @implements  EventTarget
* @author      "Lucas Fonzalida" <contacto@lucasfonzalida.com.ar>
*/
function ActiveObject(objType){
    //
    // Variables objeto globales 
    //
    var thisInstance = this; // global this JSRTF

    //
    // Atributos
    //
    this.listeners = new Array();  // Hace local DOMEventTarget.listeners
    this.obj       = null;         // Se debe inicializar en clase concreta
    this.display   = null;         // Almacena el estado original de visibilidad 

    //
    // Métodos
    //
    this.init          = init;
    this.appendChild   = appendChild;
    this.toggleDisplay = toggleDisplay;
    this.setId         = setId;
    this.setSrc        = setSrc;
    this.setClass      = setClass;
    this.setDisplay    = setDisplay;
    this.setText       = setText;
    this.getDisplay    = getDisplay;
    this.getObject     = getObject;

    /** 
    * Constructor
    *
    * @access public
    * @return void
    */
    function init(){
        this.obj = document.createElement(objType);
        // Asocia eventos
        this.obj.onclick = onClick;
    } this.init();

    //
    // Setters
    //

    function setId(newId){
        this.obj.setAttribute("id",newId);
    }

    function setSrc(newSrc){
        // Si es una imágen
        if(this.obj.nodeName == "IMG"){
            this.obj.src = newSrc;
        }
    }

    function setClass(newClass){
        this.obj.setAttribute("className",newClass);  // IE7+
        this.obj.setAttribute("class",newClass);      // Otros
    }
    
    function setDisplay(newValue){
        this.obj.style.display = newValue;
    }

    /**
    * Cambia de Visible a Invisible y viceversa
    * NOTA: Se debe indicar el estado original
    *       Ver: CSS display
    *
    * @access  public
    * @param   String  original
    * @return  void
    */
    function toggleDisplay(original){
        // Si el objeto no está invisible
        if(this.getDisplay() != "none"){
            // Lo hace invisible
            this.setDisplay("none");
        }else{
            // Lo hereda las caracteristicas del padre
            this.setDisplay(original);
        }
    }
    
    /**
    * Setea el texto entre los tags de este ActiveObject
    * NOTA: Puede ser HTML
    * 
    * @access public
    * @param  String  newText  
    * @return void     
    */
    function setText(newText){
        this.obj.innerHTML = newText;
    }
    
    /**
    * Agrega a este ActiveObject un ActiveObject hijo
    * 
    * @access public
    * @param  ActiveObject  obj
    * @return void     
    */
    function appendChild(obj){
        this.obj.appendChild(obj.getObject());
    }
    
    
    //
    // Getters
    //
    
    function getDisplay(){
        return this.obj.style.display;
    }
    
    function getObject(){
        return this.obj;
    }

    //
    // Métodos estáticos
    //
    
    /**
    * Static EventHandler (DOM0)
    * 
    * @version 1.0
    * @static
    * @access  private
    * @param   Event    evt   Un evento 
    * @return  void
    */
    function onClick(evt){
        // Si al evento lo recibe mediante métodos DOM0
        evt = (evt || window.event);
        // Si el atributo 'target' no esta definido
        if(!evt.target){
            // Lo inicializa para compatibilizar con IE 7 y 8
            evt.target = thisInstance.obj;
        }
        // Dispara evento
        thisInstance.dispatchEvent(evt);
    }

}ActiveObject.inherits(DOMEventTarget);
