//Javascript name: My Date Time Picker
//Date created: 16-Nov-2003 23:19
//Scripter: TengYong Ng
//Website: http://www.rainforestnet.com
//Copyright (c) 2003 TengYong Ng
//FileName: DateTimePicker.js
//Version: 0.8
//Contact: contact@rainforestnet.com
// Note: Permission given to use this script in ANY kind of applications if
//       header lines are left unchanged.

// External dependencies: none!

//Global variables and constants
 var dateLanguage = {};
 dateLanguage.monthNames = {
                0 : "January",
                1 : "February",
                2 : "March",
                3 : "April",
                4 : "May",
                5 : "June",
                6 : "July",
                7 : "August",
                8 : "September",
                9 : "October",
                10 : "November",
                11 : "December",
                12 : ""
             };
 dateLanguage.daysOfWeek = {
                0 : "",
                1 : "Su",
                2 : "Mo",
                3 : "Tu",
                4 : "We",
                5 : "Th",
                6 : "Fr",
                7 : "Sa"
             };
var dtToday = new Date(); //Today's date
var Cal; //will be the Calendar instance
var defaultDF = new DateFormat("MM/dd/yyyy",dateLanguage.daysOfWeek,dateLanguage.monthNames);
var minuteInMillis = 1000 * 60;
var hourInMillis = minuteInMillis * 60;
var dayInMillis = hourInMillis * 24;
function showTrace(fn) { alert(fn + "\n\nCALLED BY\n\n" + fn.caller); }
var trace = false; 

//Configurable parameters
var ShowLongMonth=true;//Show long month name in Calendar header. example: "January".
var ShowMonthYear=true;//Show Month and Year in Calendar header.

//end Configurable parameters
//end Global variable
//Create and display the calendar popup, setting it to the date found in the textfield
//window is of type CalendarWindow and is required
//pFormat is of type DateFormat and is optional (default is english MM/DD/YYYY)
//pDateField is an input field for getting and setting the date (optional)
function NewCal(pWindow, pFormat, pDateField, e) {
	//hide if visible
	if (!!Cal && Cal.window && Cal.textField == pDateField && Cal.window.winCal.width > 1) {
		Cal.window.hide();
		return false;
	}

	if (!e) { //grab IE event reference if missing
		e = window.event;
	}

    var dateObject = dtToday;
    if (pFormat && pDateField) {
        dateObject = pFormat.parseDate(pDateField.value);
    }
    if (dateObject === null) {
        dateObject = dtToday;
    }
    Cal = new Calendar(dateObject, pFormat);
    Cal.window = pWindow;
    if (!pDateField) {
        pDateField = null;
    }
    Cal.textField = pDateField; //Null is allowed
    RenderCal(Cal);
	Cal.window.show().move(e);
	return false;
}

