function CGDate(GD, GM, GY)
{
	this.Day = GD;
	this.Month = GM;
	this.Year = GY;
	this.Set = CGDate_Set;
	this.Pessach = CGDate_Pessach;
	this.RoshHashana = CGDate_RoshHashana;
	this.AddDays = CGDate_AddDays;
	this.Convert = CGDate_Convert;
	this.ConvertDate = CGDate_ConvertDate;
	this.Minus = CGDate_Minus;
	this.WeekdayName = CGDate_WeekdayName;
	this.MonthName = CGDate_MonthName;
	this.MonthLength = CGDate_MonthLength;
}

function CGDate_Set(GD, GM, GY)
{
	this.Day = GD;
	this.Month = GM;
	this.Year = GY;
}

function CGDate_Minus(GDate)
{
	var days = 0;

	while((GDate.Year != this.Year) || (GDate.Month != this.Month) || (GDate.Day != this.Day))
	{
		if(this.Year > GDate.Year)
		{
			if((this.Month > GDate.Month) || ((this.Month == GDate.Month) && (this.Day >= GDate.Day)))
			{
				if((GDate.Month < 2) || ((GDate.Month == 2) && (GDate.Day <= 28)))
					days += GLeap(GDate.Year) ? 1 : 0;
				else
					days += GLeap(GDate.Year + 1) ? 1 : 0;
				days += 365;
				GDate.Year++;
			}
			else
			{
				days++;
				GDate.AddDays(1);
			}
		}
		else
		{
			days++;
			GDate.AddDays(1);
		}
	}
	return days;
}

function CGDate_Convert(HD, HM, HY)	//HD, HM, HY as int
{
	var HDate2 = new CHDate(HD, HM, HY);
	HDate2.Create();
	var HDate1 = new CHDate(1, 7, HY);
	HDate1.YearLength = HDate2.YearLength;
	HDate1.Leap = HDate2.Leap;

	var GY = HY - 3761;
	this.RoshHashana(GY);
	this.AddDays(HDate2.Minus(HDate1));
}

function CGDate_ConvertDate(HDate)	//HDate as CHDate
{

	this.Convert(HDate.Day, HDate.Month, HDate.Year);
}

function CGDate_AddDays(days)	//days as int > 0
{
	var ml = this.MonthLength();

	if((this.Day == 1) && (this.Month == 1))
		while(days >= (GLeap(this.Year) ? 366 : 365))
		{
			days -= GLeap(this.Year) ? 366 : 365;
			this.Year++;
		}
		

	if(days + this.Day > ml)
	{
		days = days - (ml - this.Day + 1);
		this.Day = 1;
		this.Month++;
		if(this.Month == 13)
		{
			this.Month = 1;
			this.Year++;
		}
		this.AddDays(days);
	}
	else
		this.Day = this.Day + days;
}


function CGDate_RoshHashana(GY)	//GY as int
{
	this.Pessach(GY);
	this.AddDays(163);
}

function CGDate_Pessach(GY)	//GY as int
{
	var HY = GY + 3760;
	var LeapValue = (12 * HY + 17) % 19;
	var b = HY % 4;
	var dm = 32 + 4343 / 98496 + LeapValue + LeapValue * (272953 / 492480) + b / 4
	dm -= HY * (313 / 98496);
	var dmfrac = dm - Math.floor(dm);
	var dc = (3 * HY + 5 * b + Math.floor(dm) + 5) % 7
	
	if((dc == 2) || (dc == 4) || (dc == 6))
	  dm++;
	if((dc == 1) && (LeapValue > 6) && (dmfrac >= 1367 / 2160))
	  dm += 2;
	if((dc == 0) && (LeapValue > 11) && (dmfrac >= 23269 / 25920))
	  dm++;
	
	var s = Math.floor(GY / 100);
	var add = Math.floor((3 * s - 5) / 4);
	if(GY > 1582)
	  dm += add;
	
	dm = Math.floor(dm);
	var month = 3;
	if(dm > 153)
	{
	  month = 8;
	  dm -= 153;
	}
	if(dm > 122)
	{
	  month = 7;
	  dm -= 122;
	}
	if(dm > 92)
	{
	  month = 6;
	  dm -= 92;
	}
	if(dm > 61)
	{
	  month = 5;
	  dm -= 61;
	}
	if(dm > 31)
	{
	  month = 4;
	  dm -= 31;
	}
	
	
	this.Day = dm;
	this.Month = month;
	this.Year = GY;
}



function GLeap(GY)	//as bool. GY as int
{
	if(GY % 400 == 0)
		return true;
	else if(GY % 4 == 0)
	{
		if(GY % 100 == 0)
			return false;
		return true;
	}
	else return false;
}

function CGDate_MonthLength()
{
	return GMonthLength(this.Month, this.Year);
}

function GMonthLength(GM, GY)
{
	switch(GM)
	{
		case 1:	case 3:	case 5:	case 7:	case 8: case 10: case 12: return 31;
		case 2: return GLeap(GY) ? 29 : 28;
		case 4: case 6: case 9: case 11: return 30;
	}
}

function CGDate_MonthName()
{
	return GMonthName(this.Month);
}

