﻿function traverseDom(func, startNode)
  {
  var node = 
    ( null != startNode
      ? startNode
      : document.documentElement );
  
  var firstEntry = true;
      
  while(true)
    {
    if(firstEntry)
      firstEntry = false;
    else
      {
      var result = func(node);
      if(result)
        return result;
      }
    
    // Moving down the tree while we can, calling the function
    // for all children.
    while(null != node.firstChild)
      {
      var result = func(node.firstChild);
      if(result)
        return result;
      node = node.firstChild;
      }
    
    // Now we have a childless node.
    
    // Moving to the next node if we can.
    if(null != node.nextSibling)
      {
      node = node.nextSibling;
      continue;
      }
    
    // No more siblings, so we move up until we have a node 
    // that does have the next sibling.
    while(true)
      {
      node = node.parentNode;
      if(null == node)
        // End of the game.
        return false;
      
      if(null != node.nextSibling)
        {
        node = node.nextSibling;
        break;
        }
      }
    
    // At this point we have not-yet-explored node.
    }
  }

function traverseTree(rootNode, func)
  {
  var node = rootNode;
      
  while(true)
    {
    //==//
      {
      var result = func(node);
      if(result)
        return result;
      }
    
    // Moving down the tree while we can, calling the function
    // for all children.
    while(null != node.firstChild)
      {
      var result = func(node.firstChild);
      if(result)
        return result;
      node = node.firstChild;
      }
    
    // Now we have a childless node.
    
    if (node == rootNode)
      return false;
    
    // Moving to the next node if we can.
    if(null != node.nextSibling)
      {
      node = node.nextSibling;
      continue;
      }
    
    // No more siblings, so we move up until we have a node 
    // that does have the next sibling.
    while(true)
      {
      node = node.parentNode;
      if((null == node) || (node == rootNode))
        // End of the game.
        return false;
      
      if(null != node.nextSibling)
        {
        node = node.nextSibling;
        break;
        }
      }
    
    // At this point we have not-yet-explored node.
    }
  }

function findElementNearAnchor(idRegex, anchorElement)
  {
  var lastFoundElement;
  var lastDistance = null;
  
  traverseDom(
    function(elem) {
      if (elem.id && idRegex.test(elem.id))
        {
        var elemDistance = getDistanceFromAnchor(elem, anchorElement);
        var useElem;
        if (lastDistance == null)
          useElem = true;
        else if (elemDistance == null)
          useElem = false;
        else
          useElem = (elemDistance <= lastDistance);
        
        if (useElem)
          {
          lastFoundElement = elem;
          lastDistance = elemDistance;
          }
        }
    },
    document.documentElement);
  
  return lastFoundElement;
  }

function getDistanceFromAnchor(element, anchorElement)
  {
  if (!anchorElement)
    return null;
  
  for (var ancestor = element, i = 0; ancestor; ancestor = ancestor.parentNode, ++i)
    if (ancestor == anchorElement)
      return 0;
  
  var distanceFromAnchorParent = getDistanceFromAnchor(element, anchorElement.parentNode);
  if (distanceFromAnchorParent != null)
    return distanceFromAnchorParent + 1;
  else
    return null;
  }

function doForEachElementWithName(name, func)
  {
  var elements = document.getElementsByName(name);
  for (var i = 0; i < elements.length; ++i)
    {
    func(elements[i]);
    }
  }

function getActiveRadioValue(name)
  {
  var radios = document.getElementsByName(name);
  for (var i = 0; i < radios.length; ++i)
    {
    if (radios[i].checked) return radios[i].value;
    }

  return null;
  }

function hideElement(id)
  {
    var element = document.getElementById(id);
    element.style.display = "none";
  }
  
function hideIfExists(id)
  {
    var element = document.getElementById(id);
    if(element)
      element.style.display = "none";
  }

function invisibleElement(id)
  {
    var element = document.getElementById(id);
    element.style.visibility = "hidden";
  }
  
