/******************************************************************************\
 * Copyright (c) 2002-2003 MiEnterprise Pty Ltd. All rights reserved.
 * See end of file for complete source history.
 *******************************************************************************
 * GENERAL VALIDATION LIBRARY
 * 
 * Adapted from various sources including:
 *   (1) http://builder.cnet.com/webbuilding/pages/Programming/Kahn/102198/ss01.html
 *   (2) http://javascript.internet.com/.
 *******************************************************************************
 * $Id: miclub.js,v 1.8 2003/11/17 05:48:06 mozzy Exp $
\******************************************************************************/

// check for IE3
var isIE3 = (navigator.appVersion.indexOf('MSIE 3') != -1);

/*************************************************************************\
 * define and instantiate validation objects
 * the validation object accepts the following parameters:
 *
 *   realName: name used in the alerts (same as label on the page)
 *
 *   formEltName: this must be the name of the corresponding
 *       HTML form element; make it the same as the object name
 *
 *   eltType: element type (we have to create this since IE3
 *       doesn't support the type property for for elements)
 *     text
 *     textarea
 *     checkbox
 *     radio
 *     select
 *
 *   uptoSnuff: function call that's evaluated during validation check
 *     isXXXX(args)
 *
 *   format: text representation of required format;
 *       pass 'null' if no required format;
 *       used in alert as an aid to user
\*************************************************************************/

// object definition
function validation(realName, formEltName, eltType, upToSnuff, format) 
{
  this.realName = realName;
  this.formEltName = formEltName;
  this.eltType = eltType;
  this.upToSnuff = upToSnuff;
  this.format = format;
}

/*************************************************************************\
 * Define the elts array:
 * Add a new item to the array for each object you create above
 * Make sure the value of the array element is the same as
 * the name of the object, and that the array elements are listed
 * in the same order the corresponding objects appear in the form
 * (it's more clear to the user that way)
 * for example:
 * var elts = new Array(lastName, phoneNum, reason)
\*************************************************************************/

var elts = new Array();

/*************************************************************************\
 * The main function keeps track of which fields the user missed
 * or filled in incorrectly, and alerts the user so they can go
 * back and fix what's wrong.
 * Set allAtOnce to true if you want this "validation help" to
 * alert the user to all mistakes at once; set it to false if
 * you want it to show one mistake at a time
\*************************************************************************/

var allAtOnce = true;

/*************************************************************************\
  change text for alerts here
  unspecified field (text): "Please include [field name]."
  unspecified field (other): "Please choose [field name]."
  invalid text field entries: "[field value] is an invalid [field name]!"
  help with format: "Use this format: "
\*************************************************************************/

var beginRequestAlertForText = "Please include: ";
var beginRequestAlertGeneric = "Please choose: ";
var endRequestAlert = ".";
var beginInvalidAlert = " is an invalid ";
var endInvalidAlert = "!";
var beginFormatAlert = "  Use this format: ";

/*************************************************************************\
 * Trim a string
\*************************************************************************/

function ltrim(s)
{
  return s.replace( /^\s*/, "" )
}

function rtrim(s)
{
  return s.replace( /\s*$/, "" );
}

function trim(s)
{
  return rtrim(ltrim(s));
}

/*************************************************************************\
 * Equal to string
\*************************************************************************/

function isEqual(str1,str2)
{
  return strcmp(str1,str2) == 0;
}

/*************************************************************************\
 * Integer range: min <= int <= max
\*************************************************************************/

function isNumber(str, min, max) 
{
  return (isText(str) && (parseInt(str) >= min) && (parseInt(str) <= max));
}

/*************************************************************************\
 * Float range: min <= float <= max
\*************************************************************************/

function isFloat(str, min, max) 
{
  return (isText(str) && (parseFloat(str) >= parseFloat(min)) && (parseFloat(str) <= parseFloat(max)));
}

/*************************************************************************\
 * Positive whole number (n > 0)
\*************************************************************************/

function isPositiveWholeNumber(str) 
{
  for (j=0; j<str.length; j++)
  {
    if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) 
    { 
      return false; 
    }
  }
  return (parseInt(str) > 0);
}

/*************************************************************************\
 * Non-negative whole number (n >= 0)
\*************************************************************************/

function isNonNegativeWholeNumber(str) 
{
  for (j=0; j<str.length; j++)
  {
    if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) 
    { 
      return false; 
    }
  }
  return (parseInt(str) >= 0);
}

/*************************************************************************\
 * 24-hour time: HH:mm
\*************************************************************************/

function is24HourTime(str) 
{
  return (str.length == 5) && isNumber(str.charAt(0) + str.charAt(1), 0, 23)
    && (str.charAt(2) == ':') && isNumber(str.charAt(3) + str.charAt(4), 0, 59);
}

/*************************************************************************\
 * Non-empty Text
\*************************************************************************/

function isText(str) 
{
  return (str != "");
}

/*************************************************************************\
 * Text in length range
\*************************************************************************/

function isTextRange(str, minLength, maxLength)
{
  return (str.length >= minLength) && (str.length <= maxLength);
}

/*************************************************************************\
 * Plain text
\*************************************************************************/

