﻿
function leap_gregorian(year)
{
    return ((year % 4) == 0) &&
            (!(((year % 100) == 0) && ((year % 400) != 0)));
}

//  GREGORIAN_TO_JD  --  Determine Julian day number from Gregorian calendar date

var GREGORIAN_EPOCH = 1721425.5;

function gregorian_to_jd(year, month, day)
{
    return (GREGORIAN_EPOCH - 1) +
           (365 * (year - 1)) +
           Math.floor((year - 1) / 4) +
           (-Math.floor((year - 1) / 100)) +
           Math.floor((year - 1) / 400) +
           Math.floor((((367 * month) - 362) / 12) +
           ((month <= 2) ? 0 :
                               (leap_gregorian(year) ? -1 : -2)
           ) +
           day);
}

//  JD_TO_GREGORIAN  --  Calculate Gregorian calendar date from Julian day

function jd_to_gregorian(jd) {
    var wjd, depoch, quadricent, dqc, cent, dcent, quad, dquad,
        yindex, dyindex, year, yearday, leapadj;

    wjd = Math.floor(jd - 0.5) + 0.5;
    depoch = wjd - GREGORIAN_EPOCH;
    quadricent = Math.floor(depoch / 146097);
    dqc = mod(depoch, 146097);
    cent = Math.floor(dqc / 36524);
    dcent = mod(dqc, 36524);
    quad = Math.floor(dcent / 1461);
    dquad = mod(dcent, 1461);
    yindex = Math.floor(dquad / 365);
    year = (quadricent * 400) + (cent * 100) + (quad * 4) + yindex;
    if (!((cent == 4) || (yindex == 4))) {
        year++;
    }
    yearday = wjd - gregorian_to_jd(year, 1, 1);
    leapadj = ((wjd < gregorian_to_jd(year, 3, 1)) ? 0
                                                  :
                  (leap_gregorian(year) ? 1 : 2)
              );
    month = Math.floor((((yearday + leapadj) * 12) + 373) / 367);
    day = (wjd - gregorian_to_jd(year, month, 1)) + 1;

    return new Array(year, month, day);
}

var ISLAMIC_EPOCH = 1948439.5;
var ISLAMIC_WEEKDAYS = new Array("al-'ahad", "al-'ithnayn",
                                 "ath-thalatha'", "al-'arb`a'",
                                 "al-khamis", "al-jum`a", "as-sabt");

function islamic_to_jd(year, month, day)
{
    return (day +
            Math.ceil(29.5 * (month - 1)) +
            (year - 1) * 354 +
            Math.floor((3 + (11 * year)) / 30) +
            ISLAMIC_EPOCH) - 1;
}

//  JD_TO_ISLAMIC  --  Calculate Islamic date from Julian day

function jd_to_islamic(jd)
{
    var year, month, day;

    jd = Math.floor(jd) + 0.5;
    year = Math.floor(((30 * (jd - ISLAMIC_EPOCH)) + 10646) / 10631);
    month = Math.min(12,
                Math.ceil((jd - (29 + islamic_to_jd(year, 1, 1))) / 29.5) + 1);
    day = (jd - islamic_to_jd(year, month, 1)) + 1;
    return new Array(year, month, day);
}

//  LEAP_PERSIAN  --  Is a given year a leap year in the Persian calendar ?

function leap_persian(year)
{
    return ((((((year - ((year > 0) ? 474 : 473)) % 2820) + 474) + 38) * 682) % 2816) < 682;
}

//  PERSIAN_TO_JD  --  Determine Julian day from Persian date

var PERSIAN_EPOCH = 1948320.5;
var PERSIAN_WEEKDAYS = new Array("Yekshanbeh", "Doshanbeh",
                                 "Seshhanbeh", "Chaharshanbeh",
                                 "Panjshanbeh", "Jomeh", "Shanbeh");

