// ewccal.js - a library of date-related Javascript functions.
// by Thomas Wm. Madron (2002)
// For information email info@ewc-inc.com
//
// This library and each individual function, unless otherwise
// copyrighted, is:
//
// Copyright (c) 2002 by Enterprise-Wide Computing, Inc.
// All rights reserved.
//
// Notes:
// 1.  This library may use functions from a related library from EWC:
//     strings.js.
// 2.  Functions:
//     function today()
//     function currentdate( datestr )
//     function MonthName(month)
//     function shortmonthname(month)
//     function DayName( day )
//     function Julian(yr, mt, dy)
//     function JulToYMD(jul)
//     function xint( value )
//     function mod( x, y )
//     function leapyear( year )
//     function zeller( month, day, year)
//     function daysinmonth( month, year )
//     function AnyDay( month, year, seq, wkdy )
//     function CurrentTime( h, m, s )
//     function nextdate( seq, weekday, endtime )
//     function VolumeNumber( smonth, sday, syear )
//     function DayFromName( DayName )
//     function MonthFromName( MonthName )
//     function Difference( nextdate )
//     function expdate()
//     function openAnyWindow(url, name) {
//     function getCookieVal (offset)
//     function FixCookieDate (date)
//     function GetCookie (name)
//     function DeleteCookie (name,path,domain)
//     function setcookie( name, value )
//     function easter( year, format )
//     function calendar( month, year, xcolor )
//
YMD = new Array(2);	//3 elements: 0, 1 and 2

function today()
//
// Returns month, day, and year numbers in the array YMD[].
// Returns date in standard American English format (i.e., February 14, 2002)
//
{
    var dte = new Date();
    var day = dte.getDate();
    var x = dte.getMonth()+1;
	var month = MonthName( x );
    var year = dte.getFullYear();

	YMD[0] = year;	// pass year back
	YMD[1] = dte.getMonth()+1; // pass month back
	YMD[2] = day;  // pass day of month back
    tmp = month + " " + day + ", " + year;
    return tmp;
}

function currentdate( datestr )
//
// currentdate - Returns year, month, and day in YMD[0], YMD[1], and
//   YMD[2], respectively.
//
// Parameters:
// datestr - Optional date in mm-dd-yyyy string format.
//
// Notes:
// 1.  datestr is optional.  If datestr is null, then the current
//     date is passed.  If datestr is not null, then datestr is parsed.
// 2.  Use:
//     if current date is 10/4/2002, then returns current date values:
//     x = currentdate();
//     returns YMD[0]=2002; YMD[1]=10; YMD[2]=4:
//     x = currentdate( "10-04-2002" );
// 3. Function returns the julian number of the date specified in datestr
//     or the julian number of the current date.
//
{
	if ((datestr==null)||(datestr==""))
	{
    	var dte = new Date();
		YMD[0] = dte.getFullYear(); // pass year back
		YMD[1] = dte.getMonth()+1; // pass month back
		YMD[2] = dte.getDate();  // pass day back
		var y = YMD[0];
		var m = YMD[1];
		var d = YMD[2];
	}
	else
	{
		// Assume standard date format for datestr (i.e., mm-dd-yyy).
		parseoptval( datestr, "-");
		var m = parse[0];
		var tmp = parse[1];
		parseoptval( tmp, "-" );
		var d = parse[0];
		var y = parse[1];
		YMD[0] = y; // pass year back
		YMD[1] = m; // pass month back
		YMD[2] = d; // pass day back
	}
	return Julian(y,m,d);
}

function MonthName(month)
{
  var mthname=new Array(13);  // 0 thru 12 (record 0 = empty)
    mthname[1]="January";
    mthname[2]="February";
    mthname[3]="March";
    mthname[4]="April";
    mthname[5]="May";
    mthname[6]="June";
    mthname[7]="July";
    mthname[8]="August";
    mthname[9]="September";
    mthname[10]="October";
    mthname[11]="November";
    mthname[12]="December";
	var tmp = mthname[month];
	return tmp;
}

