var TOOLS_UNDEFINED_VALUE;
var TOOLS_HTML_MAIN_FORM_ID     = "Form1";
var TOOLS_COPY_SUFFIX           = "__COPY";
var TOOLS_NODE_ELEMENT_NODE     = 1;
var TOOLS_CONTROL_ID_SEPARATOR  = ':';
var TOOLS_POSITION_SUFFIX       = 0;
var TOOLS_POSITION_PREFIX       = 1;


var Tools_IsNS4    = (document.layers) ? 1 : 0;
var Tools_IsIE4    = (document.all) ? 1 : 0;
var Tools_IsW3C    = (document.getElementById && !document.all) ? 1 : 0;
var Tools_IsNS8    = (navigator.userAgent.toLowerCase().indexOf('netscape/8') != -1);
var Tools_IsSafari = (navigator.userAgent.toLowerCase().indexOf('safari') != -1);
var Tools_IsIE     = (navigator.userAgent.toLowerCase().indexOf('msie') != -1);

/** X mouse coordinate */
var Tools_giMouseX = 0;

/** Y mouse coordinate */
var Tools_giMouseY = 0;

/** Mouse button state */
var Tools_gxMouseB = 0;

/** Key pressed */
var Tools_giKeyCode = 0;

/** Currente active input element (refreshed when a key is pressed) */
var Tools_goActiveField = null;

// Register mouse move event
Event_AddAction(EVENT_MOUSE_MOVE, Tools_GetMouseXY);
Event_AddAction(EVENT_KEY_PRESS, Tools_GetKeyPress);

function Tools_ContainsKey(oObject, oKey)
{
    // Done!
    return oKey in oObject;
};

/**
 * Returns true if the element has the class _sClassName
 * @param _oElement HTML element
 * @param _sClassName Class name to check
 * @return Returns true if _sClassName is associated to _oElement
 */
function Tools_HasClass(_oElement, _sClassName)
{
    // Default return value
    var bRet = false;
    
    // Valid element ?
    if(_oElement != null)
    {
        if((_oElement.className)
        && (_oElement.className != null))
        {
            // split classes
            var asClassList = _oElement.className.split(' ');

            // Found in list?             
            bRet = (Tools_IndexOf(asClassList, _sClassName) >= 0)
        }
    }
    
    // Returns true if the class is set.
    return bRet;
}

/**
 * Returns true if the class has been added to the element, else returns false
 * @param _oElement HTML element
 * @param _sClassName Name of the class to add
 * @return true if the class has been added (or already added), else returns false
 */
function Tools_AddClass(_oElement, _sClassName)
{
    // Default return value
    var bRet = false;
    
    // Valid element ?
    if(_oElement != null)
    {
        // The class is not already assigned ?
        if(!Tools_HasClass(_oElement, _sClassName))
        {
            // Adds the class
            _oElement.className += " " + _sClassName;
        }

        // operation succeed
        bRet = true;
    }
    
    // Returns true if the class has been added
    return bRet;
}

/**
 * Returns true if the class has been removed (or already removed), else returns false
 * @param _oElement HTML element
 * @param _sClassName Name of the class to remove
 * @return true if the class has been removed (or already removed), else returns false
 */
function Tools_RemoveClass(_oElement, _sClassName)
{
    // Default return value
    var bRet = false;
    
    // Valid element ?
    if(_oElement != null)
    {
        // The class is assigned ?
        if(Tools_HasClass(_oElement, _sClassName))
        {
            // Gets the class list
            var asClassList = _oElement.className.split(' ');
            
            // Valid ?
            if((asClassList != null)
            && (asClassList.length > 0))
            {
                // Gets the position of the class
                var iPos = Tools_IndexOf(asClassList, _sClassName);
                
                // Valid ?
                if(iPos >= 0)
                {
                    var sClassName = "";
                    for(var iIdx = 0; iIdx < asClassList.length; iIdx++)
                    {
                        // Pos found ?
                        if(iIdx != iPos)
                        {
                            sClassName += asClassList[iIdx] + " ";
                        }
                    }
                    
                    // Sets the new class list
                    _oElement.className = sClassName;
                }
            }
        }

        // operation succeed
        bRet = true;
    }
    
    // Returns true if the class has been added
    return bRet;
}