function isPlainText(str)
{
  for (j=0; j<str.length; j++)
  {
    if (!isLetter(str.charAt(j)))
    {
      return false;
    }
  }
  return true;
}

/*************************************************************************\
 * Plain text with a minimum length
\*************************************************************************/

function isPlainTextLen(str, minLength) 
{
  return (isText(str) && isPlainText(str) && isTextLen(str, minLength));
}

/*************************************************************************\
 * Plain name text
\*************************************************************************/

function isPlainNameText(str)
{
    for (j=0; j<str.length; j++)
    {
      if ( ( !isLetter( str.charAt(j) ) ) && ( "'" != str.charAt(j) ) && ( " " != str.charAt(j) ) && ( "-" != str.charAt(j) ) ) 
      {
        return false;
      }
    }
    return true;
}

/*************************************************************************\
 * Plain name text of minimum length
\*************************************************************************/

function isPlainNameTextLen(str, minLength) 
{
  return (isText(str) && isPlainNameText(str) && isTextLen(str, minLength));
}

/*************************************************************************\
 * Password 
\*************************************************************************/

function isPassword(str,minLength) 
{
    if (str.length < minLength)
    {
        return false;
    }
    var digitCount = 0;
    var letterCount = 0;
       
    for (j=0; j<str.length; j++)
    {
        if (isDigit(str.charAt(j)))
        {
            digitCount++;
        }   
        else
        {
            letterCount++;
        }
    }
    return (digitCount > 0) && (letterCount > 0);
}

/*************************************************************************\
 * Text with minimum length
\*************************************************************************/

function isTextLen(str,minLength) 
{
  return (str.length >= minLength);
}

/*************************************************************************\
 * Checked Radio
\*************************************************************************/

function isSelect(formObj) 
{
  return (formObj.selectedIndex != 0);
}

/*************************************************************************\
 * Checked Radio
\*************************************************************************/

function isRadio(formObj) 
{
  for (j=0; j<formObj.length; j++) 
  {
    if (formObj[j].checked) 
    {
      return true;
    }
  }
  return false;
}

/*************************************************************************\
 * Checked
\*************************************************************************/

function isCheck(formObj, form, begin, num) 
{
  for (j=begin; j<begin+num; j++) 
  {
    if (form.elements[j].checked) 
    {
      return true;
    }
  }
  return false;
}

/*************************************************************************\
 * URL: http://domain.com
\*************************************************************************/

function isUrl(str) 
{
  return ((str.length >= 12) && (str.indexOf("http://") == 0))
}

/*************************************************************************\
 * Optional URL: [http://domain.com]
\*************************************************************************/

function isOptionalUrl(str) 
{
  return ((str.length == 0) || isUrl(str));
}

/*************************************************************************\
 * Email: aaa@aaa.com
\*************************************************************************/

function isEmail(emailStr) 
{
  /* The following pattern is used to check if the entered e-mail address
     fits the user@domain format.  It also is used to separate the username
     from the domain. */
  var emailPat=/^(.+)@(.+)$/
  /* The following string represents the pattern for matching all special
     characters.  We don't want to allow special characters in the address. 
     These characters include ( ) < > @ , ; : \ " . [ ]    */
  var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]"
  /* The following string represents the range of characters allowed in a 
     username or domainname.  It really states which chars aren't allowed. */
  var validChars="\[^\\s" + specialChars + "\]"
  /* The following pattern applies if the "user" is a quoted string (in
     which case, there are no rules about which characters are allowed
     and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
     is a legal e-mail address. */
  var quotedUser="(\"[^\"]*\")"
  /* The following pattern applies for domains that are IP addresses,
     rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
     e-mail address. NOTE: The square brackets are required. */
  var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/
  /* The following string represents an atom (basically a series of
     non-special characters.) */
  var atom=validChars + '+'
  /* The following string represents one word in the typical username.
     For example, in john.doe@somewhere.com, john and doe are words.
     Basically, a word is either an atom or quoted string. */
  var word="(" + atom + "|" + quotedUser + ")"
  // The following pattern describes the structure of the user
  var userPat=new RegExp("^" + word + "(\\." + word + ")*$")
  /* The following pattern describes the structure of a normal symbolic
     domain, as opposed to ipDomainPat, shown above. */
  var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$")

  /* Finally, let's start trying to figure out if the supplied address is
     valid. */

  /* Begin with the coarse pattern to simply break up user@domain into
     different pieces that are easy to analyze. */
  var matchArray=emailStr.match(emailPat)
  if (matchArray==null) 
  {
    /* Too many/few @'s or something; basically, this address doesn't
       even fit the general mould of a valid e-mail address. */
    return false
  }
  var user=matchArray[1]
  var domain=matchArray[2]

  // See if "user" is valid 
  if (user.match(userPat)==null) 
  {      
      return false;
  }

  /* if the e-mail address is at an IP address (as opposed to a symbolic
     host name) make sure the IP address is valid. */
  var IPArray=domain.match(ipDomainPat)
  if (IPArray!=null) 
  {
      // this is an IP address
      for (var i=1;i<=4;i++) 
      {
        if (IPArray[i]>255) 
        {
          return false;
        }
      }
      return true
  }

  // Domain is symbolic name
  var domainArray=domain.match(domainPat)
  if (domainArray==null) 
  {
    return false;
  }

  /* domain name seems valid, but now make sure that it ends in a
     three-letter word (like com, edu, gov) or a two-letter word,
     representing country (uk, nl), and that there's a hostname preceding 
     the domain or country. */

  /* Now we need to break up the domain to get a count of how many atoms
     it consists of. */
  var atomPat=new RegExp(atom,"g")
  var domArr=domain.match(atomPat)
  var len=domArr.length
  if (domArr[domArr.length-1].length<2 || 
      domArr[domArr.length-1].length>3) 
  {
     return false;
  }

  // Make sure there's a host name preceding the domain.
  if (len<2) 
  {
     return false;
  }

  // If we've gotten this far, everything's valid!
  return true;
}