function shortmonthname(month)
{
	var m = MonthName(month);
	var tmp = left( m, 3 );
	return tmp;
}

function DayName( day )
{
//
// Conforms to the usage in zeller:  0=Sunday, 6=Saturday.
//    If day runs from 1-7, then 1 will have to be subtracted before
//    calling this function.
//
	var dyname=new Array(7);
	dyname[0] = "Sunday";
	dyname[1] = "Monday";
	dyname[2] = "Tuesday";
	dyname[3] = "Wednesday";
	dyname[4] = "Thursday";
	dyname[5] = "Friday";
	dyname[6] = "Saturday";
	var tmp = dyname[ day ];
	return tmp;
}

function Julian(yr, mt, dy)
//
// Calculates the julian number for a given date.
//
{
  var yx = yr;
  var mx = mt;
  var dx = dy;
  var jul = 0;
  if (mx>2)
  {
    var mx = mx - 3;
  }
  else
  {
    var mx = mx + 9;
    var yx = yx - 1;
  }
  var j2 = xint( yx/100 );
  var j1 = yx - 100 * j2;
  var jul = xint((146097*j2)/4)+xint((1461*j1)/4)+xint((153*mx+2)/5)+dx+1721119;
  return jul;
}

function JulToYMD(jul)
//
// Calculates the date from a given julian number
//
// Parameters:
// jul - julian number calculated with function julian.
//
// Notes:
// 1.  Returns date values in YMD[0] (year), YMD[1] (month), and
//     YMD[2] (day).
// 2.  Function returns standard English date (i.e. February 14, 2002).
//
{
  jul = jul + 68569;
  var temp = Math.floor((4 * jul) / 146097);
  jul = jul - Math.floor((146097 * temp + 3) / 4);
  var tmpYear = Math.floor((4000 * (jul + 1)) / 1461001);
  jul = jul - Math.floor((1461 * tmpYear) / 4) + 31;
  var tmpMonth = Math.floor((80 * jul) / 2447);
  YMD[0] = 100 * (temp - 49) + tmpYear + Math.floor(tmpMonth / 11);  // year = element 0
  YMD[1] = tmpMonth + 2 - (12 * Math.floor(tmpMonth / 11));          // month = element 1
  YMD[2] = jul - Math.floor((2447 * tmpMonth) / 80);                 // day = element 2
  tmp = MonthName( YMD[1] )+" "+YMD[2]+", "+YMD[0];
  return tmp;
}

function xint( value )
{
    var tmp = Math.floor( value );
    return tmp;
}

function mod( x, y )
{
	// DEF FNMO(X,Y)=INT(Y*(X/Y-INT(X/Y))+.001)
	var tmp = xint(y*(x/y-xint(x/y))+.001)
	return tmp;
}

function leapyear( year )
{
   var i = 0;
   var j = (year % 4);         // i1=0 if evenly divisible
   var k = (year % 100);       // i2=0 if evenly divisible
   var l = (year % 400);       // i3=0 if evenly divisible
   // var j = mod(year, 4);         // i1=0 if evenly divisible
   // var k = mod(year, 100);       // i2=0 if evenly divisible
   // var l = mod(year, 400);       // i3=0 if evenly divisible
   if (j==0)
	{
		var i = -1; // Years evenly divisible by 4=leap years
	}
   if (k==0)
	{
		var i = 0; // Except when evenly divisible by 100
	}
   if (l==0)
	{
		var i = -1; // Unless also evenly divisibly by 400
	}
   return i;
}


function zeller( month, day, year)
{
	if (month > 2)
	{
		var AdjMonth = month - 2;
		var AdjYear = year;
	}
	else
	{
		var AdjMonth = month + 10;
		var AdjYear = year - 1;
	}
	var century = xint(AdjYear / 100);
	var YearInCentury = AdjYear - 100 * century;
	var n = xint((13*AdjMonth-1)/5)+day+YearInCentury+xint(YearInCentury/4)+xint(century/4)-century-century+77;
	var n = n - 7 * xint(n/7);
	return n;
}

