/*
 *      This script was adapted from C sources written by
 *      Scott E. Lee, which contain the following copyright notice:
 *
 *      Copyright 1993-1995, Scott E. Lee, all rights reserved.
 *      Permission granted to use, copy, modify, distribute and sell so long as
 *      the above copyright and this permission statement are retained in all
 *      copies.  THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
 *
 *      Bill Hastings
 *      RBI Software Systems
 *      bhastings@rbi.com
 */
var GREG_SDN_OFFSET = 32045,
	DAYS_PER_5_MONTHS = 153,
	DAYS_PER_4_YEARS = 1461,
	DAYS_PER_400_YEARS = 146097;
var HALAKIM_PER_HOUR = 1080,
	HALAKIM_PER_DAY = 25920,
	HALAKIM_PER_LUNAR_CYCLE = ((29 * HALAKIM_PER_DAY) + 13753),
	HALAKIM_PER_METONIC_CYCLE = (HALAKIM_PER_LUNAR_CYCLE * (12 * 19 + 7));
var HEB_SDN_OFFSET = 347997,
	NEW_MOON_OF_CREATION = 31524,
	NOON = (18 * HALAKIM_PER_HOUR),
	AM3_11_20 = ((9 * HALAKIM_PER_HOUR) + 204),
	AM9_32_43 = ((15 * HALAKIM_PER_HOUR) + 589);
var SUN = 0,
	MON = 1,
	TUES = 2,
	WED = 3,
	THUR = 4,
	FRI = 5,
	SAT = 6;
var gregday, gregmonth, gregmonthname, gregyear, gregwday, hebmonthname,
	hebrewMonth = 0,
	hebrewDate = 0,
	hebrewYear = 0,
	metonicCycle = 0,
	metonicYear = 0,
	moladDay = 0,
	moladHalakim = 0;
var gWeekday = new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
var gMonth = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
var hMonth = new Array("Tishri","Heshvan","Kislev","Tevet","Shevat","AdarI","AdarII","Nisan","Iyyar","Sivan","Tammuz","Av","Elul");
var mpy = new Array(12,12,13,12,12,13,12,13,12,12,13,12,12,13,12,12,13,12,13);