/*************************************************************************\
 * Optional Email: [aaa@aaa.com]
\*************************************************************************/

function isOptionalEmail(str) {
 return ((str.length == 0) || isEmail(str));
}

/*************************************************************************\
 * Australian Telephone: nn nnnn nnnn
\*************************************************************************/

function isAustralianPhoneNum(str) 
{
  if (str.length == 0) { return false }
  if (str.charAt(0) == "+") { return true }
  if (str.length != 12) { return false }

  for (j=0; j<str.length; j++) {
    if ((j == 2) || (j == 7)) {
      if (str.charAt(j) != " ") { return false }
    } else {
      if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) { return false }
    }
  }
  return true;
}

/*************************************************************************\
 * Optional Australian Telephone: [nn nnnn nnnn]
\*************************************************************************/

function isOptionalAustralianPhoneNum(str) {
 return ((str.length == 0) || isAustralianPhoneNum(str));
}

/*************************************************************************\
 * Australian Mobile Telephone: nnnn nnn nnn
\*************************************************************************/

function isAustralianMobilePhoneNum(str) 
{
  if (str.length == 0) { return false }
  if (str.charAt(0) == "+") { return true }
  if (str.length != 12) { return false }
  for (j=0; j<str.length; j++) {
    if ((j == 4) || (j == 8)) {
      if (str.charAt(j) != " ") { return false }
    } else {
      if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) { return false }
    }
  }
  return true;
}

/*************************************************************************\
 * Optional Australian Mobile Telephone: [nnnn nnn nnn]
\*************************************************************************/

function isOptionalAustralianMobilePhoneNum(str) 
{
  return ((str.length == 0) || isAustralianMobilePhoneNum(str));
}

/*************************************************************************\
 * Letter: a-zA-Z
\*************************************************************************/

function isLetter (c)
{   
  return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) );
}

/*************************************************************************\
 * Digit: 0-9
\*************************************************************************/

function isDigit (c)
{
  return ((c >= "0") && (c <= "9"));
}

/*************************************************************************\
 * Letter or Digit: a-zA-Z0-9
\*************************************************************************/

function isLetterOrDigit (c)
{
  return (isLetter(c) || isDigit(c));
}

/*************************************************************************\
 * Optional Timestamp: [yyyy-mm-dd hh:mm[:ss[.fff]]]
\*************************************************************************/

function isOptionalTimestamp(str)
{
    return (str.length == 0) || isTimestamp(str);
}

/*************************************************************************\
 * Timestamp: yyyy-mm-dd hh:mm[:ss[.fff]]
\*************************************************************************/

function isTimestamp(str)
{
  if (str.length < 16) { return false }
  
  return (isTimestampDate(str.substring(0,10)) && isTimestampTime(str.substring(11)));
}

/*************************************************************************\
 * Optional Timestamp Date: [yyyy-mm-dd]
\*************************************************************************/

function isOptionalTimestampDate(str)
{
    return (str.length == 0) || isTimestampDate(str);
}

/*************************************************************************\
 * Timestamp Date: yyyy-mm-dd
\*************************************************************************/

function isTimestampDate(str)
{
  if (str.length != 10) { return false }

  for (j=0; j<str.length; j++) 
  {
    if ((j == 4) || (j == 7)) 
    {
      if (str.charAt(j) != "-") { return false }
    } 
    else 
    {
      if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) { return false }
    }
  }

  // should check range of each part!
  
  return true;
}

/*************************************************************************\
 * Timestamp Time: h:mm[:ss[.ffff]]
\*************************************************************************/

function isTimestampTime(str)
{
  if (str.length < 5) { return false }

  for (j=0; j<str.length; j++) 
  {
    if ((j == 2) || (j == 5)) 
    {
      if (str.charAt(j) != ":") { return false }
    } 
    else if (j == 8)
    {
      if (str.charAt(j) != ".") { return false }
    }
    else 
    {
      if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) { return false }
    }
  }
  
  // should check range of each part!
  
  return true;
}

/*************************************************************************\
 * Date: d/m/yyyy
\*************************************************************************/