function daysinmonth( month, year )
{
//
// Month must be in the range of 1 - 12.
// Year must be a four digit year.
// Dependencies:  leapyear(), trim(), str(), mid(), val()
// This is a simple table lookup.
//
	var x = leapyear(year);  // x=0 when false; -1 when true.
	var tmp = 28-x; // when x=-1 (true), then the effect of this is to add 1 to 28.
	var feb = trim( str( tmp ), " " ); // converts tmp to a string and eliminates unwanted spaces.
	var table = "31" + feb + "31303130313130313031"; // constructs table after determining proper value for feb.
	var x = ((month-1) * 2); // determines the location of month in table.
	var tmp = mid( table, x, 2 ); // does the table lookup
	var x = val( tmp ); // converts the string "tmp" to a number.
	return x;  // returns the number of days in month as a number.
}

function AnyDay( month, year, seq, wkdy )
{
	// Returns the day of the month for the seqth wkdy.
	// Parameters:
	// month - month number (1-12)
	// year - four digit year number
	// seq - sequence number of the week in the month of the
	//	occurance of wkdy.
	// wkdy - a number from 1 - 7 where 1 = Sunday
	//
	var y = 7; // initialized to number days in week
	var dm = daysinmonth( month, year );
	if (seq > 1)
	{
		var x = ((seq -1) * y) + 1;
	}
	else
	{
		var x = 1;
	}
	var y = seq * y;
	var AnyDay = 0;
	for (day=x; day<=y; day++)
	{
		if (zeller(month, day, year)==(wkdy-1))
		{
			var AnyDay = day;
			break;
		}
	}
	return AnyDay;
}

function CurrentTime( h, m, s )
{
//
//   CurrentTime:  Current time in seconds since midnight.
//
//   by Thomas Wm. Madron (1999)
//
//   Parameters:
//       h - 4 byte integer hour (0 - 23).
//       m - 4 byte integer minute (0 - 59).
//       s - 4 byte integer second (0 - 59).
//
//   Notes:
//   If the h (hours), m (minutes), and s (seconds) parameters are
//   all zero on entry, then this function returns the number of seconds
//   since midnight represented by the current time on the computer on
//   which the program is running.  The parameters are returned as the
//   current hour, minutes, and seconds.
//
//   If any or all of the parameters are non-zero, then those values
//   are used to compute the number of seconds from midnight represented
//   by the time specified on input.  If input, then the time must
//   be specified in 24 hour format.
//
//   If there is some kind of detectable error, the function will be
//   returned as a negative number.
//
   var e = 0;
   if ((h + m + s) == 0)
	{
	  var tmp = new Date();
      var h = tmp.getHours();
      var m = tmp.getMinutes();
      var s = tmp.getSeconds();
	}
    else
	{
      if ((h < 0) || (h > 23))
		{
			var e = e - 1;
		}
      if ((m < 0) || (m > 59))
		{
			var e = e - 1;
		}
      if ((s < 0) || (s > 59))
		{
			var e = e - 1;
		}
    }
    if (e < 0) // THEN
	{
        return e;
	}
   else
	{
			var tmp = (( h * 60 * 60 ) + ( m * 60 ) + s);
			return tmp;
   }
}

