/*
 *	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 today = null,
	afterSundown = false,
	hebrewMonth = 0,
	hebrewDate = 0,
	hebrewYear = 0,
	metonicCycle = 0,
	metonicYear = 0,
	moladDay = 0,
	moladHalakim = 0;

var gWeekday = new weekdayarr("א","ב","ג","ד","ה","ו","שבת");
var gMonth = new gregmontharr("ינואר","פברואר","מרץ","אפריל","מאי","יוני","יולי","אוגוסט","ספטמבר","אוקטובר","נובמבר","דצמבר");
var hMonth = new hebrewmontharr("תשרי","חשון","כסלו","טבת","שבט","אדר א'","אדר ב'","ניסן","אייר","סיון","תמוז","אב","אלול");
var mpy = new monthsperyeararr(12,12,13,12,12,13,12,13,12,12,13,12,12,13,12,12,13,12,13);

var hebNumValues = new Array(); 
hebNumValues[0] = new Array(); hebNumValues[0][0] = 400; hebNumValues[0][1] = "ת";
hebNumValues[1] = new Array(); hebNumValues[1][0] = 300; hebNumValues[1][1] = "ש";
hebNumValues[2] = new Array(); hebNumValues[2][0] = 200; hebNumValues[2][1] = "ר";
hebNumValues[3] = new Array(); hebNumValues[3][0] = 100; hebNumValues[3][1] = "ק";
hebNumValues[4] = new Array(); hebNumValues[4][0] = 90; hebNumValues[4][1] = "צ";
hebNumValues[5] = new Array(); hebNumValues[5][0] = 80; hebNumValues[5][1] = "פ";
hebNumValues[6] = new Array(); hebNumValues[6][0] = 70; hebNumValues[6][1] = "ע";
hebNumValues[7] = new Array(); hebNumValues[7][0] = 60; hebNumValues[7][1] = "ס";
hebNumValues[8] = new Array(); hebNumValues[8][0] = 50; hebNumValues[8][1] = "נ";
hebNumValues[9] = new Array(); hebNumValues[9][0] = 40; hebNumValues[9][1] = "מ";
hebNumValues[10] = new Array(); hebNumValues[10][0] = 30; hebNumValues[10][1] = "ל";
hebNumValues[11] = new Array(); hebNumValues[11][0] = 20; hebNumValues[11][1] = "כ";
hebNumValues[12] = new Array(); hebNumValues[12][0] = 19; hebNumValues[12][1] = "יט";
hebNumValues[13] = new Array(); hebNumValues[13][0] = 18; hebNumValues[13][1] = "יח";
hebNumValues[14] = new Array(); hebNumValues[14][0] = 17; hebNumValues[14][1] = "יז";
hebNumValues[15] = new Array(); hebNumValues[15][0] = 16; hebNumValues[15][1] = "טז";
hebNumValues[16] = new Array(); hebNumValues[16][0] = 15; hebNumValues[16][1] = "טז";
hebNumValues[17] = new Array(); hebNumValues[17][0] = 14; hebNumValues[17][1] = "יד";
hebNumValues[18] = new Array(); hebNumValues[18][0] = 13; hebNumValues[18][1] = "יג";
hebNumValues[19] = new Array(); hebNumValues[19][0] = 12; hebNumValues[19][1] = "יב";
hebNumValues[20] = new Array(); hebNumValues[20][0] = 11; hebNumValues[20][1] = "יא";
hebNumValues[21] = new Array(); hebNumValues[21][0] = 10; hebNumValues[21][1] = "י";
hebNumValues[22] = new Array(); hebNumValues[22][0] = 9; hebNumValues[22][1] = "ט";
hebNumValues[23] = new Array(); hebNumValues[23][0] = 8; hebNumValues[23][1] = "ח";
hebNumValues[24] = new Array(); hebNumValues[24][0] = 7; hebNumValues[24][1] = "ז";
hebNumValues[25] = new Array(); hebNumValues[25][0] = 6; hebNumValues[25][1] = "ו";
hebNumValues[26] = new Array(); hebNumValues[26][0] = 5; hebNumValues[26][1] = "ה";
hebNumValues[27] = new Array(); hebNumValues[27][0] = 4; hebNumValues[27][1] = "ד";
hebNumValues[28] = new Array(); hebNumValues[28][0] = 3; hebNumValues[28][1] = "ג";
hebNumValues[29] = new Array(); hebNumValues[29][0] = 2; hebNumValues[29][1] = "ב";
hebNumValues[30] = new Array(); hebNumValues[30][0] = 1; hebNumValues[30][1] = "א";

   
function weekdayarr(d0,d1,d2,d3,d4,d5,d6)
{
	this[0] = d0; this[1] = d1; this[2] = d2; this[3] = d3;
	this[4] = d4; this[5] = d5; this[6] = d6;
}
   
function gregmontharr(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11)
{
	this[0] = m0; this[1] = m1; this[2] = m2; this[3] = m3;
	this[4] = m4; this[5] = m5; this[6] = m6; this[7] = m7;
	this[8] = m8; this[9] = m9; this[10] = m10; this[11] = m11;
}
   
function hebrewmontharr(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13)
{
	this[0] = m0; this[1] = m1; this[2] = m2; this[3] = m3;
	this[4] = m4; this[5] = m5; this[6] = m6; this[7] = m7;
	this[8] = m8; this[9] = m9; this[10] = m10; this[11] = m11;
	this[12] = m12; this[13] = m13;
}
   
function monthsperyeararr(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,
						  m10,m11,m12,m13,m14,m15,m16,m17,m18)
{
	this[0] = m0; this[1] = m1; this[2] = m2; this[3] = m3;
	this[4] = m4; this[5] = m5; this[6] = m6; this[7] = m7;
	this[8] = m8; this[9] = m9; this[10] = m10; this[11] = m11;
	this[12] = m8; this[13] = m13; this[14] = m14; this[15] = m15;
	this[16] = m16; this[17] = m17; this[18] = m18;
}

function translateMyDate(myYY,myMM,myDD,myHR,myMT)
{
	if(today == null) 
	{
		//today = new Date();  // this gets the current day from the client
		
		// Year must be a four digit year
		
		myMM -= 1; // months go from 0 - 11
		
		// day goes from 1 - 31
		// hour goes from 0 - 23
		// minutes go from 0 - 59
		
		today = new Date(myYY, myMM, myDD, myHR, myMT);
	    //alert(today);	
		
		// this assumes that שקיעת החמה is always at 7:00 pm
		afterSundown = (today.getHours() >= 19);
	}

	SdnToHebrew(GregorianToSdn(getFullYear(today),today.getMonth()+1,today.getDate()));
	displayHebrewDate();
}

function displayWeekday()
{
	document.writeln(gWeekday[today.getDay()] + "day");
}

function getFullYear(d)
{
    var y = d.getYear();
	    
    if (y < 1000)
    	y += 1900;
	   
    return y;
}	
	
function displayGregorianDate()
{
	document.writeln(gMonth[today.getMonth()] + " " + today.getDate() + ", " + getFullYear(today));
}


function displayHebrewDate()
{
	if(hebrewDate != 0 && hebrewMonth != 0 && hebrewYear != 0)
	{
		var strHebDt = translateToHebrewNums(hebrewDate);
		var strHebYr = translateToHebrewNums(hebrewYear);
		document.writeln(strHebDt + " " + hMonth[hebrewMonth-1] + " " + strHebYr);
	}
}

function translateToHebrewNums(numToTranslate)
{
	var indx;
	var num = numToTranslate;
	var hebNum = "";
	
	if (num > 5000)
	{
		num -= 5000;
	}
	
	for (indx=0; indx < 31; indx++)
	{
		if ( num >= hebNumValues[indx][0] )
		{
			num -= hebNumValues[indx][0];
			hebNum += hebNumValues[indx][1];
		}
		if ( num == 0 )
		{
			break;
		}
	}
	
	if ( hebNum.length >= 2 )
	{
		hebNum = hebNum.substr(0,hebNum.length-1) + '"' + hebNum.substr(hebNum.length-1,hebNum.length);
	}
	else if ( hebNum.length == 1 )
	{
		hebNum += "'";
	}
	return hebNum;
}

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;
		
	if(afterSundown) {
		sdn++;
	}

	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;
}