function isAusDate(str) 
{
  /*if (str.length != 10) { return false }

  for (j=0; j<str.length; j++) {
    if ((j == 2) || (j == 5)) {
      if (str.charAt(j) != "/") { return false }
    } else {
      if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) { return false }
    }
  }
*/
  var numSlashes = 0;
  var month = 0;
  var day = 0;
  var year = 0;

  // parse the date

  for (j=0; j<str.length; j++)
  {
    if (str.charAt(j) == "/")
    {
      numSlashes++;
    }
    else if ((str.charAt(j) < "0") || (str.charAt(j) > "9"))
    {
      return false;
    }
    else if (numSlashes == 0)
    {
      day = day * 10 + parseInt(str.charAt(j));
    }
    else if (numSlashes == 1)
    {
      month = month * 10 + parseInt(str.charAt(j));
    }
    else if (numSlashes == 2)
    {
      year = year * 10 + parseInt(str.charAt(j));
    }
    else
    {
      return false;
    }
  }

  if (day <= 0) { return false }

  if (month == 0 || month > 12) { return false }

  if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
  {
    if (day > 31) { return false }
  }
  else if (month == 4 || month == 6 || month == 9 || month == 11)
  {
    if (day > 30) { return false }
  }
  else
  {
      if (year%400 == 0)
      {
        // multiples of 400 are leap years
        if (day > 29) { return false }
      }
      else if (year%100 == 0)
      {
        // multiples of 100 are not leap years
        if (day > 28) { return false }
      }
      else if (year%4 == 0)
      {
        // multiples of 100 are leap years
        if (day > 29) { return false }
      }
      else
      {
        if (day > 28) { return false }
      }
  }
  if (year < 1900) {return false;}
  if (year > 2100) {return false;}

  return true;
}

/*************************************************************************\
 * Date (m/d/yyyy)
\*************************************************************************/

function isDate(str) 
{
  /*if (str.length != 10) { return false }

  for (j=0; j<str.length; j++) {
    if ((j == 2) || (j == 5)) {
      if (str.charAt(j) != "/") { return false }
    } else {
      if ((str.charAt(j) < "0") || (str.charAt(j) > "9")) { return false }
    }
  }
*/
  var numSlashes = 0;
  var month = 0;
  var day = 0;
  var year = 0;

  // parse the date

  for (j=0; j<str.length; j++)
  {
    if (str.charAt(j) == "/")
    {
      numSlashes++;
    }
    else if ((str.charAt(j) < "0") || (str.charAt(j) > "9"))
    {
      return false;
    }
    else if (numSlashes == 0)
    {
      month = month * 10 + parseInt(str.charAt(j));
    }
    else if (numSlashes == 1)
    {
      day = day * 10 + parseInt(str.charAt(j));
    }
    else if (numSlashes == 2)
    {
      year = year * 10 + parseInt(str.charAt(j));
    }
    else
    {
      return false;
    }
  }

  if (day <= 0) { return false }

  if (month == 0 || month > 12) { return false }

  if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
  {
    if (day > 31) { return false }
  }
  else if (month == 4 || month == 6 || month == 9 || month == 11)
  {
    if (day > 30) { return false }
  }
  else
  {
      if (year%400 == 0)
      {
        // multiples of 400 are leap years
        if (day > 29) { return false }
      }
      else if (year%100 == 0)
      {
        // multiples of 100 are not leap years
        if (day > 28) { return false }
      }
      else if (year%4 == 0)
      {
        // multiples of 100 are leap years
        if (day > 29) { return false }
      }
      else
      {
        if (day > 28) { return false }
      }
  }
  if (year < 1900) {return false;}
  if (year > 2100) {return false;}

  return true;
}

/*************************************************************************\
 * Validate Date: These functions allow date validation and building using 
 * tokens. and example of usage is : onClick="if(isDate(this.form.email.value,'%mm/%dd/%y'))
\*************************************************************************/

/*************************************************************************\
 * This section defines variables and tokens needed for date checking.
 * Original:  Sandeep Tamhankar (stamhankar@hotmail.com)
 * 
 * Here's the list of tokens we support:
 * m (or M) : month number, one or two digits.
 * mm (or MM) : month number, strictly two digits (i.e. April is 04).
 * d (or D) : day number, one or two digits.
 * dd (or DD) : day number, strictly two digits.
 * y (or Y) : year, two or four digits.
 * yy (or YY) : year, strictly two digits.
 * yyyy (or YYYY) : year, strictly four digits.
 * mon : abbreviated month name (April is apr, Apr, APR, etc.)
 * Mon : abbreviated month name, mixed-case (i.e. April is Apr only).
 * MON : abbreviated month name, all upper-case (i.e. April is APR only).
 * mon_strict : abbreviated month name, all lower-case (i.e. April is apr 
 *       only).
 * month : full month name (April is april, April, APRIL, etc.)
 * Month : full month name, mixed-case (i.e. April only).
 * MONTH: full month name, all upper-case (i.e. APRIL only).
 * month_strict : full month name, all lower-case (i.e. april only).
 * h (or H) : hour, one or two digits.
 * hh (or HH) : hour, strictly two digits.
 * min (or MIN): minutes, one or two digits.
 * mins (or MINS) : minutes, strictly two digits.
 * s (or S) : seconds, one or two digits.
 * ss (or SS) : seconds, strictly two digits.
 * ampm (or AMPM) : am/pm setting.  Valid values to match this token are
 *       am, pm, AM, PM, a.m., p.m., A.M., P.M.
\*************************************************************************/