/**
 * Replace a node with another one
 */
function Tools_ReplaceNode(_oParent, _oNewNode, _oOldNode)
{
    // Netscape 8.x ?
    if(Tools_IsNS8)
    {
        var oParent      = _oParent;
        var oNextSibling = _oOldNode.nextSibling;
        
        // Remove the current page node
        oParent.removeChild(_oOldNode);
        
        // The old node has a sibling ?
        if(oNextSibling != null)
        {
            // We can insert before it
            oParent.insertBefore(_oNewNode, oNextSibling);
        }
        else
        {
            // insert at the last position
            oParent.appendChild(_oNewNode);
        }
    }
    else
    {
        _oParent.replaceChild(_oNewNode, _oOldNode);
    }
}

function Tools_AppendID(_oNode, _sAppend, _ePosition)
{
    // Position not defined ?
    if(_ePosition == TOOLS_UNDEFINED_VALUE)
    {
        _ePosition = TOOLS_POSITION_SUFFIX;
    }
    
    // Valid node ?
    if(_oNode != null)
    {
        // Loop on the child nodes
        for(var i = 0; i<_oNode.childNodes.length; i++)
        {
            // Gets node
            var oNode = _oNode.childNodes[i];
            
            // Element ?
            if((oNode != null)
            && (oNode.nodeType == TOOLS_NODE_ELEMENT_NODE))
            {
                Tools_AppendID(oNode, _sAppend, _ePosition);
            }
        }

        // Element ?
        if(_oNode.nodeType == TOOLS_NODE_ELEMENT_NODE)
        {
            // Gets ID
            if(_oNode.getAttribute)
            {
                var sID = _oNode.getAttribute('id');
                
                // Valid ?
                if((sID)
                && (sID != null))
                {
                    // Prefix ?
                    if(_ePosition == TOOLS_POSITION_PREFIX)
                    {
                        // Yes
                        sID = _sAppend + sID;
                    }
                    else
                    {
                        // No, suffix it
                        sID = sID + _sAppend;
                    }
                   
                    // Appends suffix on each element ID
                    _oNode.setAttribute('id', sID);
                }
            }
        }
    }
}


function Tools_Copy(_oNode)
{
    // Default return value
    var oRet = _oNode;
    
    // Valid node ?
    if(_oNode != null)
    {
        // Clone node
        oRet = _oNode.cloneNode(true);

        // Updates IDs
        Tools_AppendID(oRet, TOOLS_COPY_SUFFIX, TOOLS_POSITION_SUFFIX);
    }
    
    
    // Returns copy
    return oRet;
}

function Tools_IsCopy(_oElement)
{
    // Default return value
    var bRet = false;
    
    // Valid element ?
    if(_oElement != null)
    {
        // Gets ID
        var sID = _oElement.id;
        
        // Valid ?
        if((sID)
        && (sID != null))
        {
            // Does it contains a COPY suffix ?
            var iIdx = sID.indexOf(TOOLS_COPY_SUFFIX);
            if((iIdx >= 0)
            && (sID.length - TOOLS_COPY_SUFFIX.length == iIdx))
            {
                // This is a copy
                bRet = true
            }
        }
    }
    
    // Returns the copy status
    return bRet;
}

function Tools_RemoveCopySuffix(_sID)
{
    // Default return value is the same as the input
    var sRet = _sID;
    
    // Valid ID ?
    if(_sID)
    {
        // Is there a Copy suffix ?
        iSuffixIdx = _sID.indexOf(TOOLS_COPY_SUFFIX);
        
        // Valid ?
        if((iSuffixIdx >=0)
        && (iSuffixIdx + TOOLS_COPY_SUFFIX.length == _sID.length))
        {
            // Remove the copy suffix
            sRet = _sID.substr(0, iSuffixIdx);            
        }
    }
    
    // Returns the new ID
    return sRet;
}

function Tools_ContainsValue(oObject, oValue)
{
    var bReturn = false;

    for(var sKey in oObject)
    {
        if(oObject[sKey] == oValue)
        {
            // Found
            bReturn = true;
            break;                
        }
    }

    // Done!
    return bReturn;
};