function invisibleIfExists(id)
  {
    var element = document.getElementById(id);
    if(element)
      element.style.visibility = "hidden";
  }

function getEventCharCode(ev)
  {
  var isExplorer = (-1 != navigator.appName.search("Explorer"));
  return (isExplorer ? ev.keyCode : ev.charCode);
  }

function getEventChar(ev)
  {
  return String.fromCharCode(getEventCharCode(ev));
  }

function filterNumericInput(ev)
  {
  var isExplorer = (-1 != navigator.appName.search("Explorer"));

  var code = getEventCharCode(ev);

  if((code ==44) || (code==46)) { return true; }
  if (code < 48 || code > 57)
    {
    if ((code != 0) && (code != 8))
      {
      if(isExplorer)
        ev.keyCode = 0;
      else
        ev.preventDefault();
      }
    }
  }

function filterIntegerInput(ev)
  {
  var isExplorer = (-1 != navigator.appName.search("Explorer"));

  var code = getEventCharCode(ev);

  if (code < 48 || code > 57)
    {
    if ((code != 0) && (code != 8))
      {
      if(isExplorer)
        ev.keyCode = 0;
      else
        ev.preventDefault();
      }
    }
  }

function moveToNextIfFull(textbox)
  {
  function returnUserInputElement(node)
    {
    var nodeName = node.nodeName.toLowerCase();
    if("input" == nodeName)
      {
      return (
        (node.disabled || ("hidden" == node.type))
        ? false 
        : node 
        );
      }
    else if("select" == nodeName)
      return node.disabled ? false : node;
    else
      return false;
    }
  
  if (textbox.maxLength == textbox.value.length)
    {
    var nextUserInputElement = traverseDom(
        returnUserInputElement, textbox);
    if(nextUserInputElement)
      nextUserInputElement.focus();
    }
  }

function refreshWindow(wnd)
  {
  if (/gecko|opera/i.test(navigator.userAgent))
    wnd.location.reload();
  else
    wnd.history.go();
  }

function addOnLoadFunction(functionToExecute)
  {
  if(window.onload)
    {
    var currOnload = window.onload;
    window.onload = function() { currOnload(); functionToExecute(); }
    }
  else
    {
    window.onload = functionToExecute;
    }
  }

function addOnLoadCode(codeToExecute)
  {
  addOnLoadFunction(new Function(codeToExecute));
  }

function addClass(element, cssClass)
  {
  if (!new RegExp(' ?\\b' + cssClass + '\\b', 'g').test(element.className))
    element.className = element.className + ' ' + cssClass;
  }

function removeClass(element, cssClass)
  {
  element.className = element.className.replace(new RegExp(' ?\\b' + cssClass + '\\b', 'g'), '');
  }

function showBlockAboveButton(blockId, buttonId, alignment, distance)
  {
  // Requires jquery
  
  if (distance == undefined) { distance = 6; }
  if (alignment != 'left' && alignment != 'center' && alignment != 'right') { alignment = 'center'; }
  
  var blockSet = $('#' + blockId);
  var buttonSet = $('#' + buttonId);

  blockSet.css('display', '');
  blockSet.css('margin-left', '0');
  blockSet.css('margin-top', '0');

  var blockPosition = blockSet.offset();
  var buttonPosition = buttonSet.offset();
  
  var horizontalOffset;
  switch (alignment)
  {
    case 'left':
      horizontalOffset = buttonPosition.left - blockPosition.left;
      break
    case 'center':
      horizontalOffset = buttonPosition.left - blockPosition.left
                         + (buttonSet.innerWidth() - blockSet.innerWidth()) / 2;
      break;
    case 'right':
      horizontalOffset = (buttonPosition.left + buttonSet.innerWidth())
                         - (blockPosition.left + blockSet.innerWidth());
      break;
  }
  
  var verticalOffset = buttonPosition.top - blockPosition.top - blockSet.innerHeight() - distance;
  
  blockSet.css('margin-left', horizontalOffset + 'px');
  blockSet.css('margin-top', verticalOffset + 'px');
  }