// Be careful with this pattern.  Longer tokens should be placed before shorter
// tokens to disambiguate them.  For example, parsing "mon_strict" should 
// result in one token "mon_strict" and not two tokens "mon" and a literal
// "_strict".

var tokPat=new RegExp("^month_strict|month|Month|MONTH|yyyy|YYYY|mins|MINS|mon_strict|ampm|AMPM|mon|Mon|MON|min|MIN|dd|DD|mm|MM|yy|YY|hh|HH|ss|SS|m|M|d|D|y|Y|h|H|s|S");

// lowerMonArr is used to map months to their numeric values.

var lowerMonArr={jan:1, feb:2, mar:3, apr:4, may:5, jun:6, jul:7, aug:8, sep:9, oct:10, nov:11, dec:12}

// monPatArr contains regular expressions used for matching abbreviated months
// in a date string.

var monPatArr=new Array();
monPatArr['mon_strict']=new RegExp(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/);
monPatArr['Mon']=new RegExp(/Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/);
monPatArr['MON']=new RegExp(/JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC/);
monPatArr['mon']=new RegExp("jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec",'i');

// monthPatArr contains regular expressions used for matching full months
// in a date string.

var monthPatArr=new Array();
monthPatArr['month']=new RegExp(/^january|february|march|april|may|june|july|august|september|october|november|december/i);
monthPatArr['Month']=new RegExp(/^January|February|March|April|May|June|July|August|September|October|November|December/);
monthPatArr['MONTH']=new RegExp(/^JANUARY|FEBRUARY|MARCH|APRIL|MAY|JUNE|JULY|AUGUST|SEPTEMBER|OCTOBER|NOVEMBER|DECEMBER/);
monthPatArr['month_strict']=new RegExp(/^january|february|march|april|may|june|july|august|september|october|november|december/);

// cutoffYear is the cut-off for assigning "19" or "20" as century.  Any
// two-digit year >= cutoffYear will get a century of "19", and everything
// else gets a century of "20".

var cutoffYear=50;

// FormatToken is a datatype we use for storing extracted tokens from the
// format string.

function FormatToken (token, type) {
this.token=token;
this.type=type;
}

function parseFormatString (formatStr) {
var tokArr=new Array;
var tokInd=0;
var strInd=0;
var foundTok=0;
    
while (strInd < formatStr.length) {
if (formatStr.charAt(strInd)=="%" &&
(matchArray=formatStr.substr(strInd+1).match(tokPat)) != null) {
strInd+=matchArray[0].length+1;
tokArr[tokInd++]=new FormatToken(matchArray[0],"symbolic");
} else {

// No token matched current position, so current character should 
// be saved as a required literal.

if (tokInd>0 && tokArr[tokInd-1].type=="literal") {

// Literal tokens can be combined.Just add to the last token.

tokArr[tokInd-1].token+=formatStr.charAt(strInd++);
}
else {
tokArr[tokInd++]=new FormatToken(formatStr.charAt(strInd++), "literal");
      }
   }
}
return tokArr;
}

/* buildDate does all the real work.It takes a date string and format string,
 tries to match the two up, and returns a Date object (with the supplied date
 string value).If a date string doesn't contain all the fields that a Date
 object contains (for example, a date string with just the month), all
 unprovided fields are defaulted to those characteristics of the current
 date. Time fields that aren't provided default to 0.Thus, a date string
 like "3/30/2000" in "%mm/%dd/%yyyy" format results in a Date object for that
 date at midnight.formatStr is a free-form string that indicates special
 tokens via the % character.Here are some examples that will return a Date
 object:

 buildDate('3/30/2000','%mm/%dd/%y') // March 30, 2000
 buildDate('March 30, 2000','%Mon %d, %y') // Same as above.
 buildDate('Here is the date: 30-3-00','Here is the date: %dd-%m-%yy')

 If the format string does not match the string provided, an error message
 (i.e. String object) is returned.Thus, to see if buildDate succeeded, the
 caller can use the "typeof" command on the return value.For example,
 here's the isDate function, which returns true if a given date is
 valid,and false otherwise (and reports an error in the false case):

 function isDate(dateStr,formatStr) {
 var myObj=buildDate(dateStr,formatStr);
 if (typeof myObj=="object") {
 // We got a Date object, so good.
 return true;
 } else {
 // We got an error string.
 alert(myObj);
 return false;
 }
 }

*/