function persian_to_jd(year, month, day)
{
    var epbase, epyear;

    epbase = year - ((year >= 0) ? 474 : 473);
    epyear = 474 + mod(epbase, 2820);

    return day +
            ((month <= 7) ?
                ((month - 1) * 31) :
                (((month - 1) * 30) + 6)
            ) +
            Math.floor(((epyear * 682) - 110) / 2816) +
            (epyear - 1) * 365 +
            Math.floor(epbase / 2820) * 1029983 +
            (PERSIAN_EPOCH - 1);
}

//  JD_TO_PERSIAN  --  Calculate Persian date from Julian day

function jd_to_persian(jd)
{
    var year, month, day, depoch, cycle, cyear, ycycle,
        aux1, aux2, yday;


    jd = Math.floor(jd) + 0.5;

    depoch = jd - persian_to_jd(475, 1, 1);
    cycle = Math.floor(depoch / 1029983);
    cyear = mod(depoch, 1029983);
    if (cyear == 1029982) {
        ycycle = 2820;
    } else {
        aux1 = Math.floor(cyear / 366);
        aux2 = mod(cyear, 366);
        ycycle = Math.floor(((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) +
                    aux1 + 1;
    }
    year = ycycle + (2820 * cycle) + 474;
    if (year <= 0) {
        year--;
    }
    yday = (jd - persian_to_jd(year, 1, 1)) + 1;
    month = (yday <= 186) ? Math.ceil(yday / 31) : Math.ceil((yday - 6) / 30);
    day = (jd - persian_to_jd(year, month, 1)) + 1;
    return new Array(year, month, day);
}

function convertToHijriDate(persianDate){
    try{
        var end = 4, start = 0;
        var year = getIntFromString(persianDate.substring(0, end));
        start = end + 1;
        if(persianDate.substring(start + 1, start + 2) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var month = getIntFromString(persianDate.substring(start, end));
        start = end + 1;
        if(persianDate.substring(start, start+1) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var day = getIntFromString(persianDate.substring(start, end));
        
//        var year = getIntFromString(persianDate.substring(0,4));
//        var month = getIntFromString(persianDate.substring(5,7));
//        var day = getIntFromString(persianDate.substring(8,10));
        
        if(!isValidPersianDate(year, month, day))
        {
            if(persianDate == '')
                return '';
            else
                return 'invalid date';
         }
        var jd = persian_to_jd(year, month, day);
        
        jd += 1;
        var date = jd_to_islamic(jd);
        return date[2] + '/' + date[1] + '/' + date[0];
        //var date = jd_to_gregorian(jd);  
        //return date[1] + '/' + date[2] + '/' + date[0];
    }catch(e){
        return 'invalid date';
    }
}

function convertToGregorianDate(persianDate, throwError){
    try{
        var end = 4, start = 0;
        var year = getIntFromString(persianDate.substring(0, end));
        start = end + 1;
        if(persianDate.substring(start + 1, start + 2) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var month = getIntFromString(persianDate.substring(start, end));
        start = end + 1;
        if(persianDate.substring(start, start+1) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var day = getIntFromString(persianDate.substring(start, end));
        
//        var year = getIntFromString(persianDate.substring(0,4));
//        var month = getIntFromString(persianDate.substring(5,7));
//        var day = getIntFromString(persianDate.substring(8,10));
        
        if(!isValidPersianDate(year, month, day))
            if(throwError)
                return persianDate;
            else
                return 'invalid date';
        var jd = persian_to_jd(year, month, day);
        
        var date = jd_to_gregorian(jd);
        //return date[2] + '/' + date[1] + '/' + date[0];
        return date[1] + '/' + date[2] + '/' + date[0];
    }catch(e){
        if(throwError == true)
           throw e;
        else
            return 'invalid date';
    }
}

function isValidPersianDate(year, month, day){
    if(month <= 6){
        if(day > 31) return false;
    }else if(month < 12){
        if(day > 30) return false;
    }else if(month == 12){
        if(day > 30 || (!leap_persian(year) && day == 30))
            return false;
    }else return false;
    
    return true;
}

function getIntFromString(str){
    if(str.substring(0,1) == '0')
        str = str.substring(1,2);
    if(isNaN(str))
        return '';
    return parseInt(str);
}

function mod(a, b)
{
    return a - (b * Math.floor(a / b));
}

function cascadeDateChange(id, postFix){
    var otherId = id.substring(0, id.length - postFix.length);
    document.getElementById(otherId).value = convertToGregorianDate(document.getElementById(id).value);
}

function convertToPersianDate(gregorianDate){
    try{
        gregorianDate = normalizeGregorianDate(gregorianDate);
        var end = 2, start = 0;
        if(gregorianDate.substring(1, 2) == '/')
            end = 1;
        var month = getIntFromString(gregorianDate.substring(0, end));
        start = end + 1;
        if(gregorianDate.substring(start + 1, start + 2) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var day = getIntFromString(gregorianDate.substring(start, end));
        start = end + 1;
        var year = getIntFromString(gregorianDate.substring(start, start + 4));
        
//        if(!isValidPersianDate(year, month, day))
//            return 'invalid date';
        var jd = gregorian_to_jd(year, month, day);
        
        //jd += 1;
        var date = jd_to_persian(jd);
        //return date[2] + '/' + date[1] + '/' + date[0];
        //var date = jd_to_gregorian(jd);
        if(!isNaN(date[0]) && !isNaN(date[1]) && !isNaN(date[2]))  
            return date[0] + '/' + date[1] + '/' + date[2];
        else
            throw "empty";
    }catch(e){
        return 'invalid date';
    }
}

function normalizeGregorianDate(gregorianDate){
    var prefix = gregorianDate.substring(0, 2);
    if(prefix == '19' || prefix == '20'){
        var year = gregorianDate.substring(0, 4);
        var end = 7, start = 5;
        if(gregorianDate.substring(6, 7) == '/')
            end = 6;
        var month = gregorianDate.substring(start, end);
        start = end + 1;
        if(gregorianDate.substring(start + 1, start + 2) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var day = gregorianDate.substring(start, end);
        
        return month + '/' + day + '/' + year;
    }
    return gregorianDate;
}

function cascadeGrToPersian(id, postFix){
    var otherId = id.substring(0, id.length - postFix.length);
    var val = document.getElementById(otherId).value;
    if(val != '')
        document.getElementById(id).value = convertToPersianDate(val);
    else
        document.getElementById(id).value = '';
}

function cascadeHijriDateChange(persianBox, baseBox){
    document.getElementById(baseBox).value = convertToHijriDate(document.getElementById(persianBox).value);
}

function convertHijriToPersianDate(hijriDate){
    try{
        //hijriDate = normalizeGregorianDate(hijriDate);
        var end = 2, start = 0;
        if(hijriDate.substring(1, 2) == '/')
            end = 1;
        var day = getIntFromString(hijriDate.substring(0, end));
        start = end + 1;
        if(hijriDate.substring(start + 1, start + 2) == '/')
            end = start + 1;
        else
            end = start + 2;
        
        var month = getIntFromString(hijriDate.substring(start, end));
        start = end + 1;
        var year = getIntFromString(hijriDate.substring(start, start + 4));
        
//        if(!isValidPersianDate(year, month, day))
//            return 'invalid date';
        var jd = islamic_to_jd(year, month, day);
        
        //jd += 1;
        var date = jd_to_persian(jd);
        //return date[2] + '/' + date[1] + '/' + date[0];
        //var date = jd_to_gregorian(jd);
        if(!isNaN(date[0]) && !isNaN(date[1]) && !isNaN(date[2]))  
            return date[0] + '/' + date[1] + '/' + date[2];
        else
            throw "empty";
    }catch(e){
        return 'invalid date';
    }
}