// The following code follows instructions and examples from
// Calendrical Calculations -- Millenium Edition
// by Renigold & Dershowitz

var month = 0;
var day = 0;
var year = 0;

var GregBaseYear = 1760;		// Base year
var HebrewBaseYear = 5530;		// start of next cycle after base year
var BaseMoladDay = 3560;		// Molad information for that cycle
var BaseMoladHour = 21;
var BaseMoladPart = 549;
var EPOCH_DIFF = 1373429;			// Difference between Gregorian and Hebrew calendars
var EPOCH = 1;
var TISHRI = 7;
var NISAN = 1;
var JANUARY = 1;
var MARCH = 3;
var BUFFER_SIZE = 20;


var GregMonthName = new Array();
GregMonthName[1] = "January";
GregMonthName[2] = "February";
GregMonthName[3] = "March";
GregMonthName[4] = "April";
GregMonthName[5] = "May";
GregMonthName[6] = "June";
GregMonthName[7] = "July";
GregMonthName[8] = "August";
GregMonthName[9] = "September";
GregMonthName[10] = "October";
GregMonthName[11] = "November";
GregMonthName[12] = "December";


var HebrewMonthName = new Array();
HebrewMonthName[1] = "Nisan";
HebrewMonthName[2] = "Iyyar";
HebrewMonthName[3] = "Sivan";
HebrewMonthName[4] = "Tammuz";
HebrewMonthName[5] = "Av";
HebrewMonthName[6] = "Elul";
HebrewMonthName[7] = "Tishri";
HebrewMonthName[8] = "Marheshvan";
HebrewMonthName[9] = "Kislev";
HebrewMonthName[10] = "Tevet";
HebrewMonthName[11] = "Shevat";
HebrewMonthName[12] = "Adar";
HebrewMonthName[13] = "Adar II";

function IsGregLeapYear(year) {
	if ( year % 4 == 0 )
		if ((year % 100 == 0) && (year % 400 == 0))
			return 0;
		else
			return 1;	
	else
		return 0;
	}


function HebrewLeapYear(year) {
	var vResult =  Mod(1 + (7 * year), 19);
	
	if (vResult < 7)
		return 1;
	else
		return 0;

	}


function Quotient(Product, Divisor) {
	var result = Math.floor(Product / Divisor);
	return result;
}


function DaysFromGregorian(month,day,year) {
	var days = (year - 1) * 365;
	days += Quotient(year - 1, 4);
	days -= Quotient(year - 1, 100);
	days += Quotient(year - 1, 400);
	days += Quotient(((367 * month) - 362), 12);
	if (month > 2) {
		if (IsGregLeapYear(year))
			days -= 1;
		else
			days -= 2;
		}
	days += day;
	days -= EPOCH;
	return days ;
	}

function GregorianYearLength(year) {
	if (GregLeapYear(year))
		return 366;
	else
		return 365;
	}





function FixedToHebrew(totalDays) {
	totalDays += EPOCH_DIFF;
	var approx = 1 + (Quotient(totalDays - 1, (35975351 / 98496) ));
	for (year = approx - 1; NewYear(year) <= totalDays; ++year);
	year--;
	
	var start = 0;
	if (totalDays < HebrewToFixed(year, 1, 1))
	 	start = TISHRI;
	else
		start = NISAN;

	for (month = start; !(totalDays <= HebrewToFixed(year, month, LastDayOfHebrewMonth(month,year))); ++month);
	
	day = Math.floor(1 + totalDays - HebrewToFixed(year, month, 1));
}

function NewYear(year) {
	return (1 + HebrewElapsedDays(year) + HebrewNewYearDelay(year));
}

function HebrewToFixed(year, month, day) {
	
	var result = NewYear(year) + day - 1;
	if(month < TISHRI) {
		for(var m = TISHRI; m <= LastMonthOfHebrewYear(year); ++m)
			result += LastDayOfHebrewMonth(m, year);

		for(var m = NISAN; m < month; ++m)
			result += LastDayOfHebrewMonth(m, year);

	} else {
		for(var m = TISHRI; m < month; ++m)
			result += LastDayOfHebrewMonth(m, year);
	}
		
	return result;
	
}

function Mod(Product, Divisor) {
	var result = 0;
	var myQuotient = Quotient(Product, Divisor);
	result = Product - (Divisor * myQuotient);
	return result;
}

function HebrewElapsedDays(inputYear) {
	var monthsElapsed = Quotient((235 * inputYear) - 234, 19);
	var partsElapsed = 12084 + (13753 * monthsElapsed);
	var day = (29 * monthsElapsed) + Quotient(partsElapsed, 25920);
	var test = (++day) * 3;	
	if (Mod(test, 7) < 3)
		day++;
		
	return day;
}

function HebrewNewYearDelay (inputYear) {
	var ny0 = HebrewElapsedDays(inputYear - 1);
	var ny1 = HebrewElapsedDays(inputYear);
	var ny2 = HebrewElapsedDays(inputYear + 1);
		
	if(ny2 - ny1 == 356)
		return 2;
	else if(ny1 - ny0 == 382)
		return 1;
	else
		return 0;
	
}

function LastMonthOfHebrewYear(year) {
	if (HebrewLeapYear(year))
		return 13;
	else
		return 12;
}

function LastDayOfHebrewMonth(month, year) {
	var result = 0;
	if (month == 2)
		result = 29;
	else if (month == 4)
		result = 29;
	else if (month == 6)
		result = 29;
	else if (month == 10)
		result = 29;
	else if (month == 13)
		result = 29;
	else if (month == 12 && !HebrewLeapYear(year))
		result = 29;
	else if (month == 8 && !HasLongMarheshvan(year))
		result = 29;
	else if (month == 9 && HasShortKislev(year))
		result = 29;
	else	
		result = 30;

	return result;
}