function Tools_IndexOf(oArray, oValue)
{
    var s32Return = -1;

    for(var i = 0; i < oArray.length; i++)
    {
        // Found?
        if(oArray[i] == oValue)
        {
            // Updates result
            s32Return = i;
            break;
        }        
    }

    // Done!
    return s32Return;    
}

// Compute width and height of the screen content
/**
 * Returns the height of the window
 */
function Tools_GetHeight()
{
  // Default return value
  var iRet = 0;
  
  // Non-IE ?
  if(typeof( window.innerHeight ) == 'number')
  {
    iRet = window.innerHeight;
  }
  // IE 6+ in 'standards compliant mode' ?
  else if((document.documentElement)
       && (document.documentElement.clientHeight))
  {
    iRet = document.documentElement.clientHeight;
  }
  // IE 4 compatible ?
  else if((document.body)
       && (document.body.clientHeight))
  {
    iRet = document.body.clientHeight;
  }
  
  // Returns height
  return iRet;
}

/**
 * Returns the width of the window
 */
function Tools_GetWidth()
{
  // Default return value
  var iRet = 0;
  
  // Non-IE ?
  if(typeof( window.innerWidth ) == 'number')
  {
    iRet = window.innerWidth;
  }
  // IE 6+ in 'standards compliant mode' ?
  else if((document.documentElement)
       && (document.documentElement.clientWidth))
  {
    iRet = document.documentElement.clientWidth;
  }
  // IE 4 compatible ?
  else if((document.body)
       && (document.body.clientWidth))
  {
    iRet = document.body.clientWidth;
  }
  
  // Returns height
  return iRet;
}

/**
 * Returns dimensions of an element
 * @param _oElement DOM element
 * @return An hash table of 4 values (top, left, width, height) or null
 */
function Tools_GetDimensions(_oElement)
{
    // Default return value
    var oRet = null;
    
    // Valid element ?
    if(_oElement != null)
    {
        var oTempElement = _oElement;
    	var iLeft   = 0;
    	var iTop    = 0;
    	var iWidth  = 0;
    	var iHeight = 0;
    	
    	// Loop on the element parent hierarchy and add all the Top and Left
    	// offset
    	while(oTempElement.offsetParent)
    	{
    	    iLeft        += oTempElement.offsetLeft;
    		iTop         += oTempElement.offsetTop;
    		oTempElement  = oTempElement.offsetParent;
    	}
    
    	iLeft += oTempElement.offsetLeft;
    	iTop  += oTempElement.offsetTop;
    	
    	// Gets width and height
        iWidth  = parseInt(_oElement.offsetWidth);
        iHeight = parseInt(_oElement.offsetHeight);
    
        // Stores dimension in a hash
        oRet = {iLeft:iLeft, iTop:iTop, iWidth:iWidth, iHeight:iHeight};
    }
    
    // returns the dimesions
    return oRet;
}

/** Returns true if the mouse coordinates is inside the region coordinates */
function Tools_IsMouseInRegion(_oRegion)
{
    // Default return value
    var bRet = false;
    
    // Valid region ?
    if((_oRegion != null)
    && (Tools_giMouseX > _oRegion.iLeft)
    && (Tools_giMouseX < _oRegion.iLeft + _oRegion.iWidth)
    && (Tools_giMouseY > _oRegion.iTop)
    && (Tools_giMouseY < _oRegion.iTop + _oRegion.iHeight))
    {
        bRet = true;
    }
    
    // Returns the region detection status
    return bRet;
}

function Tools_GetScrollTop()
{
    // Default return value
    var iRet = 0;
    
    if(typeof(window.pageYOffset) == 'number' )
    {
        //Netscape compliant
        iRet = window.pageYOffset;
    }
    else if(document.body.scrollTop)
    {
        //DOM compliant
        iRet = document.body.scrollTop;
    }
    else if(document.documentElement.scrollTop)
    {
        //IE6 standards compliant mode
        iRet = document.documentElement.scrollTop;
    }

    // Returns top scroll
    return iRet;
}