function showBlockNextToButton(blockId, buttonId, alignment, distance)
  {
  // Requires jquery
  
  if (distance == undefined) { distance = 6; }
  if (alignment != 'top' && alignment != 'middle' && alignment != 'bottom' && alignment != 'gc') { alignment = 'middle'; }
  
  var blockSet = $('#' + blockId);
  var buttonSet = $('#' + buttonId);

  blockSet.css('display', '');
  blockSet.css('margin-left', '0');
  blockSet.css('margin-top', '0');

  var blockPosition = blockSet.offset();
  var buttonPosition = buttonSet.offset();
  
  var verticalOffset;
  switch (alignment)
  {
    case 'top':
      verticalOffset = buttonPosition.top - blockPosition.top;
      break
    case 'middle':
      verticalOffset = buttonPosition.top - blockPosition.top
                       + (buttonSet.innerHeight() - blockSet.innerHeight()) / 2;
      break;
    case 'bottom':
      verticalOffset = (buttonPosition.top + buttonSet.innerHeight())
                       - (blockPosition.top + blockSet.innerHeight());
    case 'gc':
      verticalOffset = 10; 
      break;
  }

  if (alignment != "gc") {
    var horizontalOffset = buttonPosition.left - blockPosition.left + buttonSet.innerWidth() + distance;
  } else {
    var horizontalOffset = 16;
  }


  blockSet.css('margin-left', horizontalOffset + 'px');
  blockSet.css('margin-top', verticalOffset + 'px');
  }

function deferredDisable(control)
  {
  window.setTimeout(function() { control.disabled = true; });
  return true;
  }

function checkMoneyFormat(str)
  {
  return /^\$?[0-9]+(,[0-9]{3,3})*(\.[0-9]{1,2})?$/.test(str);
  }
  
function checkPercentFormat(str)
  {
  return /^[0-9]+(,[0-9]{3,3})*(\.[0-9]+)? *\%?$/.test(str);
  }
  
function checkNumberFormat(str)
  {
  return /^[0-9]+(\.[0-9]+)?$/.test(str);
  }
  
function checkNumberListFormat(str)
  {
  var numbersArray = str.split(/ +/);
  for (var i = 0; i < numbersArray.length; ++i)
    {
    if (numbersArray[i] == '')
      continue;
    if (!/^[0-9]+(\.[0-9]+)?$/.test(numbersArray[i]))
      return false;
    }
  
  return true;
  }

function checkNonNegativeIntegerListFormat(str)
  {
  var numbersArray = str.split(/ +/);
  for (var i = 0; i < numbersArray.length; ++i)
    {
    if (numbersArray[i] == '')
      continue;
    if (!/^\d+$/.test(numbersArray[i]))
      return false;
    }
  
  return true;
  }

function checkNonNegativeIntegerFormat(str)
  {
  return /^\d+$/.test(str);
  }

String.prototype.trim = function() 
  {
  return this.replace(/^\s+/, '').replace(/\s+$/, '');
  };

function URLEncode(clearString)
{
  var output = '';
  var x = 0;
  clearString = clearString.toString();
  var regex = /(^[a-zA-Z0-9_.]*)/;
  while (x < clearString.length)
  {
    var match = regex.exec(clearString.substr(x));
    if (match != null && match.length > 1 && match[1] != '')
    {
      output += match[1];
      x += match[1].length;
    }
    else
    {
      if (clearString[x] == ' ' || clearString.charCodeAt(x).toString(16).toUpperCase() == '20' || clearString.charCodeAt(x).toString(16).toUpperCase() == 'A0')
      {
        output += '+';
      }
      else
      {
        var charCode = clearString.charCodeAt(x);
        var hexVal = charCode.toString(16);
        output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
      }
      x++;
    }
  }
  return output;
}

