/**
 *  @fileoverview This file contains utility functions used throughout site.
 *//*
 *  Variables
 *  Functions
 *    isBlank(value)
 *    isDate(value)
 *    isEmail(value)
 *    isNumeric(value)
 *    isTime(value)
 *    numcmp(n1, n2)
 *    pop(), push(item)
 *    setSizes()
 *    strcmp(s1, s2)
 *    swapImg(id, img)
 *    swrite_r(a)
 *    toggleViz(id)
 *    write_r(a)
 *
 *  AJAX function
 *    makeXMLHttpRequest()
 *
 *  String methods
 *    .replaceChar(tar, rep)
 *    .stripSpaces()
 *    .strReverse()
 *    .trimLeft()
 *    .trimRight()
 *    .trim()
 *    .ungetc(s)
 */

/**
 *  Tests string variable for content.
 *
 *  @param  {String} value
 *  @type   boolean
 */
function isBlank(value)
{
  return (value.trim() == "");
}

/**
 *  Tests whether a string is in a valid date format.
 *
 *  @param  {String} value
 *  @type   boolean
 */
function isDate(value)
{
  if (isNaN(Date.parse(value))) {
    return false;
  }
  return true
}

/**
 *  Tests whether a string is in a valid email format. Input must match regx format
 *  /[%\+-\.\w]+&#64;[-\.a-z0-9]+\.[\w]+/i
 *
 *  @param  {String} value
 *  @type   boolean
 */
function isEmail(value)
{
  if (value != "" && !/[%\+-\.\w]+@[-\.a-z0-9]+\.[\w]+/i.test(value)) {
    return false;
  }
  return true;
};

/**
 *  Tests whether value is numeric.
 *
 *  @param  {String} value
 *  @type   boolean
 */
function isNumeric(value)
{
  return !isNaN(stripSeparators(value.trim()));
}

/**
 *  Tests whether a string is in a valid time format. Input must match regx format
 *  /\d\d:\d\d:\d\d/
 *
 *  @param  {String} value
 *  @type   boolean
 */
function isTime(value)
{
  if (value != "" && !/\d\d:\d\d:\d\d/.test(value)) {
    return false;
  }
  return true;
};

/**
 *  Compares two numbers for sorting. See strcmp().
 *
 *  @param  {numeric} n1
 *  @param  {numeric} n2
 *  @type   int
 *  @return If n1 > n2 then (> 0) else if n1 == n2 then 0 else (< 0) (i.e. n1 < n2)
 */
function numcmp(n1, n2)
{
  return n1 - n2;
}

/**
 *  Creates a FIFO stack.
 */
var stack = new Array();

function pop()
{
  return stack.pop();
}

function push(item)
{
  stack.push(item);
}

/**
 *  Compares two strings for sorting. See numcmp().
 *
 *  @param  {String} s1
 *  @param  {String} s2
 *  @type   int
 *  @return If s1 > s2 then 1 else if s1 == s2 then 0 else -1 (i.e. s1 < s2)
 */
function strcmp(s1, s2)
{
  if (s1 > s2) {
    return 1;
  }

  if(s1 == s2) {
    return 0;
  }

  return -1;
}

/**
 *  Swaps an image by changing its src.
 *
 *  @param  {String} id   ID attribute of image element to replace
 *  @param  {Image} img   replacement Image object
 *  @type   void
 */
function swapImg(id, img)
{
  if (document.getElementById) {
    document.getElementById(id).src = img.src;
  }
  else if (document.all) {
    document.all[id].src = img.src;
  }
}

/**
 *  DEBUG FUNCTION: Parses an array and converts the elements to a string.
 *
 *  @param  {Array} a
 *  @type   String
 */
function swrite_r(a)
{
  var s = "array [key] : value\n";

  for (item in a) {
    s += "  [" + item + "] : " + a[item] + "\n";
  }

  return s;
}

/**
 *  Reverses the visibility of an element. A hidden element's initial visibility must be defined
 *  in its style attribute.
 *
 *  @param  {String} id   id of element to show/hide
 *  @type   void
 */
function toggleViz(id)
{
  var el = document.getElementById(id);

  el.style.visibility = (el.style.visibility == "hidden") ? "visible" : "hidden";
}

/**
 *  DEBUG FUNCTION: Prints array items.
 *
 *  @param  {Array} a
 *  @type   void
 */
function write_r(a)
{
  document.write(swrite_r(a));
}

/**
 *  Declare AJAX global variable.
 */
var xhRequest;

/**
 *  AJAX factory function. Sets global var xhRequest to an XML-HTTP request instance.
 *
 *  @type   boolean
 */
function makeXMLHttpRequest()
{
  xhRequest = null;

  // Mozilla, Safari, ...
  if (window.XMLHttpRequest) {
    xhRequest = new XMLHttpRequest();
    if (xhRequest.overrideMimeType) {
      xhRequest.overrideMimeType('text/xml');
    }
  }
  // IE
  else if (window.ActiveXObject) {
    try {
      xhRequest = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      try {
        xhRequest = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {}
    }
  }

  if (!xhRequest) {
    alert("Error: this browser cannot create an XMLHttpRequest instance");
    return false;
  }
  else {
    xhRequest.post = function (reqFile, reqData)
    {
      xhRequest.onreadystatechange = handleResponse;
      xhRequest.open('POST', reqFile, true);
      xhRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      xhRequest.send(reqData);
    }
  }

  return true;
}

// STRING PROTOTYPE DEFINITIONS ================================================

/**
 *  Replaces all target characters with the replacement character. Works by
 *  splitting it into an array and then rejoining it. Method added to String object.
 *
 *  @param  {String} str    String in which to replace characters
 *  @param  {String} tar    target character to replace
 *  @param  {String} rep    replacement character
 *  @return String with target characters replaced
 *  @type   String
 */
String.prototype.replaceChar = function(tar, rep)
{
  return this.split(tar).join(rep);
}

/**
 *  Strips spaces from a string. Method added to String object.
 *
 *  @requires String
 *  @return   String with spaces removed.
 *  @type     String
 */
String.prototype.stripSpaces = function()
{
  return this.replaceChar(" ", "");
}

/**
 *  Reverses the characters in a string. Method added to String object.
 *
 *  @requires String
 *  @return   String in reversed order
 *  @type     String
 */
String.prototype.strReverse = function()
{
  return this.split("").reverse().join("");
}

/**
 *  Trims leading whitespace from a string. Method added to String object.
 *
 *  @requires String
 *  @return   New string with spaces removed from the left.
 *  @type     String
 */
String.prototype.trimLeft = function()
{
  return this.replace(/^\s+/, "");
}

/**
 *  Trims trailing whitespace from a string. Method added to String object.
 *
 *  @requires String
 *  @return   New string with spaces removed from the right.
 *  @type     String
 */
String.prototype.trimRight = function()
{
  return this.replace(/\s+$/, "");
}

/**
 *  Trims leading and trailing whitespace from a string. Method added to String
 *  object.
 *
 *  @requires String
 *  @return   New string with leading and trailing spaces removed.
 *  @type     String
 */
String.prototype.trim = function()
{
  return this.trimLeft().trimRight();
}

/**
 *  Removes the last char from a string.
 *
 *  @requires String
 *  @return   New string with one less char than the original.
 *  @type     String
 */
String.prototype.ungetc = function()
{
  return this.substr(0, this.length - 1);
}