function Tools_GetScrollLeft()
{
    // Default return value
    var iRet = 0;
    
    if(typeof(window.pageXOffset) == 'number' )
    {
        //Netscape compliant
        iRet = window.pageXOffset;
    }
    else if(document.body.scrollLeft)
    {
        //DOM compliant
        iRet = document.body.scrollLeft;
    }
    else if(document.documentElement.scrollLeft)
    {
        //IE6 standards compliant mode
        iRet = document.documentElement.scrollLeft;
    }

    // Returns left scroll
    return iRet;
}

/**
 * TODO : update this method with the Matrix code style.
 */
function Tools_GetCalculatedProperty(_sID, _sProperty)
{
    // Default return value
    var sRet = "";
    var oElement = null;

    // ***** W3C Compatible DOM (NN6, Mozilla 16, etc.) *****
    if(Tools_IsW3C)
    {
        oElement = document.getElementById(_sID);
        
        // Use the default function to compute style
		
		// Visibility Property ?
        if(_sProperty == "visibility")
        {
            sRet = oElement.style.visibility;
            
            // Empty value ?
            if(sRet == "")
            {
                sRet = "inherit";
            }
        }
        // Clip property ?
        else if(_sProperty == "clip")
        {
            sRet = oElement.style.clip;
            
            // Empty value ?
            if(sRet = "")
            {
                sRet =  "rect(0px ";
                sRet += Tools_GetCalculatedProperty(_sID, "width")  + " ";
                sRet += Tools_GetCalculatedProperty(_sID, "height") + " ";
                sRet += "0px)"                
            }
        }
        // Z-Index ?
        else if(_sProperty == "zIndex")
        {
            sRet = oElement.style.zIndex;
            
            // Empty ?
            if(sRet == "")
            {
                sRet = "inherit";
            }
        }
        else
        {
            sRet = document.defaultView.getComputedStyle(oElement, "").getPropertyValue(_sProperty);
            
            // empty result ?
            if(sRet == "")
            {
                sRet = "unknown";
            }
        }
    }
    // ***** Netscape Navigator 4+ DOM *****
    else if(Tools_IsNS4)
    {
        oElement = document.layers[objName];
        
        // Visibility ?
        if(_sProperty == "visibility")
        {
            sRet = oElement.visibility;
            
            // Hide => Hidden
            // Show => Visible / inherit
            if(sRet == "hide")
            {
                sRet = "hidden";
            }
            else if(sRet == "show")
            {
                sRet = "inherit";
            }
        }
        // Clip ?
        else if(_sProperty == "clip")
        {
    	    sRet =  "rect(" + oElement.clip.top + "px ";
    	    sRet += oElement.clip.right         + "px ";
    	    sRet += oElement.clip.bottom        + "px ";
    	    sRet += oElement.clip.left          + "px)";
        }
        // Width or height ?
        else if((_sProperty == "width")
             || (_sProperty == "height"))
        {
            sRet = eval("oElement.clip." + _sProperty) + "px";
        }
        else
        {
            // Top ?
            if(_sProperty == "top")
            {
                _sProperty = "pageY";
            }
            // Left ?
            else if(_sProperty == "left")
            {
                _sProperty = "pageX";
            }
            
            // Compute the property value
            sRet = eval("oElement." + _sProperty);
            
            // Not zIndex ?
            if(_sProperty != "zIndex")
            {
                // Adds unit
                sRet += "px";
            }
        }
    }
    // ***** Internet Explorer 4+ DOM *****
    else if(Tools_IsIE4)
    {
        // Width ?
        if(_sProperty == "width")
        {
            sRet = eval(_sID + ".offsetWidth") + "px";
        }
        // Height ?
        else if(_sProperty == "height")
        {
            sRet = eval(_sID + ".offsetHeight") + "px";
        }
        // Clip ?
        else if(_sProperty == "clip")
        {
            sRet = eval(_sID + ".style.clip");
            
            // Empty result ?
            if(sRet == "")
            {
                sRet += "rect(0px ";
                sRet += Tools_GetCalculatedProperty(_sID, "width") + " ";
                sRet += Tools_GetCalculatedProperty(_sID, "height") + " ";
                sRet += "0px)";
            }
        }
        // Top ?
        else if(_sProperty == "top")
        {
            sRet = eval(_sID + ".offsetTop") + "px";
        }
        // Left ?
        else if(_sProperty == "left")
        {
            sRet = eval(_sID + ".offsetLeft") + "px";
        }
        // Else, use 'currentStyle'
        else
        {
            sRet = eval(_sID + ".currentStyle." + _sProperty);
        }
    }

    // returns the computed style
	return sRet;
}