function GMonthName(GM)
{
	switch(GM)
	{
	case 1: return "janvier";
	case 2: return "fevrier";
	case 3: return "mars";
	case 4: return "avril";
	case 5: return "mai";
	case 6: return "juin";
	case 7: return "juillet";
	case 8: return "aout";
	case 9: return "septembre";
	case 10: return "octobre";
	case 11: return "novembre";
	case 12: return "decembre";
	}
}

function CGDate_WeekdayName()
{
	var a = Math.floor((14 - this.Month) / 12);
	var y = this.Year - a;
	var m = this.Month + 12 * a - 2;
	var d = (this.Day + y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) + Math.floor(31 * m / 12)) % 7;

	switch(d)
	{
	case 0: return "dimanche";
	case 1: return "lundi";
	case 2: return "mardi";
	case 3: return "mercredi";
	case 4: return "jeudi";
	case 5: return "vendredi";
	case 6: return "samedi";
	}
}


function CHDate(HD, HM, HY)
{
	this.Day = HD;
	this.Month = HM;
	this.Year = HY;

	this.YearLength = 0;
	this.Leap = false;

	/*
	 * Methods
	 */
	this.Set = CHDate_Set;
	this.Create = CHDate_Create;
	this.Minus = CHDate_Minus;
	this.MonthLength = CHDate_MonthLength;
	this.MonthName = CHDate_MonthName;
	this.AddDays = CHDate_AddDays;
	this.Convert = CHDate_Convert;
	this.ConvertDate = CHDate_ConvertDate;
}

function CHDate_Create()
{
	var GY = this.Year - 3761;

	var GDate1 = new CGDate;
	var GDate2 = new CGDate;
	GDate1.RoshHashana(GY);
	GDate2.RoshHashana(GY + 1);
	this.YearLength = GDate2.Minus(GDate1);

	this.Leap = (this.YearLength > 355);
}

function CHDate_Minus(HDate)
{
	var days = 0;

	if(HDate.Year != this.Year)
		return null;	//Not implemented yet !!

	while(HDate.Month != this.Month)
	{
		days += HDate.MonthLength() - HDate.Day + 1;
		HDate.Day = 1;
		HDate.Month++;
		if(HDate.Month > (HDate.Leap ? 13 : 12))
			HDate.Month = 1;
	}

	days += this.Day - HDate.Day;

	return days;
}

function CHDate_Convert(GD, GM, GY)
{
	var GDate = new CGDate;
	var GRH = new CGDate;
	var days = 0;
	
	GDate.Set(GD, GM, GY);
	GRH.RoshHashana(GY);
	if((GRH.Month > GM) || ((GRH.Month == GM) && (GRH.Day > GD)))
		GRH.RoshHashana(GY-1);
	
	this.Day = 1;
	this.Month = 7;
	this.Year = GRH.Year + 3761;
	this.Create();
	days = GDate.Minus(GRH);
	this.AddDays(days);
}

function CHDate_ConvertDate(GDate)
{
	this.Convert(GDate.Day, GDate.Month, GDate.Year);
}


function CHDate_AddDays(days)
{
	while(days > 0)
	{
		if(days + this.Day > this.MonthLength())
		{
			days -= this.MonthLength() - this.Day + 1;
			this.Day = 1;
			if(this.Month == 6)
			{
				this.Month = 7;
				this.Year++;
				this.Create();
			}
			else
			{
				this.Month++;
				if(this.Month > (this.Leap ? 13 : 12))
					this.Month = 1;
			}
		}
		else
		{
			this.Day += days;
			days = 0;
		}
	}
}


function CHDate_Set(HD, HM, HY)
{
	this.Day = HD;
	this.Month = HM;
	if(HY != this.Year)
	{
		this.Year = HY;
		this.Create;
	}
}

function CHDate_MonthLength()
{
	return HMonthLength(this);
}

function HMonthLength(hdate)
{
	var month = hdate.Month;
	var yearlength = hdate.YearLength;
	var leap = hdate.Leap;

	switch(Number(month))
	{
	case 1: return 30;
	case 3: return 30;
	case 5: return 30;
	case 7: return 30;
	case 11: return 30;

	case 2: return 29;
	case 4: return 29;
	case 6: return 29;
	case 10: return 29;

	case 8: return ((yearlength == 355) || (yearlength == 385)) ? 30 : 29;
	case 9: return ((yearlength == 353) || (yearlength == 383)) ? 29 : 30;
	case 12: return (leap ? 30 : 29);
	case 13: return 29;
	}
}

function CHDate_MonthName()
{
	return HMonthName(this.Month);
}

function HMonthName(hm)
{
	switch(hm)
	{
	case 1: return "Nissan";
	case 2: return "Iyar";
	case 3: return "Sivan";
	case 4: return "Tamouz";
	case 5: return "Av";
	case 6: return "Eloul";
	case 7: return "Tishri";
	case 8: return "Heshvan";
	case 9: return "Kislev";
	case 10: return "Tevet";
	case 11: return "Shvat";
	case 12: return "Adar";
	case 13: return "Adar II";
	}
}


var myGDate = new CGDate;
var today = new Date();
var myHDate = new CHDate;
myGDate.Set(today.getDate(), today.getMonth() + 1, today.getFullYear());
myHDate.Convert(myGDate.Day, myGDate.Month, myGDate.Year);
document.write(myHDate.Day+' '+HMonthName(myHDate.Month)+' '+myHDate.Year);

