/**
 *
 * Smart controls
 * Copyright (c) J2B 2000.
 * All rights reserved.
 *
 * USE: 
 *   add prepareForm(Form frm) to body onLoad event.
 *   add validateForm(Form frm)  to form's onSubmit event.
 *
 * @version 2.0
*/

var formValidatorMessages = [
/*  0 */	"Error in prepareForm function. Not a Form object.",
/*  1 */	"Error in validateForm function. Not a Form object.",
/*  2 */	"The field",
/*  3 */	"is mandatory",
/*  4 */	"has too long value",
/*  5 */	"Maximum length",
/*  6 */	"has too short value",
/*  7 */	"Minimum length",
/*  8 */	"Minimum value",
/*  9 */	"Maximum value",
/* 10 */	"You must enter correct INTEGER value into the field",
/* 11 */	"You must enter correct FLOATING POINT value into the field",
/* 12 */	"You must enter correct E-MAIL into the field",
/* 13 */	"field value must be specified",
/* 14 */	"Wrong value for field",
/* 15 */	"You must check an item for field",
/* 16 */	"You must enter correct DATE into the field",
/* 17 */	"You must enter correct RGB value into the field"
];

var __obj= new Object;

// form validation procedure
// NOTE: won't work in Netscape 4.x for unnamed forms because of formObj.attributes absense
function submitData(formObj, formAction, formTarget) {
	var isValid = false;

	// validate form elements
	isValid = validateForm(formObj);

	// run form validator if exists
	if(isValid && formObj.attributes && formObj.attributes["name"]
			&& eval("window.formValidator_" + formObj.attributes["name"].value)) {
		isValid = eval("formValidator_" + formObj.attributes["name"].value + "()");
	}

	// run form validator (alternative sintax) if exists
	if(isValid && formObj.onValidate) {
		isValid = eval("formObj.onValidate()");
	}

	// run page validator validator if exists
	if(isValid && eval("window.formValidator")) {
		isValid = eval("formValidator()");
	}

	// submit form if validation passed
	if(isValid) {
		// set form action if exists
		if(formAction) {
			formObj.action = formAction;
		}

		// set form target if exists
		if(formTarget) {
			formObj.target = formTarget;
		}

		formObj.submit();
	}

	// return false for using in <a href="" onClick="">...</a> tag
	return false;
}

function prepareForms() {
	for(var i = 0; i < document.forms.length; i++) {
		prepareForm(document.forms[i]);

		if(document.forms[i].onsubmit) {
			document.forms[i].onValidate = document.forms[i].onsubmit;
		}

		document.forms[i].onsubmit = new Function("return submitData(this);");
	}
}