function Tools_GetStyleSize(_sID, _sProperty)
{
    // Default return value
    var iRet = 0;
    
    if(_sID != null)
    {
        iRet = Tools_GetCalculatedProperty(_sID, _sProperty);
        iRet = iRet.substring(0, iRet.length - 2);
    }
    
    // Return size
    return iRet;
}

function Tools_ResizeCover(_oNode)
{
    // Valid ?
    if(_oNode != null)
    {
        _oNode.style.width   = Tools_GetStyleSize(TOOLS_HTML_MAIN_FORM_ID, "width");
        _oNode.style.height  = Tools_GetStyleSize(TOOLS_HTML_MAIN_FORM_ID, "height");
    }
}

function Tools_CenterPopup(_oNode)
{
    // Valid ?
    if(_oNode != null)
    {
        var sID = _oNode.getAttribute("id");

        // Valid ?
        if(sID != null)
        {
            // Display the list of loaded CSS

            var sHeight = Tools_GetStyleSize(sID, "height");
            var sWidth  = Tools_GetStyleSize(sID, "width");
    
            var sTop  = ((Tools_GetHeight() - sHeight) / 2.0) + Tools_GetScrollTop();
            var sLeft = ((Tools_GetWidth() - sWidth) / 2.0) + Tools_GetScrollLeft();
    
            _oNode.style.top    = sTop;
            _oNode.style.left   = sLeft;
        }
    }
}

function Tools_UpdateFixedPosition(_oNode)
{
    // Valid ?
    if(_oNode != null)
    {
        var sID = _oNode.getAttribute("id");

        // Valid ?
        if(sID != null)
        {
            var sWidth = Tools_GetStyleSize(sID, "width");
            var sLeft = (Tools_GetWidth() - sWidth) + Tools_GetScrollLeft();
    
            _oNode.style.top  = Tools_GetScrollTop();
            _oNode.style.left = sLeft;
        }
    }
}

/**
 * Check that all CSS files have been loaded
 */
function Tools_CheckCssLoaded()
{
    // Default return value
    var bAllValid = true;
    
    // Check that all files have at least one rule
    var aoCSSList = document.styleSheets;
    
    // Valid ?
    if((aoCSSList)
    && (aoCSSList != null))
    {
        for(var i=0; (bAllValid) && (i<aoCSSList.length); i++)
        {
            // Valid ?
            if((aoCSSList[i])
            && (aoCSSList[i] != null)
            && (aoCSSList[i] != TOOLS_UNDEFINED_VALUE))
            {
                var aoCSSRules = new Array();
                try
                {
                    if(aoCSSList[i].cssRules)
                    {
                        aoCSSRules = aoCSSList[i].cssRules
                    }
                    else if(aoCSSList[i].rules)
                    {
                    	aoCSSRules = aoCSSList[i].rules
                    }
                    
                    // No rule loaded ?
                    if(aoCSSRules.length == 0)
                    {
                        bAllValid = false;
                    }
                }
                catch(_oEx)
                {
                    // Ignore the CSS file that cannot be loaded
                    // ex : a href="chrome:///x.css" under firefox
                }
            }
        }
    }
    
    // Returns the loading status (of popup CSS)
    return bAllValid;
}

function Tools_SetBuggedControlVisibility(_oNode, _sVisibility)
{
    // Valid ?
    if(_oNode != null)
    {
        // Drop down ?
        if(_oNode.nodeType == TOOLS_NODE_ELEMENT_NODE)
        {
            if(_oNode.nodeName == "SELECT")
            {
                _oNode.style.visibility = _sVisibility; 
            }
            else if(_oNode.nodeName == "INPUT")
            {
                // Is it a radio button ?
                if(_oNode.getAttribute("type") == "radio")
                {
                    _oNode.style.visibility = _sVisibility; 
                }
            }
            else
            {
                // Go further
                for(var i = 0; i < _oNode.childNodes.length; i++)
                {
                    Tools_SetBuggedControlVisibility(_oNode.childNodes[i], _sVisibility);
                }
            }
        }
    }
}