function getTodayDate()
{
var today = new Date();
getAnyDate(today.getFullYear(),today.getMonth(),today.getDate());
}
function getAnyDate(inputYear,inputMonth,inputDay)
{
gregyear = inputYear; gregmonth = inputMonth; gregday = inputDay;
SdnToHebrew(GregorianToSdn(inputYear,inputMonth+1,inputDay));
hebmonthname = returnHebrewMonth();
gregmonthname = gMonth[gregmonth];
}
function returnHebrewMonth()
{
	if (hebrewMonth == 6)
	    if (mpy[(hebrewYear - 1) % 19] == 12)
			return ("Adar");	
	return (hMonth[hebrewMonth-1]);
}
function GregorianToSdn(inputYear,inputMonth,inputDay)
{
	var year = 0,
		month = 0,
		sdn;
	// Make year a positive number
	if (inputYear < 0)
		year = inputYear + 4801;
	else
		year = inputYear + 4800;
	// Adjust the start of the year
	if (inputMonth > 2) {
		month = inputMonth - 3;
	}
	else {
		month = inputMonth + 9;
		year--;
	}
	sdn      = Math.floor((Math.floor(year / 100) * DAYS_PER_400_YEARS) / 4);
	sdn += Math.floor(((year % 100) * DAYS_PER_4_YEARS) / 4);
	sdn += Math.floor((month * DAYS_PER_5_MONTHS + 2) / 5);
	sdn += inputDay - GREG_SDN_OFFSET;
	gregwday = gWeekday[(sdn + 1) % 7];
	return sdn;
}
function SdnToHebrew(sdn)
{
	var inputDay,
		tishri1 = 0,
		tishri1After = 0,
		yearLength = 0,
	inputDay = sdn - HEB_SDN_OFFSET;
	FindTishriMolad(inputDay);
	tishri1 = Tishri1(metonicYear,moladDay,moladHalakim);
	if (inputDay >= tishri1) {
		// It found Tishri 1 at the start of the year.
		hebrewYear = metonicCycle * 19 + metonicYear + 1;
		if (inputDay < tishri1 + 59) {
			if (inputDay < tishri1 + 30) {
				hebrewMonth = 1;
				hebrewDate = inputDay - tishri1 + 1;
			}
			else {
				hebrewMonth = 2;
				hebrewDate = inputDay - tishri1 - 29;
			}
			return;
		}
		// We need the length of the year to figure this out,so find Tishri 1 of the next year.
		moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear];
		moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
		moladHalakim = moladHalakim % HALAKIM_PER_DAY;
		tishri1After = Tishri1((metonicYear + 1) % 19,moladDay,moladHalakim);
	}
	else {
		// It found Tishri 1 at the end of the year.
		hebrewYear = metonicCycle * 19 + metonicYear;
		if (inputDay >= tishri1 - 177) {
			// It is one of the last 6 months of the year.
			if (inputDay > tishri1 - 30) {
				hebrewMonth = 13;
				hebrewDate = inputDay - tishri1 + 30;
			}
			else if (inputDay > tishri1 - 60) {
				hebrewMonth = 12;
				hebrewDate = inputDay - tishri1 + 60;
			}
			else if (inputDay > tishri1 - 89) {
				hebrewMonth = 11;
				hebrewDate = inputDay - tishri1 + 89;
			}
			else if (inputDay > tishri1 - 119) {
				hebrewMonth = 10;
				hebrewDate = inputDay - tishri1 + 119;
			}
			else if (inputDay > tishri1 - 148) {
				hebrewMonth = 9;
				hebrewDate = inputDay - tishri1 + 148;
			}
			else {
				hebrewMonth = 8;
				hebrewDate = inputDay - tishri1 + 178;
			}
			return;
		}
		else {
			if (mpy[(hebrewYear - 1) % 19] == 13) {
				hebrewMonth = 7;
				hebrewDate = inputDay - tishri1 + 207;
				if (hebrewDate > 0)
				        return;
				hebrewMonth--;
				hebrewDate += 30;
				if (hebrewDate > 0)
				        return;
				hebrewMonth--;
				hebrewDate += 30;
			}
			else {
				hebrewMonth = 6;
				hebrewDate = inputDay - tishri1 + 207;
				if (hebrewDate > 0)
				        return;
				hebrewMonth--;
				hebrewDate += 30;
			}
			if (hebrewDate > 0)
				return;
			hebrewMonth--;
			hebrewDate += 29;
			if (hebrewDate > 0)
				return;
			// We need the length of the year to figure this out,so find Tishri 1 of this year.
			tishri1After = tishri1;
			FindTishriMolad(moladDay - 365);
			tishri1 = Tishri1(metonicYear,moladDay,moladHalakim);
		}
	}
	yearLength = tishri1After - tishri1;
	moladDay = inputDay - tishri1 - 29;
	if (yearLength == 355 || yearLength == 385) {
		// Heshvan has 30 days
		if (moladDay <= 30) {
			hebrewMonth = 2;
			hebrewDate = moladDay;
			return;
		}
		moladDay -= 30;
	}
	else {
		// Heshvan has 29 days
		if (moladDay <= 29) {
			hebrewMonth = 2;
			hebrewDate = moladDay;
			return;
		}
		moladDay -= 29;
	}
	// It has to be Kislev.
	hebrewMonth = 3;
	hebrewDate = moladDay;
}
function FindTishriMolad(inputDay)
{
	// Estimate the metonic cycle number.  Note that this may be an under
	// estimate because there are 6939.6896 days in a metonic cycle not
	// 6940,but it will never be an over estimate.   The loop below will
	// correct for any error in this estimate.
	metonicCycle = Math.floor((inputDay + 310) / 6940);
	// Calculate the time of the starting molad for this metonic cycle.
	MoladOfMetonicCycle();
	// If the above was an under estimate,increment the cycle number until
	// the correct one is found.  For modern dates this loop is about 98.6%
	// likely to not execute,even once,because the above estimate is
	// really quite close.
	while (moladDay < inputDay - 6940 + 310) {
		metonicCycle++;
		moladHalakim += HALAKIM_PER_METONIC_CYCLE;
		moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
		moladHalakim = moladHalakim % HALAKIM_PER_DAY;
	}
	// Find the molad of Tishri closest to this date.
	for (metonicYear = 0; metonicYear < 18; metonicYear++) {
		if (moladDay > inputDay - 74)
			break;
		moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear];
		moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
		moladHalakim = moladHalakim % HALAKIM_PER_DAY;
	}
}
function MoladOfMetonicCycle()
{
	var r1,r2,d1,d2;
	// Start with the time of the first molad after creation.
	r1 = NEW_MOON_OF_CREATION;
	// Calculate gMetonicCycle * HALAKIM_PER_METONIC_CYCLE.  The upper 32
	// bits of the result will be in r2 and the lower 16 bits will be in r1.
	r1 += metonicCycle * (HALAKIM_PER_METONIC_CYCLE & 0xFFFF);
	r2 = r1 >> 16;
	r2 += metonicCycle * ((HALAKIM_PER_METONIC_CYCLE >> 16) & 0xFFFF);
	// Calculate r2r1 / HALAKIM_PER_DAY.  The remainder will be in r1,the
	// upper 16 bits of the quotient will be in d2 and the lower 16 bits
	// will be in d1.
	d2 = Math.floor(r2 / HALAKIM_PER_DAY);
	r2 -= d2 * HALAKIM_PER_DAY;
	r1 = (r2 << 16) | (r1 & 0xFFFF);
	d1 = Math.floor(r1 / HALAKIM_PER_DAY);
	r1 -= d1 * HALAKIM_PER_DAY;
	moladDay = (d2 << 16) | d1;
	moladHalakim = r1;
}
function Tishri1(metonicYear,moladDay,moladHalakim)
{
	var tishri1 = moladDay;
	var dow = tishri1 % 7;
	var leapYear =  metonicYear == 2 || metonicYear == 5 || metonicYear == 7 || metonicYear == 10 ||
				        metonicYear == 13 || metonicYear == 16 || metonicYear == 18;
	var lastWasLeapYear =   metonicYear == 3 || metonicYear == 6 || metonicYear == 8 || metonicYear == 11 ||
				                        metonicYear == 14 || metonicYear == 17 || metonicYear == 0;
	// Apply rules 2,3 and 4
	if ((moladHalakim >= NOON) ||
		((!leapYear) && dow == TUES && moladHalakim >= AM3_11_20) ||
		(lastWasLeapYear && dow == MON && moladHalakim >= AM9_32_43))
	{
		tishri1++;
		dow++;
		if (dow == 7)
			dow = 0;
	}
	// Apply rule 1 after the others because it can cause an additional delay of one day.
	if (dow == WED || dow == FRI || dow == SUN) {
		tishri1++;
	}
	return tishri1;
}