function buildDate(dateStr,formatStr) {
// parse the format string first.
var tokArr=parseFormatString(formatStr);
var strInd=0;
var tokInd=0;
var intMonth;
var intDay;
var intYear;
var intHour;
var intMin;
var intSec;
var ampm="";
var strOffset;

// Create a date object with the current date so that if the user only
// gives a month or day string, we can still return a valid date.

var curdate=new Date();
intMonth=curdate.getMonth()+1;
intDay=curdate.getDate();
intYear=curdate.getFullYear();

// Default time to midnight, so that if given just date info, we return
// a Date object for that date at midnight.

intHour=0;
intMin=0;
intSec=0;

// Walk across dateStr, matching the parsed formatStr until we find a 
// mismatch or succeed.

while (strInd < dateStr.length && tokInd < tokArr.length) {

// Start with the easy case of matching a literal.

if (tokArr[tokInd].type=="literal") {
if (dateStr.indexOf(tokArr[tokInd].token,strInd)==strInd) {

// The current position in the string does match the format 
// pattern.

strInd+=tokArr[tokInd++].token.length;
continue;
}
else {

// ACK! There was a mismatch; return error.
if (dateStr.length == 0) {
return "Please specify a date.";
} 
else {
return "\"" + dateStr + "\" does not conform to the expected format: " + formatStr;
}
   }
}

// If we get here, we're matching to a symbolic token.
switch (tokArr[tokInd].token) {
case 'm':
case 'M':
case 'd':
case 'D':
case 'h':
case 'H':
case 'min':
case 'MIN':
case 's':
case 'S':

// Extract one or two characters from the date-time string and if 
// it's a number, save it as the month, day, hour, or minute, as
// appropriate.

curChar=dateStr.charAt(strInd);
nextChar=dateStr.charAt(strInd+1);
matchArr=dateStr.substr(strInd).match(/^\d{1,2}/);
if (matchArr==null) {

// First character isn't a number; there's a mismatch between
// the pattern and date string, so return error.

switch (tokArr[tokInd].token.toLowerCase()) {
case 'd': var unit="day"; break;
case 'm': var unit="month"; break;
case 'h': var unit="hour"; break;
case 'min': var unit="minute"; break;
case 's': var unit="second"; break;
}
return "Bad " + unit + " \"" + curChar + "\" or \"" + curChar +
nextChar + "\".";
}
strOffset=matchArr[0].length;
switch (tokArr[tokInd].token.toLowerCase()) {
case 'd': intDay=parseInt(matchArr[0],10); break;
case 'm': intMonth=parseInt(matchArr[0],10); break;
case 'h': intHour=parseInt(matchArr[0],10); break;
case 'min': intMin=parseInt(matchArr[0],10); break;
case 's': intSec=parseInt(matchArr[0],10); break;
}
break;
case 'mm':
case 'MM':
case 'dd':
case 'DD':
case 'hh':
case 'HH':
case 'mins':
case 'MINS':
case 'ss':
case 'SS':

// Extract two characters from the date string and if it's a 
// number, save it as the month, day, or hour, as appropriate.

strOffset=2;
matchArr=dateStr.substr(strInd).match(/^\d{2}/);
if (matchArr==null) {

// The two characters aren't a number; there's a mismatch 
// between the pattern and date string, so return an error
// message.

switch (tokArr[tokInd].token.toLowerCase()) {
case 'dd': var unit="day"; break;
case 'mm': var unit="month"; break;
case 'hh': var unit="hour"; break;
case 'mins': var unit="minute"; break;
case 'ss': var unit="second"; break;
}
return "Bad " + unit + " \"" + dateStr.substr(strInd,2) + 
"\".";
}
switch (tokArr[tokInd].token.toLowerCase()) {
case 'dd': intDay=parseInt(matchArr[0],10); break;
case 'mm': intMonth=parseInt(matchArr[0],10); break;
case 'hh': intHour=parseInt(matchArr[0],10); break;
case 'mins': intMin=parseInt(matchArr[0],10); break;
case 'ss': intSec=parseInt(matchArr[0],10); break;
}
break;
case 'y':
case 'Y':

// Extract two or four characters from the date string and if it's
// a number, save it as the year.Convert two-digit years to four
// digit years by assigning a century of '19' if the year is >= 
// cutoffYear, and '20' otherwise.

if (dateStr.substr(strInd,4).search(/\d{4}/) != -1) {

// Four digit year.

intYear=parseInt(dateStr.substr(strInd,4),10);
strOffset=4;
}
else {
if (dateStr.substr(strInd,2).search(/\d{2}/) != -1) {

// Two digit year.

intYear=parseInt(dateStr.substr(strInd,2),10);
if (intYear>=cutoffYear) {
intYear+=1900;
}
else {
intYear+=2000;
}
strOffset=2;
}
else {

// Bad year; return error.

return "Bad year \"" + dateStr.substr(strInd,2) + 
"\". Must be two or four digits.";
   }
}
break;
case 'yy':
case 'YY':

// Extract two characters from the date string and if it's a 
// number, save it as the year.Convert two-digit years to four 
// digit years by assigning a century of '19' if the year is >= 
// cutoffYear, and '20' otherwise.

if (dateStr.substr(strInd,2).search(/\d{2}/) != -1) {

// Two digit year.

intYear=parseInt(dateStr.substr(strInd,2),10);
if (intYear>=cutoffYear) {
intYear+=1900;
}
else {
intYear+=2000;
}
strOffset=2;
} else {
// Bad year; return error
return "Bad year \"" + dateStr.substr(strInd,2) + 
"\". Must be two digits.";
}
break;
case 'yyyy':
case 'YYYY':

// Extract four characters from the date string and if it's a 
// number, save it as the year.

if (dateStr.substr(strInd,4).search(/\d{4}/) != -1) {

// Four digit year.

intYear=parseInt(dateStr.substr(strInd,4),10);
strOffset=4;
}
else {

// Bad year; return error.

return "Bad year \"" + dateStr.substr(strInd,4) + 
"\". Must be four digits.";
}
break;
case 'mon':
case 'Mon':
case 'MON':
case 'mon_strict':

// Extract three characters from dateStr and parse them as 
// lower-case, mixed-case, or upper-case abbreviated months,
// as appropriate.

monPat=monPatArr[tokArr[tokInd].token];
if (dateStr.substr(strInd,3).search(monPat) != -1) {
intMonth=lowerMonArr[dateStr.substr(strInd,3).toLowerCase()];
}
else {

// Bad month, return error.

switch (tokArr[tokInd].token) {
case 'mon_strict': caseStat="lower-case"; break;
case 'Mon': caseStat="mixed-case"; break;
case 'MON': caseStat="upper-case"; break;
case 'mon': caseStat="between Jan and Dec"; break;
}
return "Bad month \"" + dateStr.substr(strInd,3) + 
"\". Must be " + caseStat + ".";
}
strOffset=3;
break;
case 'month':
case 'Month':
case 'MONTH':
case 'month_strict':

// Extract a full month name at strInd from dateStr if possible.

monPat=monthPatArr[tokArr[tokInd].token];
matchArray=dateStr.substr(strInd).match(monPat);
if (matchArray==null) {

// Bad month, return error.

return "Can't find a month beginning at \"" +
dateStr.substr(strInd) + "\".";
}

// It's a good month.

intMonth=lowerMonArr[matchArray[0].substr(0,3).toLowerCase()];
strOffset=matchArray[0].length;
break;
case 'ampm':
case 'AMPM':
matchArr=dateStr.substr(strInd).match(/^(am|pm|AM|PM|a\.m\.|p\.m\.|A\.M\.|P\.M\.)/);
if (matchArr==null) {

// There's no am/pm in the string.Return error msg.

return "Missing am/pm designation.";
}

// Store am/pm value for later (as just am or pm, to make things
// easier later).

if (matchArr[0].substr(0,1).toLowerCase() == "a") {

// This is am.

ampm = "am";
}
else {
ampm = "pm";
}
strOffset = matchArr[0].length;
break;
}
strInd += strOffset;
tokInd++;
}
if (tokInd != tokArr.length || strInd != dateStr.length) {

/* We got through the whole date string or format string, but there's 
 more data in the other, so there's a mismatch. */

return "\"" + dateStr + "\" is either missing desired information or has more information than the expected format: " + formatStr;
}

// Make sure all components are in the right ranges.

if (intMonth < 1 || intMonth > 12) {
return "Month must be between 1 and 12.";
}
if (intDay < 1 || intDay > 31) {
return "Day must be between 1 and 31.";
}

// Make sure user doesn't put 31 for a month that only has 30 days

if ((intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11) && intDay == 31) {
return "Month "+intMonth+" doesn't have 31 days!";
}

// Check for February date validity (including leap years) 

if (intMonth == 2) {

// figure out if "year" is a leap year; don't forget that
// century years are only leap years if divisible by 400

var isleap=(intYear%4==0 && (intYear%100!=0 || intYear%400==0));
if (intDay > 29 || (intDay == 29 && !isleap)) {
return "February " + intYear + " doesn't have " + intDay + 
" days!";
   }
}

// Check that if am/pm is not provided, hours are between 0 and 23.

if (ampm == "") {
if (intHour < 0 || intHour > 23) {
return "Hour must be between 0 and 23 for military time.";
   }
}
else {

// non-military time, so make sure it's between 1 and 12.

if (intHour < 1|| intHour > 12) {
return "Hour must be between 1 and 12 for standard time.";
   }
}

// If user specified amor pm, convert intHour to military.

if (ampm=="am" && intHour==12) {
intHour=0;
}
if (ampm=="pm" && intHour < 12) {
intHour += 12;
}
if (intMin < 0 || intMin > 59) {
return "Minute must be between 0 and 59.";
}
if (intSec < 0 || intSec > 59) {
return "Second must be between 0 and 59.";
}
return new Date(intYear,intMonth-1,intDay,intHour,intMin,intSec);
}