//Generate the html for the calendar popup
function RenderCal(calObj) {
    //Close the window if it is opened so that show() will be consistent
    var i, j;
    var selectString;
    var vDayCount=0;

	//build HTML segments of calendar

    var vCalHeader="<table id=\"CalTable\" border=0 cellpadding=0 cellspacing=3 width='100%' align=\"center\" valign=\"top\">\n";
	//Close stripe
	vCalHeader+="<tr>\n<td colspan='7'>";
	vCalHeader+="<div id=\"closeStripe\"><a href=\"#\" onclick=\"parent.Cal.window.hide(); return false;\">close</a></div>";
	vCalHeader+="</td></tr>";
    //Month Selector
    vCalHeader+="<tr>\n<td colspan='7'><table border=0 width='100%' cellpadding=0 cellspacing=0><tr>";
    vCalHeader+="<td align='left' width='70%'>\n";
    vCalHeader+="<select id=\"MonthSelector\" name=\"MonthSelector\" onChange=\"parent.Cal.SwitchMth(this.selectedIndex); parent.RenderCal(parent.Cal);\">\n";
    for (i=0;i<12;i++) {
        if (i==Cal.Month) {
            selectString="Selected";
        } else {
            selectString="";
        }
        vCalHeader += "<option " + selectString + " value >" + Cal.Format.monthName[i] + "\n";
    }
    vCalHeader+="</select></td>";
    //year selector
    vCalHeader+="<td align='right' width='30%'>\n";
    vCalHeader+="<select id=\"YearSelector\" name=\"YearSelector\" onChange=\"parent.Cal.setYear(this.selectedIndex); parent.RenderCal(parent.Cal);\">\n";
    var latestYear = Cal.Format.endDate.getFullYear();
    var earliestYear = Cal.Format.startDate.getFullYear();
    for (i=earliestYear;i<=latestYear;i++) {
        if (i==Cal.Year) {
            selectString="Selected";
        } else {
            selectString="";
        }
        vCalHeader+="<option "+selectString+" value >"+i+"\n";
    }
    vCalHeader+="</select></td>";

    vCalHeader+="</tr></table></td></tr>";
    var monthIncr;
    var monthDecr;
    //Calendar header shows Month and Year
    if (ShowMonthYear) {
	    monthIncr = "<a href=\"#\" onclick=\"parent.Cal.incrMonth(); parent.RenderCal(parent.Cal); return false;\"><img align='right' src='/images/arrowRight.png'></a>";
	    //Do not allow years past latest date
	    if (Cal.Format.endDate !== null && Cal.Year == Cal.Format.endDate.getFullYear() && Cal.Format.endDate.getMonth() <= Cal.Month) {
	        monthIncr = "<img align='right' src='/images/arrowRightDisabled.png'>";
	    }
	    monthDecr = "<a id=\"monthDecr\" href=\"#\" onclick=\"parent.Cal.decrMonth(); parent.RenderCal(parent.Cal); return false;\"><img align='left' src='/images/arrow.png'></a>";
	    //Do not allow years past latest date
	    if (Cal.Format.startDate !== null && Cal.Year == Cal.Format.startDate.getFullYear()&& Cal.Format.startDate.getMonth() == Cal.Month) {
	        monthDecr = "<img align='left' src='/images/arrowDisabled.png'>";
	    }
        vCalHeader+="<tr><td colspan='7'>";
        vCalHeader+="<table border=0 width='100%' cellpadding=0 cellspacing=0><tr>";
        vCalHeader+="<td class='head2' align='left'>"+monthDecr+"</td>";
        vCalHeader+="<td class='head2'><b>"+Cal.GetMonthName(ShowLongMonth)+" "+Cal.Year+"</b></td>";
        vCalHeader+="<td class='head2' align='right'>"+monthIncr+"</td>";
        vCalHeader+="</tr></table></td></tr>\n";
    }
    //Weekday header cells
    vCalHeader+="<tr>";
    for (i=1;i<8;i++) {
        vCalHeader+="<td class='head1' width='14.3%'>"+Cal.Format.weekDayName[i]+"</td>";
    }
    vCalHeader+="</tr>";

    //Calendar day cells
    var calDate=new Date(Cal.Year,Cal.Month);
    calDate.setDate(1);
    var vFirstDay=calDate.getDay();
    var vCalData="<tr>";
    var flag = 0;
    for (i=0;i<vFirstDay;i++) {
        vCalData=vCalData+GenCell(null, null, "head1", flag);
        vDayCount=vDayCount+1;
    }
    var strCell;
    var todayFlag = false;
    for (j=1;j<=Cal.GetMonDays();j++) {
        calDate.setDate(j);
        vDayCount=vDayCount+1;
        if (Cal.Format.endDate !== null && calDate.getTime() > Cal.Format.endDate.getTime()) {
           flag = 0;
        } 
		else if (Cal.Format.startDate !== null && calDate.getTime() < Cal.Format.startDate.getTime()){
           flag = 0;
        }
		else { 
           flag = 1;
        }
        todayFlag = false;
        if ((j==dtToday.getDate())&&(Cal.Month==dtToday.getMonth())&&(Cal.Year==dtToday.getFullYear())) {
           todayFlag = true;
        }
        if (j==Cal.Date  && Cal.Month == Cal.origMonth && Cal.Year == Cal.origYear) {
                flag = 2;
        }
        strCell=GenCell(j,todayFlag,"div1",flag);
        vCalData=vCalData+strCell;

        if ((vDayCount%7 === 0)&&(j<Cal.GetMonDays())) {
           vCalData=vCalData+"</tr>\n<tr>";
        }
    }
	
	// write HTML segments of calendar
    var docCal = calObj.window.getDocument();
    docCal.open();
    docCal.writeln("<html><head><title>Calendar</title>");
    docCal.writeln("<link rel=\"stylesheet\" href=\"/stylesheets/calendar.css\" type=\"text/css\">");
    docCal.writeln("</head><body class='framebody' onload='parent.Cal.window.adjustSize();'><form name='Calendar'>");
    docCal.writeln(vCalHeader); //docCal.write(vCalHeader);
    docCal.writeln(vCalData);
    docCal.writeln("\n</tr></table>");
    docCal.writeln("</form></body></html>");
    docCal.close();
}