function nextdate( seq, weekday, endtime )
// Purpose:
//		To calculate the next date for seq and weekday.
// Parameters:
//		seq - sequential week (i.e., (1)st, (2)nd, (3)rd, (4)th, (5)th)
//		weekday - day of the week on which the date occurs (1=Sunday, 7=Saturday)
//		endtime - Ending time for the event in stadard format (i.e., hh:mm:ss, mm and ss may = 00).
//
{
	var dt = new Array(2);
	var np = strtok ( dt, ":", endtime );
	var h = val(dt[0]);
	var m = val(dt[1]);
	var s = val(dt[2]);
	var tmp = new Date();
	var month = tmp.getMonth()+1; // getMonth() returns a number in the range 0-11.
	var year = tmp.getFullYear();
	var day = tmp.getDate();
	var bday = AnyDay( month, year, seq, weekday );
	var bjulval = Julian( year, month, bday );
	var bdate = JulToYMD(bjulval);
	var tjulval = Julian( year, month, day );
	var tdate = JulToYMD(tjulval);
	if (tjulval < bjulval)
	{
		var xmonth = month;
	}
	else
	{
		var ctime = CurrentTime(0,0,0); // gets current client clock time in seconds from midnight
		var etime = CurrentTime(h,m,s); // gets 11:00:00 (ending time) time in seconds from midnight
		if ((ctime < etime) && (tjulval==bjulval))
		{
			var xmonth = month;
		}
		else
		{
			var xmonth = month + 1;
			if (xmonth > 12)
			{
				var xmonth = xmonth - 12;
				var year = year + 1;
			}
		}
	}
	var nextday = AnyDay( xmonth, year, seq, weekday );
	var ndate = MonthName(xmonth)+" "+nextday+", "+year;
	if ((ndate=="") || (ndate==null))
	{
		var ndate = "Date not returned properly.";
	}
	return ndate;
}

function VolumeNumber( smonth, sday, syear )
{
	// Returns a Volume Number and Issue Number for a sequence of daily
	// publications that starts with smonth, sday, syear.  The resulting
	// data values are returned in the global array YMD[].
	//
	// YMD[0] = vol (Volume Number)
	// YMD[1] = issue (Issue Number with year)
	//
	// Parameters:
	//   smonth - Starting month of publication.
	//   sday - Starting day of publication.
	//   syear - Starting year of publication.
	//
	var startdate = Julian( syear, smonth, sday );
	var tmpdate = today(); // used to initialize YMD[]
	var year = YMD[0];
	var month = YMD[1];
	var day = YMD[2];
	var curdate = Julian( year, month, day );
	var tmp1 = curdate-startdate;
	var vol = xint(tmp1/365)+1;
	var tmpyear = syear + (vol-1);
	var tmpdate = Julian( tmpyear, smonth, sday );
	var issue = curdate - tmpdate + 1;
	YMD[0] = vol;
	YMD[1] = issue;
	return vol;
}

function DayFromName( DayName )
{
//
// Obtains the day number (Sunday=1; Saturday=7) from the day name.
// DayName can be in any form from standard two or three character
// abbreviations to the full name (i.e., sa, sat, saturday).
//
    var tmpname = ucase( left( trim( DayName ), 2 ));
    var tmp = "\SUMOTUWETHFRSA";
    var ii = instr( tmp, tmpname );
    if (ii > 0)
	{
			var y = ii / 2;
			var x = xint( y );
    }
    return x;
}

function MonthFromName( MonthName )
{
//
// Obtains the month number from the month name.
//
	tmpname = ucase( left( trim( MonthName ), 3 ));
	var tmp = "\\JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
	var ii = instr( tmp, tmpname );
	if (ii > 0)
	{
		var y = ii / 3;
		var x = xint( y );
	}
	return x;
}

function Difference( nextdate )
{
//
// Difference - calculates the difference in number of days between
//   the current date and the date string contained in "nextdate"
//   (i.e., 'October 4, 1937').
//
	// Next Breakfast day:
	var knt = strtok( YMD, " ", nextdate );
	var month = MonthFromName( YMD[0] );
	var day = val( trim( YMD[1], "," ) );
    var year = val( YMD[2] );
	var nday = Julian( year, month, day );
	// Today:
	var tday = today();
	var knt = strtok( YMD, " ", tday );
	var m = MonthFromName( YMD[0] );
	var d = val( trim( YMD[1], "," ) );
	var yr = val( YMD[2] );
	var xday = Julian( yr, m, d );
	// Difference:
	var diff = nday - xday;
	return diff;
}