function isDate(dateStr,formatStr) {
var myObj = buildDate(dateStr,formatStr);
if (typeof myObj == "object") {

// We got a Date object, so good.

return true;
}
else {

// We got an error string.

//alert(myObj);
return false;
   }
}

/*************************************************************************\
 * The validateFormElements() function validates the form elements
 * previously defined as validation objects and as members of
 * the elts array. We loop through the elts array, testing each
 * element in turn, and alerting the user when they've missed
 * a required field
\*************************************************************************/

function validateFormElements(form,elts) 
{
  var formEltName = "";
  var formObj = "";
  var str = "";
  var realName = "";
  var alertText = "";
  var firstMissingElt = null;
  var hardReturn = "\r\n";

  for (i=0; i<elts.length; i++) {

    formEltName = elts[i].formEltName;

    formObj = form.elements[formEltName];

    /*formObj = eval("form." + formEltName );*/

    realName = elts[i].realName;

    formObj.value = trim(formObj.value);
    
    if (elts[i].eltType == "text") 
    {
      str = formObj.value;

      if (eval(elts[i].upToSnuff)) continue;

      if (str == "") 
      {
        if (allAtOnce) 
        {
          alertText += beginRequestAlertForText + realName + endRequestAlert + hardReturn;
          if (firstMissingElt == null) {firstMissingElt = formObj};
        } 
        else 
        {
          alertText = beginRequestAlertForText + realName + endRequestAlert + hardReturn;
          alert(alertText);
        }
      } 
      else 
      {
        if (allAtOnce) 
        {
          alertText += str + beginInvalidAlert + realName + endInvalidAlert + hardReturn;
        } 
        else 
        {
          alertText = str + beginInvalidAlert + realName + endInvalidAlert + hardReturn;
        }
        if (elts[i].format != null) {
          alertText += beginFormatAlert + elts[i].format + hardReturn;
        }
        if (allAtOnce) {
          if (firstMissingElt == null) {firstMissingElt = formObj};
        } else {
          alert(alertText);
        }
      }
    } 
    else 
    {
      if (eval(elts[i].upToSnuff)) continue;
      if (allAtOnce) 
      {
        alertText += beginRequestAlertGeneric + realName + endRequestAlert + hardReturn;
        if (firstMissingElt == null) {firstMissingElt = formObj};
      } 
      else 
      {
        alertText = beginRequestAlertGeneric + realName + endRequestAlert + hardReturn;
        alert(alertText);
      }
    }
    if (!isIE3) 
    {
      var goToObj = (allAtOnce) ? firstMissingElt : formObj;
      if (goToObj.select) goToObj.select();
      if (goToObj.focus) goToObj.focus();
    }
    if (!allAtOnce) {return false};
  }
  if (allAtOnce) 
  {
    if (alertText != "") 
    {
      alert(alertText);
      return false;
    }
  }
  return true;
}