//Generate the html for a particular date in the calendar popup (table cell with value)
function GenCell(pValue,pHighLight,classID,linkFlag) {
    var PValue;
    var PCellStr;
    var data;
    var vDIVend;
    var vDIVstart;

    if (pValue === null) {
        PValue="";
    } else {
        PValue=pValue;
    }
    var displayValue = PValue;
    if ((pHighLight !== null)&&(pHighLight)) {
        classID=classID + " today";
    }    
    if (linkFlag === 2) {
       vDIVstart = "<div>";
       vDIVend = "</div>";
    
    } else {
       vDIVstart = "";
       vDIVend = "";
    }

   // if (linkFlag === 0) {
        data = PValue;
   // } else {
   //     data = "<a href=\"javascript:parent.Cal.formatSelectionDate('"+PValue+"');parent.Cal.window.hide();\">"+displayValue+"</a>";
   // }
    PCellStr="<td class=\""+classID+"\">" +vDIVstart +  data + vDIVend + "</td>";
    return PCellStr;
}


/** 
 * DateRangeFields class
 */

 //Keeps track of a set of DateRangePairs
function DateRangeFields() {
   this.pair = [];
}

//register a pair of fields
DateRangeFields.prototype.addPair = function addPair(startDateField,endDateField,dateFormat,maxDays) {
   var drp = new DateRangePair(startDateField,endDateField,dateFormat,maxDays);
   this.pair[this.pair.length] = drp;
    if (startDateField) {
        dateFormat.verifyDate(startDateField);
    }
    if (endDateField) {
        dateFormat.verifyDate(endDateField);
    }
    return drp;
};

//set all the fields to this one and check the other end
DateRangeFields.prototype.startChanged = function startChanged(changedField) {
    var i;
    var j;
    for(i=0; i < this.pair.length; i++) {
        if (this.pair[i].startField === changedField) {
           if (this.pair[i].df.verifyDate(changedField)){
               this.pair[i].restrictEndDate();
               break;
           } else {
               return false;
           }
        }
    }
    for(j=0; j < this.pair.length; j++) {
       if (i != j) { 
	       if (this.pair[j].startField) {
	           this.pair[j].startField.value = changedField.value;
	           this.pair[j].df.verifyDate(this.pair[j].startField);
	           this.pair[j].restrictEndDate();
	       } else {
	           //try seeding it with the enddate that goes with the field that changed
	           if (this.pair[j].endField && this.pair[i].endField) {
	              this.pair[j].endField.value = this.pair[i].endField.value;
	              this.pair[j].df.verifyDate(this.pair[j].endField);
	              this.pair[j].df.restrictDateWidget(this.pair[j].endField);
	           }
	       }
       }
    }
    return true;
};

//set all the fields to this one and check the other end
DateRangeFields.prototype.endChanged = function endChanged(changedField) {
    var i;
    var j;
    for(i=0; i < this.pair.length; i++) {
        if (this.pair[i].endField === changedField) {
           if (this.pair[i].df.verifyDate(changedField)){
               this.pair[i].restrictStartDate();
               break;
           } else {
               return false;
           }
        }
    }
    for(j=0; j < this.pair.length; j++) {
       if (i != j) { 
	       if (this.pair[j].endField) {
	           this.pair[j].endField.value = changedField.value;
	           this.pair[j].df.verifyDate(this.pair[j].endField);
	           this.pair[j].restrictStartDate();
	       }
       }
    }
    return true;
};


//verify that the dates are valid and revert them if they are not
DateRangeFields.prototype.verifyChangedDate = function verifyChangedDate(startDateTextField, endDateTextField) {
   if (endDateTextField) {
       if (startDateTextField) { 
		   if (startDateTextField.value == startDateTextField.revertValue) {
		      return this.endChanged(endDateTextField);
		   } else if (endDateTextField.value == endDateTextField.revertValue) {
		      return this.startChanged(startDateTextField);
		   }
	   } else {
	      return this.endChanged(endDateTextField);
	   }
   } else {
      return this.startChanged(startDateTextField);
   }
   return false;
};

/* 
 * End of DateRangeFields class
 **/

/** 
 * DateRangePair class
 */

 //Two textfields that represent a start date and an ending date
//They startDate is kept not later than the endDate
//The date are checked that they span no more than the supplied maxDayRange
function DateRangePair(startDate, endDate, dateFormat, maxDayRange) {
   this.startField = startDate;
   this.endField = endDate;
   this.df = dateFormat;
   this.maxMillis = maxDayRange * dayInMillis;
}