function prepareForm(frm) {
   if ( !frm || !frm.elements ) { 
     alert(formValidatorMessages[0]); 
     return false; 
   }

   var firstElem=null;
   for(var i=0; i< frm.elements.length; i++ ) {
     str = frm.elements[i].onselect + "";
	 
	 if(str == "undefined" || str == null) {
		 str = "{" + frm.elements[i].onSelect + "}";
	 }

     if((p = str.indexOf("__")) != -1) {
        __obj = frm.elements[i];

        with(__obj) {
			eval("{" + str.substring(p));
		}

        //if ( firstElem == null ) firstElem = frm.elements[i];
     }
   }    
  //if ( firstElem != null ) firstElem.focus();
  //prepareFunction(frm);
  //__obj= new Object;
 }

 function prepareFunction(frm) {   
   for(var i=0; i< frm.elements.length; i++ ) {
       obj = frm.elements[i];   
     }     
 }
 
 function validateForm(frm) { 
   if ( !frm || !frm.elements ) {
     alert(formValidatorMessages[1]); 
     return false;
   }
 
   for(var i=0; i< frm.elements.length; i++ ) {
     obj = frm.elements[i];     

	if(obj.preCheck && !eval(obj.preCheck)) {
		continue;
	}

     if ( obj.notEmpty  || obj.mandatory) {
	   if((obj.type == "select" || obj.type == "select-one" || obj.type == "select-multiple")) {
	   	if(obj.selectedIndex < 0 || isEmptyString(obj.options[obj.selectedIndex].value)) {
         alert("'" + obj.title + "' " + formValidatorMessages[13] + ".");
		 setFocus(obj);
		 return false;
		}
	   } else if(obj.type == "radio" || obj.type == "checkbox") {
	   	var newObj = eval("obj.form." + obj.name);
	    if(objectCheckedIndexes(newObj).length == 0) {
         alert(formValidatorMessages[15] + " '" + obj.title + "'.");    
		 setFocus(obj);
		 return false;
		}
	   } else if ( isEmpty(obj) ) {
         if ( obj.mandatoryWarning ) alert(obj.mandatoryWarning);
         else alert(formValidatorMessages[2] + " '" + obj.title + "' " + formValidatorMessages[3] + ".");
         setFocus(obj);
         return false;
       }
     }     

     if ( obj.maxLength && obj.maxLength > 0 && !isEmpty(obj) && obj.value.length > obj.maxLength) {
	 	alert(formValidatorMessages[2] + " '" + obj.title + "' " + formValidatorMessages[4] + ".\n" + formValidatorMessages[5] + " = " + obj.maxLength + ".");
		setFocus(obj);
		return false;
     }     

     if ( obj.minLength && !isEmpty(obj) && obj.value.length < obj.minLength) {
	 	alert(formValidatorMessages[2] + " '" + obj.title + "' " + formValidatorMessages[6] + ".\n" + formValidatorMessages[7] + " = " + obj.minLength + ".");
        setFocus(obj);
        return false;
     }     

     if ( obj.utype == 'int' ){
       if ( !checkInteger(obj, obj.minValue, obj.maxValue) ) {
         addMsg="";
         if ( obj.minValue != null ) addMsg += "\n" + formValidatorMessages[8] + " = " + obj.minValue + ".";
         if ( obj.maxValue != null ) addMsg += "\n" + formValidatorMessages[9] + " = " + obj.maxValue + ".";

         alert(formValidatorMessages[10] + " '" + obj.title + "'. " + addMsg);
         setFocus(obj);
         return false;
       }
     }

     if ( obj.utype == 'float' ){
       if ( !checkFloat(obj, obj.minValue, obj.maxValue, obj.decimals) ) { 
         addMsg="";
         if ( obj.minValue != null ) addMsg += "\n" + formValidatorMessages[8] + " = " + obj.minValue + ".";
         if ( obj.maxValue != null ) addMsg += "\n" + formValidatorMessages[9] + " = " + obj.maxValue + ".";
         
         alert(formValidatorMessages[11] + " '" + obj.title + "'. " + addMsg);
         setFocus(obj);
         return false;
       }         
     }
     
    if ( obj.utype == 'email' && !checkEmail(obj) ){
        alert(formValidatorMessages[12] + " '" + obj.title + "'.");
        setFocus(obj);
        return false;
    }

    if ( obj.utype == 'date' && !checkDate(obj, obj.format) ){
        alert(formValidatorMessages[16] + " '" + obj.title + "'" + 
			(obj.format ? " (" + obj.format + ")." : "."));
        setFocus(obj);
        return false;
    }

    if ( obj.utype == 'rgb' && !checkRGB(obj) ){
        alert(formValidatorMessages[17] + " '" + obj.title + "'.");
        setFocus(obj);
        return false;
    }

    if ( obj.utype == 'regexp' && !checkRegExp(obj) ){
        alert(formValidatorMessages[14] + " '" + obj.title + "'.");
        setFocus(obj);
        return false;
    }

	if(obj.selectedIndexNonZero && obj.options && obj.selectedIndex == 0) {
		alert("'" + obj.title + "' " + formValidatorMessages[13] + ".");
        setFocus(obj);
        return false;
	}     

   	if(obj.postCheck && !eval(obj.postCheck)) {
		alert(formValidatorMessages[14] + " '" + obj.title + "'.");
        setFocus(obj);
        return false;
	}
   }  

   return true;
 }
 
function checkString(obj, minLength, maxLength) {
	if(minLength == null) minLength = 0;
	if(maxLength == null) maxLength = Number.POSITIVE_INFINITY;

	return isEmpty(obj) || (obj.value.length >= minLength &&
		obj.value.length <= maxLength);
}

// checkEmail (STRING s)
// 
// Email address must be of form a@b.c -- in other words:
// * there must be at least one character before the @
// * there must be at least one character before and after the .
// * the characters @ and . are both required

function checkEmail(obj) {
   var reEmail = /^.+\@.+\..+$/

   return isEmpty(obj) || reEmail.test(obj.value);
}