/*************************************************************************\
 * Use a confirmation dialog to perform a conditional hyperlink.
\*************************************************************************/

function decision(message, url)
{
  if (confirm(message)) location.href = url;
}

/*************************************************************************\
 * Format a numeric field to two decimal places.
\*************************************************************************/

function numTo2dpDecimal(field) 
{ 
  var tmp1 = fraction = whole = "";
  var dec = -1;
  var num = 0;

  num = field.value;
  num = "" + (Math.round(num * 100)/100);
  dec = num.indexOf(".");
  fraction = ((dec > 0) ? num.substring(dec,num.length) : ".00");
  if (fraction.length == 2) fraction += "0";
  whole = parseInt(num);

  num = whole + fraction;

  field.value = num;

  return true;
}

/*************************************************************************\
 * Helpers for opening new windows
\*************************************************************************/

function MM_openBrWindow(theURL,winName) 
{
  mywindow = window.open(theURL,winName,'scrollbars=yes,width=450,height=500,resizable=no');
  mywindow.focus();
}

function MM_openNewWindow(theURL,winName,width,height,resizable) 
{
  mywindow = window.open(theURL,winName,'scrollbars=yes,width='+width+',height='+height+',resizable='+resizable);
  mywindow.focus();
}

function MM_openNewWindowNoScroll(theURL,winName,width,height,resizable) 
{
  mywindow = window.open(theURL,winName,'scrollbars=no,width='+width+',height='+height+',resizable='+resizable);
  mywindow.focus();
}

function MM_openHelpWindow(theURL) 
{
  mywindow = window.open(theURL,'HELP','scrollbars=yes,width=500,height=300,resizable=yes');
  mywindow.focus();
}

/*************************************************************************\
 * Form focus helpers
\*************************************************************************/

function setFocus(target)
{
    if (target.select) target.select();
    if (target.focus) target.focus();
}

function setDefaultFocus(skip) {
  try {
    done = false;
    allForms = document.forms;
    if(allForms!=null && allForms.length>0) {
      for(n=0;n < allForms.length;n++) {
        if(done==false) {
          if(allForms[n]!=null && allForms[n].elements!=null) {
            allElements = allForms[n].elements;
            if(allElements!=null) {
              for(i=0;i < allElements.length;i++) {
                if(done==false) {
                  element = allElements[i];
                  if (element!=null && element.type!=null && element.enabled && (element.type.indexOf("text")!=-1 || element.type.indexOf("select")!=-1 || element.type.indexOf("radio")!=-1 || element.type.indexOf("checkbox")!=-1 ||  element.type.indexOf("password")!=-1)) {
                    if(n>=skip) {
                      element.focus();
                      done=true;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  } catch (exception) {
    //Do nothing as it isnt that important.
  }
  
}
    
/*************************************************************************\
 * Stops multiple clicking of buttons
\*************************************************************************/
    
var hitCount =0;
    
function checkFirstClick() {
    if(hitCount==0) {
        hitCount = 1;
        setTimeout("clearHitCount()",1000);
        return true;
    }
    return false;
}

function clearHitCount() {
    hitCount=0;
}