//The start date was tweaked - adjust the other date to be valid with it
DateRangePair.prototype.restrictEndDate = function restrictEndDate() {
   var maxRange;
   var picker1;
   var picker2;
   var time1;
   var time2;
   var offset;
   var range;
   var testDate;
   if (this.endField) {
        //Make sure the changed date is not past the restricted date
        this.df.restrictDateWidget(this.startField);
        maxRange = this.maxMillis;
        picker1 = this.df.parseDate(this.startField.value);
        picker2 = this.df.parseDate(this.endField.value);
        time1 = picker1.getTime();
        time2 = picker2.getTime();
        offset = picker1.getTimezoneOffset() - picker2.getTimezoneOffset();

        if (time1 > time2) {
            //Change the second date to match this one
            picker2 = picker1;
        } else {
            // calculate the range and consider daylight saving time.
            range = time2 - time1 + dayInMillis;         // [t1, t2]
            range += offset * minuteInMillis;

            // enforce range limit
            if (range > maxRange) {
                time2 = time1 + maxRange - dayInMillis;
                testDate = new Date(time2);
                offset = picker1.getTimezoneOffset() - testDate.getTimezoneOffset();
                time2 -= offset * minuteInMillis;
                picker2 = new Date(time2);
            }
        }
        this.endField.value = this.df.formatDate(picker2);
        this.endField.revertValue = this.endField.value;
    }
    return false;
};

//The end date was tweaked - adjust the other date to be valid with it
DateRangePair.prototype.restrictStartDate = function restrictStartDate() {
    var maxRange;
    var picker1;
    var picker2;
    var time1;
    var time2;
    var offset;
    var range;
    var testDate;
    if (this.startField) {
        //Make sure the changed date is not past the restricted date
        this.df.restrictDateWidget(this.endField);
        
        maxRange = this.maxMillis;
        picker1 = this.df.parseDate(this.startField.value);
        picker2 = this.df.parseDate(this.endField.value);
        time1 = picker1.getTime();
        time2 = picker2.getTime();
        offset = picker1.getTimezoneOffset() - picker2.getTimezoneOffset();
        
        if (time1 > time2) {
            //Set the other date to match this one - (the best we can do in this situation)
            picker1 = picker2;
        } else {
            // calculate the range and consider daylight saving time.
            range = time2 - time1 + dayInMillis;         // [t1, t2]
            range += offset * minuteInMillis;

            // enforce range limit
            if (range > maxRange) {
                time1 = time2 - maxRange + dayInMillis;
                testDate = new Date(time1);
                offset = testDate.getTimezoneOffset() - picker2.getTimezoneOffset();
                time1 += offset * minuteInMillis;
                picker1 = new Date(time1);
            }
        }
        this.startField.value = this.df.formatDate(picker1);
        this.startField.revertValue = this.startField.value;
    }
    return false;
};

/* 
 * End of DateRangePair class
 **/

/** 
 * Calendar class
 */

//Create a Calendar object for the supplied Date and DateFormat
function Calendar(pDate, pFormat) {
    //Properties
    if (!pDate) {
       pDate = dtToday;
    }
    if (!pFormat) {
        pFormat = new DateFormat();
    }
    this.Date=pDate.getDate();//selected day of Month
    this.Month=pDate.getMonth();//selected month number (0 based)
    this.Year=pDate.getFullYear();//selected year in 4 digits
    this.Format = pFormat;
    this.origYear = this.Year;
    this.origMonth = this.Month;
}

//Format the date for use by this calendar's input text field
Calendar.prototype.formatSelectionDate = function formatSelectionDate(day) {
    this.Date = day;
    if (this.textField) {
	    this.textField.value = this.Format.formatDateFromMonthDayYear(this.Month+1,day,this.Year);
	    this.textField.onchange();
    }
};

//Return the 0 based month name for the currently set month
Calendar.prototype.getMonthIndex = function getMonthIndex(shortMonthName) {
    for (var i=0;i<12;i++) {
        if (this.Format.monthName[i].substring(0,3).toUpperCase()==shortMonthName.toUpperCase()) {
            return i;
        }
    }
};

//Increment the year displayed in the Calendar popup
Calendar.prototype.incrYear = function incrYear() {
    this.Year++;
};

//Decrement the year displayed in the Calendar popup
Calendar.prototype.decrYear = function decrYear() {
    this.Year--;
};

//Increment the month that is displayed in the Calendar popup
Calendar.prototype.incrMonth = function incrMonth() {
    if (this.Month === 11) {
        this.incrYear();
        this.Month=0;
    } else {
        this.Month++;
    }
};

//Decrement the month that is displayed in the Calendar popup
Calendar.prototype.decrMonth = function decrMonth() {
    if (this.Month===0) {
        this.decrYear();
        this.Month=11;
    } else {
        this.Month--;
    }
};

//Change the Month to display in the Calendar popup
Calendar.prototype.SwitchMth = function SwitchMth(intMth) {
    this.Month=intMth;
};

//Change the Year to display in the Calendar popup
Calendar.prototype.setYear = function setYear(selIndex) {
    var earliestYear = Cal.Format.startDate.getFullYear();
    this.Year=earliestYear + selIndex;
};

//Return the name of the month string for the supplied month subscript
Calendar.prototype.GetMonthName = function GetMonthName(IsLong) {
    var Month=this.Format.monthName[this.Month];
    if (IsLong) {
        return Month;
    } else {
        return Month.substring(0,3);
    }
};