/**
 * Get Mouse coordinates
 * @param _oEvent Event
 */ 
function Tools_GetMouseXY(_oContext, _oEvent) // works on IE6,FF,Moz,Opera7
{ 
  // Not valid event ?
  if(!_oEvent)
  {
    // IE is the only browser that we can use to get the event,
    // Use parameter for other browser
    _oEvent = window.event; 
  }

  // Valid ? 
  if(_oEvent)
  {
    // According to brwoser implementation

    if(_oEvent.pageX || _oEvent.pageY)
    {
      Tools_giMouseX = _oEvent.pageX;
      
      // Limit height ?
      if(_oEvent.pageY > 5)
      {
        Tools_giMouseY = _oEvent.pageY;
      }
      else
      {
        Tools_giMouseY = 5;
      }
    }
    else if(_oEvent.clientX || _oEvent.clientY)
    {
      // According to th interpretation of ScroolValue and DocType
      // http://www.quirksmode.org/js/doctypes.html
      Tools_giMouseX = _oEvent.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;

      // Limit height ?
      if(_oEvent.clientY > 5)
      {
        Tools_giMouseY = _oEvent.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
      }
      else
      {
        Tools_giMouseY = 5 + document.body.scrollTop  + document.documentElement.scrollTop;
      }
    }
  }
}

function Tools_GetKeyPress(_oContext, _oEvent)
{
  // Not valid event ?
  if(!_oEvent)
  {
    // IE is the only browser that we can use to get the event,
    // Use parameter for other browser
    _oEvent = window.event; 
  }

  // Valid ? 
  if(_oEvent)
  {
      // According to the browser implementation
      if(_oEvent.keyCode)
      {
          Tools_giKeyCode = _oEvent.keyCode;
      }
      else if(_oEvent.which)
      {
          Tools_giKeyCode = _oEvent.which;
      }
      
      // Save target
      if(_oEvent.target)
      {
          // Firefox, W3C
          Tools_goActiveField = _oEvent.target;
      }
      else
      {
          // Microsoft / IE
          Tools_goActiveField = _oEvent.srcElement;
      }
  }
}


// Removes leading whitespaces
function Tools_LeftTrim(_sValue)
{
    var oExp = /^\s+/g;
	return _sValue.replace(oExp, "");
}

// Removes ending whitespaces
function Tools_RightTrim(_sValue)
{
    var oExp = /\s+$/g;
	return _sValue.replace(oExp, "");
}

// Removes leading and ending whitespaces
function Tools_Trim(_sValue)
{
	return Tools_LeftTrim(Tools_RightTrim(_sValue));
}


function Tools_TextboxSwap(_sID)
{
    // Gets the Element
    var oInput = document.getElementById(_sID);
    var oLabel = document.getElementById(_sID + "_lbl"); // Temp : replace with const
    var oEmpty = document.getElementById(_sID + "_hid"); // Temp : replace with const
    
    // Valid controls ?
    if((oInput != null)
    && (oLabel != null))
    {
        // Input visible ?
        if(oInput.style.display != 'none')
        {
            // Hides input
            oInput.style.display = 'none';
            
            // Shows label
            oLabel.style.display = 'block';
            
            // Copy value from input into label
            var sValue = oInput.value;
            oLabel.innerHTML = sValue;
            
            // Empty value ?
            if((oEmpty != null)
            && ((sValue == null)
              ||(Tools_Trim(sValue) == "")))
            {
                oLabel.innerHTML = oEmpty.innerHTML;
            }
        }
        else
        {
            // Shows input
            oInput.style.display = 'block';
            oInput.focus();
            
            // Hides label
            oLabel.style.display = 'none';
        }
    }
}

/**
 * Import a node from a document to the main one.
 * @param _oNode Node to import
 * @param _bDeep Returns node recursivly
 * @return Returns the node in the context of the current document
 */