function checkInteger(obj, sign) {
	var s = obj ? obj.value.replace(',', '.') : null;
	var checkSign = sign ? true : false;
		
	if(isEmpty(obj)) return true;
	
	ret = !isNaN(s) && (s.indexOf('.') == -1) &&
		(checkSign ? (sign ? eval(s) >= 0 : eval(s) <= 0) : true);

	return ret;
}

function checkInteger(obj, minValue, maxValue) {
	var s = obj ? obj.value.replace(',', '.') : null;
		
	if(isEmpty(obj)) return true;
	if(minValue == null) minValue = Number.NEGATIVE_INFINITY;
	if(maxValue == null) maxValue = Number.POSITIVE_INFINITY;

	ret = !isNaN(s) && s.indexOf('.') == -1 && eval(s) >= minValue && eval(s) <= maxValue;

	return ret;
}

function checkFloat(obj, sign) {
	var s = obj ? obj.value.replace(',', '.') : null;
	var checkSign = sign ? true : false;
	
	if(isEmpty(obj)) return true;
	
	ret = !isNaN(s) &&
		(checkSign ? (sign ? eval(s) >= 0 : eval(s) <= 0) : true);

	return ret;
}

function checkFloat(obj, minValue, maxValue, decimals) {
	var s = obj ? trim(obj.value).replace(',', '.') : null;

	if(isEmpty(obj)) return true;
	if(minValue == null) minValue = Number.NEGATIVE_INFINITY;
	if(maxValue == null) maxValue = Number.POSITIVE_INFINITY;
	
	ret = !isNaN(s) && eval(s) >= minValue && eval(s) <= maxValue &&
		(decimals ? s.lastIndexOf('.') == -1 ||
		s.length - s.lastIndexOf('.') - 1 <= decimals : true);

	return ret;
}

function checkDate(obj, format) {
	// convert Java date format
	var fmt = convertFormat(format ? format : "yyyy-mm-dd hh:min:ss");

	return isEmpty(obj) || (typeof buildDate(obj.value, fmt) == "object");
}

function checkRGB(obj) {
	if(isEmpty(obj)) return true;
	
	idx = obj.value.indexOf("#");
	
	if(idx == 0)
		s = obj.value.substr(1);
	else
		s = obj.value;

	if(s.length != 6 || "" + parseInt(s, 16) == "NaN")
		return false;
	else
		return true;
}

function checkRegExp(obj) {
   var regexp = new RegExp(obj.pattern, "g");

   return isEmpty(obj) || regexp.test(obj.value);
}

/*
utility functions
*/
function trim(s) {
	var i, j;
	for (i = 0; i < s.length && s.charAt(i) == " "; i++);
	for (j = s.length-1; j >= 0 && s.charAt(j) == " "; j--);

	if(i == s.length)
		return "";
	else
		return s.substring(i, j+1);
}

function isEmpty(obj) {
	return !obj || !obj.value || trim(obj.value) == "";
}

function isEmptyString(s) {
	return !s || trim(s) == "";
}

function isLeapYear(year) {
	return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}
	
function roundVal(val, scale) {
	scale = scale * Math.pow(10, scale);
	val = Math.round(val * scale) / scale;

	return val;
}

/*
* Parse functions
*/
function getFloat(val) {
	if(!val || val == isNaN(val))
		ret = 0;
	else
		ret = eval(val.replace(',', '.'));
	
	return ret;
}

function getInt(val) {
	if(!val || val == isNaN(val))
		ret = 0;
	else
		ret = eval(val);
	
	return ret;
}

/*
* RADIO & CHECKBOX routines
*/
function toggleObjectState(obj, idx, checked) {
	if(obj.length) {
		if(idx) {
			if(idx < obj.length) obj[idx].checked = checked;
		} else {
			// change state of ALL object items
			for(var i = 0; i < obj.length; i++) {
				obj[i].checked = checked;
			}
		}
	} else {
		obj.checked = checked;
	}
}

function checkObject(obj, idx) {
	toggleObjectState(obj, idx, true);
}

function unCheckObject(obj, idx) {
	toggleObjectState(obj, idx, false);
}

function objectCheckedIndexes(obj) {
	var idx = new Array();
	var j = 0;

	if(!obj.length) {
		if(obj.checked) idx[j] = 0;
	} else {
		for(i = 0; i < obj.length; i++) {
			if(obj[i].checked) idx[j++] = i;
		}
	}
	
	return idx;
}