//Get number of days in a month
Calendar.prototype.GetMonDays = function GetMonDays() {
    return DateFormat.getMonthDays(this.Month,this.Year); 
};

/*
 * End of Calendar class
 **/

/**
 * DateFormat class
 */

//Create a DateFormat using the supplied date pattern and arrays for names of the days of the week and months
function DateFormat(patternString, daysOfWeek, monthNames) {
   if (!patternString) {
        patternString = "MM/dd/yyyy";
   } 
   if (!daysOfWeek){
       daysOfWeek = { 0: "", 1: "Su", 2: "Mo", 3: "Tu", 4: "We", 5: "Th", 6: "Fr", 7: "Sa"};
   }
   if (!monthNames) {
       monthNames = {0: "January", 1: "February", 2: "March", 3: "April", 4: "May", 5: "June", 6: "July", 7: "August", 8: "September", 9: "October", 10: "November", 11: "December"};
   }
   this.pattern = patternString;
   this.dayPos = patternString.indexOf('dd');
   this.monthPos = patternString.indexOf('MM');
   this.yearPos = patternString.indexOf('yyyy');
   this.badFormatMsg = "{1} is not a valid date of format {0}";
   this.startDate = null;
   this.endDate = null;
   this.monthName = monthNames;
   this.weekDayName = daysOfWeek;
   
   var separatorPos = this.monthPos - 1;
   if (separatorPos < 0) {
      separatorPos = this.dayPos - 1;
   }
   if(this.dayPos < 0 || this.monthPos < 0 || this.yearPos < 0 || separatorPos < 0){
      throw new Error("Date Format " + patternString + " is invalid");
   }
   this.separator = patternString.substring(separatorPos,separatorPos+1);
}

//Show an error message when the date string cannot be parsed
//Expects a placeholder of '{1}' for the string that could not be parsed, but does not require it
// A placeholder of '{0}' will display the date pattern.
DateFormat.prototype.showBadFormatAlert = function showBadFormatAlert(badDateString) {
   var msg = this.badFormatMsg;
   var placeHolderIndex = msg.indexOf("{0}");
   if (placeHolderIndex >= 0) {
       msg = msg.substring(0,placeHolderIndex) + '"' + this.pattern + '"'+
             msg.substring(placeHolderIndex + 3,msg.length);
   }
   placeHolderIndex = this.badFormatMsg.indexOf("{1}");
   if (placeHolderIndex >=0) {
       msg = msg.substring(0,placeHolderIndex) + '"' + badDateString + '"'+
             msg.substring(placeHolderIndex + 3,msg.length);
   }
   alert(msg);
};

//Verify that the text fields date is readable. Reset it to its previous value if it is not
DateFormat.prototype.verifyDate = function verifyDate(dateWidget) {
        var exDate;
        var checkedDate;
    if (dateWidget) {
        exDate = dateWidget.value;
        checkedDate = this.normalizeDate(exDate);
        if (checkedDate === null) {
            dateWidget.value = dateWidget.revertValue;
            this.showBadFormatAlert(exDate);
        } else {
           dateWidget.value = checkedDate;
           this.restrictDateWidget(dateWidget);
           return true;
        }
    } else {
       throw new Error("verifyDate called without a parameter");
    }
    return false;
};

//Ensure that the date is within the acceptable date range
//When a date falls out of the the date range, change the date to closest end of the range
DateFormat.prototype.restrictDateWidget = function restrictDateWidget(widget) {
    var currDate = this.parseDate(widget.value);
    if (currDate === null) {
        this.showBadFormatAlert(widget.value);
        return false;
    }
    if (this.endDate && currDate.getTime() > this.endDate.getTime()) {
        widget.value = this.formatDate(this.endDate);
    } else if (this.startDate && currDate.getTime() < this.startDate.getTime()) {
        widget.value = this.formatDate(this.startDate);
    }
    widget.revertValue = widget.value;
};

//Set the allowable range of dates that may be formatted
DateFormat.prototype.setDateRange = function setDateRange(earliestDate,latestDate) {
    if (earliestDate !== undefined){
        if (latestDate === undefined) {
            this.startDate = earliestDate;
        } 
        else if (earliestDate !== null && latestDate !== null) {
	       if (latestDate.getTime() > earliestDate.getTime()){
	           this.startDate = earliestDate;
	           this.endDate = latestDate;
	       } else {
	           this.startDate = latestDate;
	           this.endDate = earliestDate;
	       }
	   } else {
           this.startDate = earliestDate;
           this.endDate = latestDate;
       }  
    }
};