function expdate()
{
//
// Format:  Thu, 01-Jan-1970 00:00:00 GMT
//
	var tmp = new Date();
	var m = tmp.getMonth()+1; // getMonth() returns a number in the range 0-11.
	var y = tmp.getFullYear();
	var d = tmp.getDate();
	var dy = zeller( m, d, y );
	var day = DayName( dy );
	var day = left( day, 3 );
	var daynum = trim( str( d ) );
	if (len( daynum ) == 1)
	{
		daynum = "0" + daynum;
	}
	var month = left( MonthName( m ), 3 );
	var tmp2 = day + ", " + daynum + "-" + month + "-" + str( y ) + " 00:00:00 GMT";
	return tmp2;
}

function openAnyWindow(url, name) {
     var l = openAnyWindow.arguments.length;
     var w = "";
     var h = "";
     var features = "";

     for (i=2; i<l; i++) {
          var param = openAnyWindow.arguments[i];
          if ( (parseInt(param) == 0) ||
               (isNaN(parseInt(param))) ) {
               features += param + ',';
          } else {
               (w == "") ? w = "width=" + param + "," :
               h = "height=" + param;
          }
     }

     features += w + h;
     var code = "popupWin = window.open(url, name";
     if (l > 2) code += ", '" + features;
     code += "')";
     eval(code);
}

function getCookieVal (offset)
{
  // "Internal" function to return the decoded value of a cookie
  //
  var endstr = document.cookie.indexOf (";", offset);
  if (endstr == -1)
  endstr = document.cookie.length;
  return unescape(document.cookie.substring(offset, endstr));
}

function FixCookieDate (date)
{
  //
  //  Function to correct for 2.x Mac date bug.  Call this function to
  //  fix a date object prior to passing it to SetCookie.
  //  IMPORTANT:  This function should only be called *once* for
  //  any given date object!  See example at the end of this document.
  //
  var base = new Date(0);
  var skew = base.getTime(); // dawn of (Unix) time - should be 0
  if (skew > 0)  // Except on the Mac - ahead of its time
  date.setTime (date.getTime() - skew);
}

function GetCookie (name)
{
  //
  //  Function to return the value of the cookie specified by "name".
  //  name - String object containing the cookie name.
  //  returns - String object containing the cookie value, or null if
  //    the cookie does not exist.
  //
  var arg = name + "=";
  var alen = arg.length;
  var clen = document.cookie.length;
  var i = 0;
  while (i < clen) {
  var j = i + alen;
  if (document.cookie.substring(i, j) == arg)
    return getCookieVal (j);
  i = document.cookie.indexOf(" ", i) + 1;
  if (i == 0) break;
  }
  return null;
}