function Tools_ImportAllNode(_oDestinationDoc, _oNode)
{
    // Default return value
    var oRet = null;

    // W3C DOM Import node available ?
    if(document.importNode)
    {
        // Uses it
        oRet = _oDestinationDoc.importNode(_oNode, true);
    }
    else
    {
        // Gets the node to duplicate
    	var oNode = _oNode.xml || _oNode.outerHTML;
    	
    	// Create a dummy element
    	var oDummy = _oDestinationDoc.createElement("div");
    	
    	// Insert the HTML in the dummy node
    	oDummy.innerHTML = oNode;
    	
    	// Returns the Node (without dummy)
    	oRet = oDummy.firstChild;
    }

    // Returns the new node
    return oRet;
}

///////////////////////////////////////////////////
/////////////// TIMER SYSTEM //////////////////////
///////////////////////////////////////////////////

/** Current list of Timer */
var Timer_goTimerList = new Object();

/** Next timer ID builder */
var Timer_giNextID = 0;

/** Timer context */
function Timer_Context()
{
    this.sCallback = null;  // Callback event
    this.iTime = 0;         // Time set for the event time
    this.iKey = 0;          // Idx to match
}

/** Time elapsed */
function Timer_OnEvent(_sID, _iKey)
{
    // Valid input ?
    if(_sID != null)
    {
        // Check that the ID exists
        if(Tools_ContainsKey(Timer_goTimerList, _sID))
        {
            // Gets context
            var oTimer = Timer_goTimerList[_sID];
            
            // Valid ?
            if(oTimer != null)
            {
                // Check key
                if(_iKey == oTimer.iKey)
                {
                    // We can call the callback function
                    eval(oTimer.sCallback);
                    
                    // Stops the timer
                    Timer_Stop(_sID);
                }
            }
        }
    }
}

function Timer_Stop(_sID)
{
    // Valid input ?
    if(_sID != null)
    {
        // Remove the context from the global list
        Timer_goTimerList[_sID] = null;
    }
}

/** Starts a callback in _iTime ms */
function Timer_Start(_sCallback, _iTime)
{
    // Default return value
    var sID = null;
    
    // Valid input ?
    if((_sCallback != null)
    && (_sCallback != ""))
    {
        // Gets the next index
        sID = Timer_giNextID.toString();
        
        // Increase counter for new index
        Timer_giNextID++;
        
        // Build structure
        var oTimer = new Timer_Context();
        
        // Set values
        oTimer.sCallback    = _sCallback;
        oTimer.iTime        = _iTime;
        
        // Saves it
        Timer_goTimerList[sID] = oTimer;
        
        // Start timer
        window.setTimeout("Timer_OnEvent(" + sID + ", " + oTimer.iKey + ")", oTimer.iTime);
    }
    
    // Returns the ID
    return sID;
}

/** Restart a timer */
function Timer_Restart(_sID)
{
    // Valid input ?
    if((_sID != null)
    && (_sID != ""))
    {
        // Context exists ?
        if(Tools_ContainsKey(Timer_goTimerList, _sID))
        {
            // Gets context
            var oTimer = Timer_goTimerList[_sID];
            
            // Valid ?
            if(oTimer != null)
            {
                // Sets the new key
                oTimer.iKey++;
                
                // Restart callback
                window.setTimeout("Timer_OnEvent(" + _sID + ", " + oTimer.iKey + ")", oTimer.iTime);
            }
        }
    }
}

/** Reset a timer */
function Timer_Reset(_sID, _iNewTime)
{
    // Valid input ?
    if((_sID != null)
    && (_sID != ""))
    {
        // Context exists ?
        if(Tools_ContainsKey(Timer_goTimerList, _sID))
        {
            // Gets context
            var oTimer = Timer_goTimerList[_sID];
            
            // Valid ?
            if(oTimer != null)
            {
                // Sets the new key
                oTimer.iKey++;
                
                // Save new time
                oTimer.iTime = _iNewTime;
                
                // Restart callback
                window.setTimeout("Timer_OnEvent(" + _sID + ", " + oTimer.iKey + ")", oTimer.iTime);
            }
        }
    }
}