//Set the message text to use for the alert displayed in the showBadFormatAlert function
//Expects a placeholder of '{1}' for the string that could not be parsed, but does not require it
// A placeholder of '{0}' will display the date pattern.
DateFormat.prototype.setErrorMessageText = function setErrorMessageText(text) {
    this.badFormatMsg = text;
};

//Returns a dateString that matches the pattern
//handles single digit months an days and some wrong date separators
DateFormat.prototype.normalizeDate = function normalizeDate(exDate) {
    var separator1;//Index of Date Separator 1
    var separator2;//Index of Date Separator 2
    var strMonth;
    var strDate;
    var strYear;
    var intMonth;
    var YearPattern;
    //Find the date separators
    var separator = this.separator;
    //When the pattern's separator cannot be found,
    //Look for dashes and slashes as separators
    separator1=exDate.indexOf(separator,0);
    if (separator1 < 0) {
        separator = "-";
        separator1=exDate.indexOf(separator,0);
        if (separator1 < 0) {
            separator = "/";
            separator1=exDate.indexOf(separator,0);
        }
    }
    separator2=exDate.indexOf(separator,(parseInt(separator1,10)+1));
    var ddIndex = this.dayPos;
    var ddEnd = ddIndex + 2;
    var mmIndex = this.monthPos;
    var mmEnd = mmIndex + 2;
    var yyIndex = this.yearPos;
    var yyEnd = yyIndex + 4;
    var rc = true;
    if (ddIndex === 0) {
       ddEnd = separator1;
    } else if (this.dayPos > this.monthPos && this.dayPos > this.yearPos) {
       ddIndex = separator2 + 1;
       ddEnd = exDate.length;
    } else {
       ddIndex = separator1+ 1;
       ddEnd = separator2;
    }
    if (mmIndex === 0) {
       mmEnd = separator1;
    } else if (mmIndex > this.dayPos && this.monthPos > this.yearPos) {
       mmIndex = separator2+1;
       mmEnd = exDate.length;
    } else {
       mmIndex = separator1 + 1;
       mmEnd = separator2;
    }
    if (yyIndex === 0) {
       yyEnd = separator1;
    } else if (this.yearPos > this.dayPos && this.yearPos > this.monthPos) {
       yyIndex = separator2+1;
       yyEnd = exDate.length;
    } else {
       //alert("Date Format " + this.pattern + " has year in the middle??");
       rc = false;
    }
    strMonth=exDate.substring(mmIndex,mmEnd);
    strDate=exDate.substring(ddIndex,ddEnd);
    if (strMonth.length === 1) {
        strMonth = "0" + strMonth;
    }
    if (strDate.length === 1) {
        strDate = "0" + strDate;
    }
    if (isNaN(strMonth)) {
        rc  = false;
    } else {
        intMonth=parseInt(strMonth,10)-1;
	    if (intMonth < 0 || intMonth >= 12) {
	        rc = false;
	    }
    }
    strYear=exDate.substring(yyIndex,yyEnd);
    var intYear;
    YearPattern=/^\d{4}$/;
    if (rc === true) {
	    if (YearPattern.test(strYear)){
	        intYear=parseInt(strYear,10);
	        //end parse month
	        //parse Date
	        if (!((parseInt(strDate,10)<=DateFormat.getMonthDays(intMonth,intYear)) &&
	              (parseInt(strDate,10)>=1))){
	            //alert("Day out of range for month " +  strMonth + "/" +strYear);
	            rc = false;
	        }
	    } else {
	        //alert("YearPattern test failed:" +  strYear);
	        rc = false;
	    }
    }
    //end parse Date
    //parse year
    //end parse year
    if (rc === true) {
        return this.formatDateFromMonthDayYear(strMonth, strDate, strYear);
    }
	else {
        return null;
    }
};

//Return a properly formatted string for the supplied date object
DateFormat.prototype.formatDate = function formatDate(dateObject) {
   var m = DateFormat.formatTwoDigitNumber(dateObject.getMonth()+1);
   var d = DateFormat.formatTwoDigitNumber(dateObject.getDate());
   return this.formatDateFromMonthDayYear(m,d,dateObject.getFullYear());
};

//Return a formatted date string from the supplied month, day and year.
// Month is 1 based rather than the Date objects 0 based month.
DateFormat.prototype.formatDateFromMonthDayYear = function formatDateFromMonthDayYear(month,day,year){
   month = DateFormat.formatTwoDigitNumber(month);
   day = DateFormat.formatTwoDigitNumber(day);
   if (this.yearPos < this.dayPos && this.yearPos < this.monthPos) {
      if (this.monthPos < this.dayPos) {
         return (year + this.separator + month + this.separator + day);
      }
	  else {
         return (year + this.separator + day + this.separator + month);
      }
   } else {
      if (this.monthPos < this.dayPos) {
         return (month + this.separator + day + this.separator + year);
      }
	  else {
         return (day + this.separator + month + this.separator + year);
      }
   }
};