function HasLongMarheshvan(year) {
	var days = DaysInHebrewYear(year);
	return (days == 355 || days == 385);
	
}

function HasShortKislev(year) {
	var days = DaysInHebrewYear(year);
	return (days == 353 || days == 383);
}


function DaysInHebrewYear(year) {
	return (NewYear(year + 1) - NewYear(year));
	
}


function HebrewDaysInMonth(month, year) {
	var length = HebrewYearLength(year);
	var days = HebrewMonthDays[month];
	if ( month == 1 && (length == 355 || length == 385 )) {
		days = HebrewMonthDays[month] + 1;
		}
	if ( month == 2 && (length == 353 || length == 383)) {
		days = HebrewMonthDays[month] - 1;
		}
	return days;
	}

function HebrewNextMonth(month,year) {
	/* Check if the month is Shevet and if it's a leap year */
	if (month == 4  && !HebrewLeapYear(year)) {
		month = month + 2; // skip Adar I
		}
	else {
		month++;
		}
	return month;
	}

function GetHebrewMonthName(month, year) {
	if (HebrewLeapYear(year) && month == 12) {
			return "Adar I";
	}
	else {
		return HebrewMonthName[month];
	}
}

function Yahrzeit(deathMonth, deathDay, deathYear, inputYear) {

	var vResult = 0;
		
	if (deathMonth == 8 && deathDay == 30 && !HasLongMarheshvan(deathYear + 1))
		vResult = HebrewToFixed(inputYear, 9, 1) - 1;
	else if (deathMonth == 9 && deathDay == 30 && hasShortKislev(deathYear + 1))
		vResult = HebrewToFixed(inputYear, 10, 1) - 1;
	// else if (deathMonth == 13)
	//	vResult = HebrewToFixed(inputYear, LastHebrewMonthOfYear(inputYear), deathDay);
	else if (deathDay == 30 && deathMonth == 12 && !HebrewLeapYear(inputYear))
		vResult = HebrewToFixed(inputYear, 11, 30);
	else
		vResult = HebrewToFixed(inputYear, deathMonth, 1) + deathDay - 1;

	return vResult;
}

function FixedToGregorian(inputDays) {

	year = GregYearFromFixed(inputDays);
	var vPriorDays = inputDays - DaysFromGregorian(JANUARY, 1, year);
	var vCorrection = 0;
	if (inputDays < DaysFromGregorian(MARCH, 1, year)) {
		 vCorrection = 0;
	} else {
		if (IsGregLeapYear(year))
		 	 vCorrection = 1;
		else
		 	 vCorrection = 2;
	}
	month = Quotient(12 * (vPriorDays + vCorrection) + 373, 367);
	day = (inputDays - DaysFromGregorian(month, 1, year) + 1);
	
}


function GregYearFromFixed(inputDays) {
    var vL0 = inputDays + EPOCH - 1;
    var vN400 = Quotient(vL0, 146097);
    var vD1 = Mod(vL0, 146097);
    var vN100 = Quotient(vD1, 36524);
    var vD2 = Mod(vD1, 36524);
    var vN4 = Quotient(vD2, 1461);
    var vD3 = Mod(vD2, 1461);
    var vN1 = Quotient(vD3, 365);
    var year = (400 * vN400) + (100 * vN100) + (4 * vN4) + vN1;
    
    if (vN100 == 4 || vN1 == 4)
    	return year;
    else
    	return (year + 1);

}


function Calendar(m, d, y) {
	// find hebrew date
	m++;
	var days = DaysFromGregorian(m, d, y);
	days++;

	var RDDays = days;
	FixedToHebrew(days);
	var Hday = day;
	var Hyear = year;
	var HDeathMonth = month
	var HDeathDay = day;
	var HDeathYear = year;
	var HDeathMonthName = GetHebrewMonthName(month, year);

	var today = new Date();
	var tempGyear = today.getYear();
	var tempGmonth = today.getMonth() + 1;
	var tempGday = today.getDate();
	var todayFixedDays = DaysFromGregorian(tempGmonth,tempGday,tempGyear);
	
	var vStartYear = HDeathYear;
	days = Yahrzeit(HDeathMonth, HDeathDay, HDeathYear, vStartYear);
	while(days <= (todayFixedDays+EPOCH_DIFF)) {
		vStartYear++;
		days = Yahrzeit(HDeathMonth, HDeathDay, HDeathYear, vStartYear);
	}	

	// find next 20 civil occurence
	var vOutput = "";
	var vOutput2 = "";
	var Buffer = ""

	for (var i=0; i<20; i++) {
		days = Yahrzeit(HDeathMonth, HDeathDay, HDeathYear, (vStartYear)+i);
		days -= (EPOCH_DIFF+1); 
		FixedToGregorian(days);
		var GNextMonth = month;
		var GNextDay = day;
		var GNextYear = year;
		GNextMonth = GregMonthName[GNextMonth]
		Buffer = GNextMonth + " " + GNextDay + ", " + GNextYear;
		var Buffer_Len = Buffer.length;
		for (; Buffer.length < BUFFER_SIZE; ) {
			Buffer += " ";
		}
		if (i <= 9)
			vOutput += Buffer ;
		else
			vOutput2 += Buffer;
			
	}
	// document.calendar.RDDays.value = RDDays;	
	document.calendar.MyComment.value = vOutput;
	document.calendar.MyComment2.value = vOutput2;
	document.calendar.HebMonthOut.value = HDeathMonthName;
	document.calendar.HebDayOut.value = HDeathDay;
	document.calendar.HebYearOut.value = HDeathYear;
	}