function DeleteCookie (name,path,domain)
{
  //  Function to delete a cookie. (Sets expiration date to start of epoch)
  //  name -   String object containing the cookie name
  //  path -   String object containing the path of the cookie to delete.  This MUST
  //       be the same as the path used to create the cookie, or null/omitted if
  //       no path was specified when creating the cookie.
  //  domain - String object containing the domain of the cookie to delete.  This MUST
  //       be the same as the domain used to create the cookie, or null/omitted if
  //       no domain was specified when creating the cookie.
  //
  if (GetCookie(name)) {
  document.cookie = name + "=" +
    ((path) ? "; path=" + path : "") +
    ((domain) ? "; domain=" + domain : "") +
    "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  }
}

function setcookie( name, value )
{
  document.cookie = name + "=" + escape(value) + "; path=" + "/"
}

function easter( year, format )
//
// Easter - for any given year in the Gregorian Calendar returns
//   the date date of Easter.
//
// Paramters:
//   year - year of interest.
//   format - output format (1 = mm-dd-yyyy [default]; 2 = dd-mmm-yyyy).
//
// Notes:
// 1.  Calculation of the date of Easter:
//     http://aa.usno.navy.mil/faq/docs/easter.html
// 2.  Explanation of calendars
//     http://astro.nmsu.edu/~lhuber/leaphist.html
// 3.  Requires the use of trunc() and padleft() from strings.js.
// 4.  The format paramter is optional.  If not used, the default format
//     is generated for the date of Easter.
// 5.  If the date of easter is to be input into other functions in this
//     library the default format may be required.
//
{
	var y = year;
    var c = trunc(y / 100);
    var n = y - 19 * trunc( y / 19 );
    var k = trunc(( c - 17 ) / 25);
	var k = trunc( k );
    var i = c - trunc(c / 4) - trunc(( c - k ) / 3) + 19 * n + 15;
    var i = i - 30 * trunc( i / 30 );
    var i = i - trunc( i / 28 ) * ( 1 - trunc( i / 28 ) * trunc( 29 / ( i + 1 ) ) * trunc( ( 21 - n ) / 11 ) );
    var j = y + trunc(y / 4) + i + 2 - c + trunc(c / 4);
    var j = j - 7 * trunc( j / 7 );
    var l = i - j;
    var m = 3 + trunc(( l + 40 ) / 44);
	var month = padleft( str(m), "0", 2 );
    var d = l + 28 - 31 * trunc( m / 4 );
	var day = padleft( str(d), "0", 2 );
	if (format==2)
	{
		var tmp = day + "-" + shortmonthname( m ) + "-" + str(y);
	}
	else
	{
		var tmp = month + "-" + day + "-" + str(y);
	}
	return tmp;
}

function calendar( month, year, xcolor )
// Given month and year, a calendar is displayed.
// Parameters:
//   month - calendar month (numeric).
//   year - calendar year (numeric, 4 digits).
//   xcolor - color name for color of current date in quotes.
{
	var bgclr = "#C0C0C0";
	var m = month;
	var y = year;
	var dstr = m+"-01-"+y;
	var caldate = currentdate( dstr );
	var cy = val(YMD[0]);
	var cm = val(YMD[1]);
	var cd = val(YMD[2]);

	// Start Calendar Table:
	var tmp = "<table border='1' cellpadding='0' cellspacing='0' bgcolor="+bgclr+">";
	document.write( tmp );

	// Write Month Header:
	var mname = MonthName(cm);
	var tmp = mname+" "+cy;
	document.write( "<tr>","<td colspan='7' align='center'>" )
	document.write( "<font size='2' face='sans-serif'>","<strong>",tmp,"</td>","</strong></font>","</tr>" );

	// Write Day Name header row:
	document.write( "<tr>" );
	for (dy=0;dy<7;dy++)
	{
		var tmp = DayName( dy );
		var da = left( tmp, 2 );
		document.write( "<td align='right' width='15'>","<font size='2' face='sans-serif'><strong>",da,"</strong></font>","</td>" );
	}
	document.write( "</tr>" );

	// Write Date Value Rows:
	var tmp = "";
	var curdate = currentdate( tmp );
	var curdate = YMD[2];
	var curmnth = YMD[1];
    var dm = daysinmonth( cm, cy );
    var cxd = 1;
    var firstday = zeller( cm, cxd, cy) + 1;
    var tmpday = 1;
    for (i=1;i<7;i++)
    {
        document.write( "<tr>" );
        for (dy=1;dy<8;dy++)
        {
			var clr = "black";
            if (dy>=firstday)
            {
                if (tmpday<=dm)
                {
					if ((tmpday==curdate)&&(cm==curmnth))
					{
						var clr = xcolor;
					}
                    var da = tmpday;
            		tmpday++;
					var firstday = zeller( cm, tmpday, cy ) + 1;
                }
                else
                {
                    var da = "&nbsp;";
                }
            }
            else
            {
                var da = "&nbsp;";
            }
			var f = "<font size='2' face='sans-serif' color='"+clr+"'>";
            document.write( "<td align='right' width='15'>",f,"<strong>",da,"</strong></font></td>" );
        }
        document.write( "</tr>" );
    }

	// End Calendar Table:
	document.write( "</table>" );
}