//Parse the supplied string into its associated date object. If cannot parse, return null
DateFormat.prototype.parseDate = function parseDate(dateString) {
    dateString = this.normalizeDate(dateString);
    var ddEnd;
    var mmEnd;
    var yyEnd;
    var day;
    var month;
    var year;
    if (dateString) {
       ddEnd = this.dayPos + 2;
       mmEnd = this.monthPos + 2;
       yyEnd = this.yearPos + 4;
       day = dateString.substring(this.dayPos,ddEnd);
       month = dateString.substring(this.monthPos,mmEnd);
       year = dateString.substring(this.yearPos,yyEnd);
       return new Date(year,month-1,day);
    }
    return null;
};

//Return a two character number string by appending a leading zero when necessary
DateFormat.formatTwoDigitNumber = function formatTwoDigitNumber(number) {
    var numString = (number.toString().length < 2) ? ("0" + number) : number;
    return numString;
};

//Return the number of days in the supplied month/year
DateFormat.getMonthDays = function getMonthDays(month,year) { //Get number of days in a month
    var DaysInMonth=[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if (DateFormat.isLeapYear(year)) {
        DaysInMonth[1]=29;
    }
    return DaysInMonth[month];
};

//Return whether the supplied year is a leap year or not
DateFormat.isLeapYear = function isLeapYear(year) {
    if ((year%4)===0) {
        if ((year%100===0) && (year%400)!==0){
            return false;
        }
		else {
            return true;
        }
    }
	else {
        return false;
    }
};

/*
 * End of DateFormat class
 **/

 
 /**
 * CalendarWindow class
 */

//Create a CalendarWindow that uses the supplied iFrame
function CalendarWindow(iframe) {
   if (iframe === undefined) {
      throw new Error("CalendarWindow parameter not supplied");
   }
   this.winCal = iframe;
   this.cnTop=200;//top coordinate of calendar window.
   this.cnLeft=200;//left coordinate of calendar window
}

//make the window visible (give the window a nonzero width and height)
CalendarWindow.prototype.show = function show() {
	if (trace) { showTrace(arguments.callee); }
    this.winCal.width = 200;
    this.winCal.height = 300;
	this.adjustSize();
	return this;
};

//Give the window a width and height relevant to the content
CalendarWindow.prototype.adjustSize = function adjustSize() {
	if (trace) { showTrace(arguments.callee); }
    var selectHeight = 96;
    var selectWidth = 96;
    var padding = 4;
    var table = this.getDocument().getElementById("CalTable");
    if (table) {
	    if (table.clientHeight) {
	        selectHeight = parseInt(table.clientHeight,10);
	        selectWidth = parseInt(table.clientWidth,10);
	    }
		else if (table.offsetHeight) {
	        selectHeight = parseInt(table.offsetHeight,10);
	        selectWidth = parseInt(table.offsetWidth,10);
	    } 
      this.winCal.width = selectWidth + padding ;
      this.winCal.height = selectHeight + padding;
    } 
	return this;
};

//Return the document associated with this window
CalendarWindow.prototype.getDocument = function getDocument() {
    if (this.winCal.contentDocument) {
       return this.winCal.contentDocument;
    }
	else if (this.winCal.contentWindow) {
       return this.winCal.contentWindow.document;
    }
	else if (this.winCal.document) { 
       return this.winCal.document;
    }
};

//Hide the iFrame calendar
CalendarWindow.prototype.hide = function hide() {
	if (trace) { showTrace(arguments.callee); }
    this.winCal.width = 0;
    this.winCal.height = 0;
	return this;
};

//Move the calendar popup a little below and somewhat to the left
// of the object that triggered the supplied event
CalendarWindow.prototype.move = function move(e) {
	if (trace) { showTrace(arguments.callee); }
	if (!e) {
		e = window.event;
	}
    this.cnTop = 0;
    this.cnLeft = 0;
	
    if (e.x) {
      this.cnTop = e.y + 16;
      this.cnLeft = e.x - 110;
    }
	else {
      this.cnTop = e.clientY + 16;
      this.cnLeft = e.clientX - 110;
    }
    if (e.offsetX) {
      this.cnTop = this.cnTop - e.offsetY;
      this.cnLeft = this.cnLeft - e.offsetX;
    }
    if (document.documentElement) {
        this.cnTop = this.cnTop + document.documentElement.scrollTop;
        this.cnLeft = this.cnLeft + document.documentElement.scrollLeft;
    }
	else if (parent.pageYOffset) {
       this.cnTop = this.cnTop + parent.pageYOffset;
       this.cnLeft = this.cnLeft + parent.pageXOffset;
    } 
    if (this.cnLeft < 0) {
       this.cnLeft = 0;
    }
    if (parent.height && parent.height < this.cnTop - 300) {
       this.cnTop = parent.height - 300;
    }

    this.winCal.style.left = this.cnLeft + "px";
    this.winCal.style.top = this.cnTop + "px";

	return this;
};
/*
 * End of CalendarWindow class
 *
 */

function inframeCal(iframe) {
    var pwindow = new CalendarWindow(iframe);
   var docCal = pwindow.getDocument();
    docCal.open();
    docCal.writeln("<html><head><title>Calendar</title>");
    docCal.writeln("<link rel=\"stylesheet\" href=\"calendar.css\" type=\"text/css\">");
    docCal.writeln("</head><body class='framebody' onload='parent.Cal.window.adjustSize();'>");
    docCal.writeln(inlineCal()); //docCal.write(vCalHeader);
    docCal.writeln("\n</tr></table>");
    docCal.writeln("</body></html>");
    docCal.close();
 Cal.window = pwindow;
    
}

function inlineCal() {
   Cal = new Calendar(dtToday, defaultDF);
   var vTable="<table id=\"CalTable\" border=0 cellpadding=0 cellspacing=3 width='100%' align=\"center\" valign=\"top\">\n<tr>\n";
   vTable+="<td colSpan='7' class='head3'>Meeting Nights</td></tr><tr>";
   vTable+= getCalendarHtml(Cal);
   vTable += "\n</tr></table>";
   return vTable;
}
//Generate the html for the calendar popup
function getCalendarHtml(calObj) {
    var i, j, k;
    var selectString;
    var vDayCount=0;

    var vCalData="<tr>";
    //Calendar day cells
    var calDate;
    var vFirstDay;
    var flag;
    var todayFlag = false;
    var strCell;

    for (k=0; k < 3; k++) {
      for (i=1;i<8;i++) {
        vCalData+="<td class='head1' width='14.3%'>"+Cal.Format.weekDayName[i]+"</td>";
      }
      vCalData+="</tr><tr><td class='head1' colSpan='7'>" + dateLanguage.monthNames[Cal.Month]+" "+ Cal.Year +"</td></tr><tr>";
      calDate=new Date(Cal.Year,Cal.Month);
      calDate.setDate(1);
      vFirstDay=calDate.getDay();
      vDayCount = 0;
      for (i=0;i<vFirstDay;i++) {
        vCalData=vCalData+GenCell(null, null, "head1", flag);
        vDayCount=vDayCount+1;
      }
      for (j=1;j<=Cal.GetMonDays();j++) {
        calDate.setDate(j);
        vDayCount=vDayCount+1;
        flag = isMeetingDay(calDate);
      
        todayFlag = false;
        if ((j==dtToday.getDate())&&(Cal.Month==dtToday.getMonth())&&(Cal.Year==dtToday.getFullYear())) {
           todayFlag = true;
        }
        
        strCell=GenCell(j,todayFlag,"div1",flag);
        vCalData=vCalData+strCell;

        if ((vDayCount%7 === 0)&&(j<Cal.GetMonDays())) {
           vCalData=vCalData+"</tr>\n<tr>";
        }
       
      }
      vCalData=vCalData+"</tr>\n<tr>";
      Cal.Month++;
      if (Cal.Month == 12) {
        Cal.Month = 0;
        Cal.Year++;
      }
   }
   return vCalData;
}

function isMeetingDay(date) {
    var dayOfWeek = date.getDay();
    var month = date.getMonth();
    var year = date.getYear();
    switch (dayOfWeek){
       case 1:
          if (date.getDate() < 8  || date.getDate() > 13){
               return 0;
          }
          break;
      case 2:
           if (date.getDate() > 7 && date.getDate() < 15){
                return 0;
           }
           break;
     default:
         //If its not Tuesday or monday, we don't meet
         return 0;
    }
    //Special days that we don't meet
    //Christmas and Christmas Eve
    if (month == 11 && (date.getDate() == 25 || date.getDate() == 24)){
        return 0;
    }
    //Special days that we don't meet
    //Election day
    if (month == 10 && (date.getDate() >1  && date.getDate() < 9)) {
        return 0;
    }
    if (month == 4 && (date.getDate() == 19)) {
        return 0;
    }

    
    //New Years Day
    if (month === 0 && date.getDate() ===1) {
        return 0;
    }
    //near New Years Day
    if (month === 11 && date.getDate() > 29) {
        return 0;
    }
     if (month === 0 && date.getDate() ===14) {
       alert(dayOfWeek + " " + date + date.getDate());
    }
    //If we haven't ruled it out yet, the rest of the nights are meeting nights
    return 2;

}