function objectCheckedValues(obj) {
	var idx = objectCheckedIndexes(obj);

	if(obj.length) {
		for(var i = 0; i < idx.length; i++) {
			idx[i] = obj[idx[i]].value;
		}
	} else if(idx.length > 0) {
		idx[0] = obj.value;
	}
	
	return idx;
}

function radioCheckedIndex(obj) {
	var idx = objectCheckedIndexes(obj);

	return idx.length > 0 ? idx[0] : -1;
}

function radioCheckedValue(obj) {
	var val = objectCheckedValues(obj);
	
	return val.length > 0 ? val[0] : null;
}

function setFocus(obj, idx) {
	if(obj) {
		if(obj.type == "checkbox" && obj.length > 1) {
			if(!obj[idx ? idx : 0].disabled) {
				obj[idx ? idx : 0].focus();
			}
		} else {
			if(!obj.disabled) {
				obj.focus();
			}
		}
	}
}
	
function getElements(frm, mask) {
	var elements = new Array(0);
	
	for(var i = 0; i < frm.elements.length; i++) {
		var el = frm.elements[i];
		
		if(el.name.search(mask) != -1) {
			elements[elements.length] = el;
		}
	}
	
	return elements;
}

function elementsCount(frm, mask, countEmpty) {
	var elements = getElements(frm, mask);
	var counter = 0;

	if(!countEmpty) {
		for(var i = 0; i < elements.length; i++) {
			if(!isEmpty(elements[i])) {
				counter++;
			}
		}
	} else {
		counter = elements.length;
	}
	
	return counter;
}

/*
* Navigator test functions
*/
function isIE() {
	return navigatorName().toLowerCase().indexOf("microsoft internet explorer") != -1;
}

function isNN() {
	return navigatorName().toLowerCase().indexOf("netscape") != -1;
}

function navigatorName() {
	return navigator.appName;
}

function navigatorVersion() {
	return parseFloat(navigator.appVersion);
}

/* Date validation functions */
/* 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".


function convertFormat(fmt) {
	var aSrc = ["MMMM", "yyyy", "MMM", "MM", "dd", "yy", "HH", "mm", "ss", "M", "d", "H", "m", "s"];
	var aDst = ["%month", "%yyyy", "%mon", "%mm", "%dd", "%y", "%hh", "%mins", "%ss", "%m", "%d", "%h", "%min", "%s"];
	var exp = "'.*'";

	for(var i = 0; i < aSrc.length; i++) {
		exp += "|" + aSrc[i];
	}

	return fmt.replace(new RegExp(exp, "g"), 
		function(str) {
			for(var i = 0; i < aSrc.length; i++) {
				if(aSrc[i] == str) {
					return aDst[i];
				}
			}

			return str;
		});
}

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']=/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/
monPatArr['Mon']=/Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/
monPatArr['MON']=/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']=/^january|february|march|april|may|june|july|august|september|october|november|december/i
monthPatArr['Month']=/^January|February|March|April|May|June|July|August|September|October|November|December/
monthPatArr['MONTH']=/^JANUARY|FEBRUARY|MARCH|APRIL|MAY|JUNE|JULY|AUGUST|SEPTEMBER|OCTOBER|NOVEMBER|DECEMBER/
monthPatArr['month_strict']=/^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 dateCheck function, which returns true if a given date is
 valid,and false otherwise (and reports an error in the false case):

 function dateCheck(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.

//return "\"" + dateStr + "\" does not conform to the expected format: " + formatStr;
return false;
   }
}

// 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 + "\".";
return false;
}
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) + "\".";
return false;
}
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.";
return false;
   }
}
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.";
return false;
}
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.";
return false;
}
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 + ".";
return false;
}
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) + "\".";
return false;
}

// 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.";
return false;
}

// 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;
return false;
}

// Make sure all components are in the right ranges.

if (intMonth < 1 || intMonth > 12) {
//return "Month must be between 1 and 12.";
return false;
}
if (intDay < 1 || intDay > 31) {
//return "Day must be between 1 and 31.";
return false;
}

// 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!";
return false;
}

// 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 + 
return false;
" 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.";
return false;
   }
}
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.";
return false;
   }
}

// 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.";
return false;
}
if (intSec < 0 || intSec > 59) {
//return "Second must be between 0 and 59.";
return false;
}
return new Date(intYear,intMonth-1,intDay,intHour,intMin,intSec);
}