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 "Février";
    case 3: return "Mars";
    case 4: return "Avril";
    case 5: return "Mai";
    case 6: return "Juin";
    case 7: return "Juillet";
    case 8: return "Août";
    case 9: return "Septembre";
    case 10: return "Octobre";
    case 11: return "Novembre";
    case 12: return "Décembre";
    }
}

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";
    }
}


function HebrewMonthToString(nMonth)
{
    var aMonths = new Array ("ניסן", "איר", "סיון", "תמוז", "אב", "אלול", "תשרי", "חשון", "כסלו", "טבת", "שבט", "אדר", "ואדר");
    return aMonths[nMonth - 1];
}

function HebrewNumberToString(N, bNoSeparator)
{
    if(isNaN(N))
        return N;
    
    if(N == 15)
        return "ט\"ו";
    
    var sAlefBet =          "אבגדהוזחטיכלמנסעפצקרשת";
//  var sAlefBetSofit = "אבגדהוזחטיךלםןסעףץקרשת";
    var sAlefBetSofit =             "אבגדהוזחטיכלמנסעפצקרשת";

    var aValues = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400);
    var s = "";
    var i = 21;
    var n = N;

    while(n >= 1)
    {
        while(n >= aValues[i])
        {
            if(n == aValues[i])
            {
                if(s.length > 0)
                    s += (bNoSeparator == true ? "" : "\"") + sAlefBetSofit.charAt(i);
                else
                    s =  sAlefBetSofit.charAt(i) + (bNoSeparator == true ? "" : "\"");
            }
            else
                s += sAlefBet.charAt(i);
                
            n -= aValues[i];
        }
        
        i --;
    }
    
    return s;
}

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(myGDate.WeekdayName()+' '+today.getDate()+' '+GMonthName(today.getMonth() + 1)+' '+today.getFullYear() + '&nbsp; | &nbsp;');
document.write(myHDate.Day+' '+HMonthName(myHDate.Month)+' '+myHDate.Year);
