var MARS_TO_EARTH_DAYS = 1.0274913;
//var MARS_TO_EARTH_DAYS = 1.0274895;
var EPOCH_OFFSET = 721703.94875;
//var EPOCH_OFFSET = 721016.55828;
var ROUND_UP_SECOND = 1/86400;
var eDaysTilMonth = new Array( -1, -1,
 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333);
var eDaysInMonth = new Array( 0, 31, 29, 31, 30, 31, 30, 31, 31,
 30, 31, 30, 31);

function getEarthDaysFromForm()
{
    var year = parseInt(document.calc.eYear.value, 10);
    var month= parseInt(document.calc.eMonth.value,10);
    var day  = parseInt(document.calc.eDay.value,  10);

    var daysSince = day + eDaysTilMonth[month]
        + 365 * year
        + Math.floor(year / 4)
        - Math.floor(year / 100)
        + Math.floor(year / 400)

    if((month < 3)
      && isEarthLeapYear(year))
        daysSince -= 1;

    var hour = parseInt(document.calc.eHour.value, 10)/24
    var min  = parseInt(document.calc.eMin.value, 10)/1440
    var sec  = parseInt(document.calc.eSec.value, 10)/86400;

    if(!isNaN(hour)) daysSince += hour;
    if(!isNaN(min))  daysSince += min;
    if(!isNaN(sec))  daysSince += sec;

    return daysSince;
}


function getMarsSolsFromForm()
{
    var year = parseInt(document.calc.mYear.value, 10);
    var month= parseInt(document.calc.mMonth.value,10);
    var day  = parseInt(document.calc.mDay.value,  10);

    var solsSince = day + ((month-1) * 28) - Math.floor((month-1)/6)
        + 668 * year
          + Math.floor(year / 2)
          + Math.floor((year-1) / 10)
          - Math.floor((year-1) / 100)
          + Math.floor((year-1) / 500);

    var hour = parseInt(document.calc.mHour.value, 10)/24
    var min  = parseInt(document.calc.mMin.value, 10)/1440
    var sec  = parseInt(document.calc.mSec.value, 10)/86400;

    if(!isNaN(hour)) solsSince += hour;
    if(!isNaN(min))  solsSince += min;
    if(!isNaN(sec))  solsSince += sec;

    return solsSince;
}

function setMarsDateFromSols(solsSince)
{
    // get the fractional part, to do the time later
    partialSol = solsSince - Math.floor(solsSince);

    // Convert sols to Martian date:
    var s = solsSince;
 
    var sD  = Math.floor(s/334296);
    var doD = Math.floor(s-(sD*334296));
 
    var sC = 0;
    var doC = doD;
    if(doD != 0) sC = Math.floor((doD-1)/66859);
    if(sC != 0) doC -= (sC*66859+1);

    var sX = 0;
    var doX = doC;
    if(sC != 0)  // century that does not begin with leap day
    {
      sX = Math.floor((doC+1)/6686);
      if(sX != 0) doX -= (sX*6686-1);
    }
    else
    {
      sX = Math.floor(doC/6686);
      if(sX != 0) doX -= (sX*6686);
    }

    var sII = 0;
    var doII = doX;
    if(sC != 0 && sX == 0)  // decade that does not begin with leap day
    {
      sII = Math.floor(doX/1337);
      if(sII != 0) doII -= (sII*1337);
    }
    else  // 1338, 1337, 1337, 1337 ...
    {
      if(doX != 0) sII = Math.floor((doX-1)/1337);
      if(sII != 0) doII -= (sII*1337+1);
    }

    var sI = 0;
    var doI= doII;
    if(sII==0 && (sX != 0 || (sX == 0 && sC == 0)))
    {
      sI = Math.floor(doII/669);
      if(sI != 0) doI -= 669;
    }
    else  // 668, 669
    {
      sI = Math.floor((doII+1)/669);
      if(sI != 0) doI -= 668;
    }

    marsYear = 500*sD + 100*sC + 10*sX + 2*sII + sI;


    // get the date from the day of the year:

    var tmpSeason = getMartianSeasonFromSol(doI);            // 0-3
    var tmpSolOfSeason = doI-167*tmpSeason;                  // 0-167
    var tmpMonthOfSeason = Math.floor(tmpSolOfSeason/28);    // 0-5

    var marsMonth = tmpMonthOfSeason + 6*tmpSeason + 1;      // 1-24

    var marsDay   = doI - ((marsMonth-1)*28 - tmpSeason) + 1;  // 1-28

    // Put the result up:

    document.calc.mYear.value = marsYear;
    document.calc.mMonth.value = marsMonth;
    document.calc.mDay.value = marsDay;

    var tmpHour = partialSol*24;
    var tmpMin  = (tmpHour - Math.floor(tmpHour))*60;
    var tmpSec  = (tmpMin - Math.floor(tmpMin))*60;
    document.calc.mHour.value = Math.floor(tmpHour);
    document.calc.mMin.value  = twoDigit(tmpMin);
    document.calc.mSec.value  = twoDigit(tmpSec);
}

function setEarthDateFromDays(daysSince)
{
    // get the fractional part, to do the time later
    partialDay = daysSince - Math.floor(daysSince);

    // Convert days to Gregorian date:

    var d = Math.floor(daysSince)+1;

    var sCD = Math.floor(d/146097);   // what 400 year span
    var doCD= Math.floor(d-(sCD*146097));

    var sC = 0;
    var doC = doCD;
    if(doCD != 0) sC = Math.floor((doCD-1)/36524);
    if(sC != 0) doC -= (sC*36524+1);

    var sIV = 0;
    var doIV = doC;
    if(sC != 0)  // 1460 + 1461*24
    {
      sIV = Math.floor((doC+1)/1461);
      if(sIV != 0) doIV -= (sIV*1461-1);
    }
    else  // 1461*25
    {
      sIV = Math.floor(doC/1461);
      if(sIV != 0) doIV -= (sIV*1461);
    }

    var sI = 0;
    var doI = doIV;
    if(sC != 0 && sIV == 0)  // four 365-day years in a row
    {
      sI = Math.floor(doIV/365);
      if(sI != 0) doI -= (sI*365);
    }
    else   // normal leap year cycle
    {
      if(doI != 0) sI = Math.floor((doIV-1)/365);
      if(sI != 0) doI -= (sI*365 + 1);
    }

    earthYear = 400*sCD + 100*sC + 4*sIV + sI;
    var tmpDayOfYear = doI+1;

    for(i=1; i<12; i++)
    {
        var tmpDaysInMonth = eDaysInMonth[i];
        if(i==2 && !isEarthLeapYear(earthYear))
            tmpDaysInMonth -= 1;

        if(tmpDayOfYear > tmpDaysInMonth)
            tmpDayOfYear -= tmpDaysInMonth;
        else
            break;
    }

    earthMonth = i;
    earthDay = tmpDayOfYear;


    // Put the result up:

    document.calc.eYear.value = earthYear;
    document.calc.eMonth.value = earthMonth;
    document.calc.eDay.value = earthDay;

    var tmpHour = partialDay*24;
    var tmpMin  = (tmpHour - Math.floor(tmpHour))*60;
    var tmpSec  = (tmpMin - Math.floor(tmpMin))*60;
    document.calc.eHour.value = Math.floor(tmpHour);
    document.calc.eMin.value  = twoDigit(tmpMin);
    document.calc.eSec.value  = twoDigit(tmpSec);
}


function convEarthToMars()
{
    var daysSince, solsSince, partialSol;
    var marsYear, marsMonth, marsDay;

    // Range checking:

    if(document.calc.eYear.value < 0)
    {
        alert("Pas op: data voor het jaar 1 kunnen er iets naast zitten.");
    }
    else if(document.calc.eYear.value < 1582)
    {
        alert("Pas op: de Gregoriaanse kalender bestond nog niet echt in dat jaar.");
    }
    else if(document.calc.eYear.value < 1753)
    {
        alert("Pas op: de Gregoriaanse kalender is in Nederland pas ingevoerd in de 17de eeuw.");
    }

    if(document.calc.eMonth.value < 1
     || document.calc.eMonth.value > 12)
    {
        alert("Er is nog geen maand ingevuld...");
        return;
    }

    if(document.calc.eDay.value < 1
     || document.calc.eDay.value > eDaysInMonth[document.calc.eMonth.value]
     || (!isEarthLeapYear(document.calc.eYear.value)
       && document.calc.eMonth.value==2
       && document.calc.eDay.value > 28))
    {
        alert("Zoveel dagen zitten er niet in een maand op Aarde.");
        return;
    }


    // Convert to straight days:

    daysSince = getEarthDaysFromForm();

    if(document.calc.eTZ.options[document.calc.eTZ.selectedIndex].text == "Plaatselijke")
      daysSince += (new Date()).getTimezoneOffset()/1440;
    else
      daysSince +=
        document.calc.eTZ.options[document.calc.eTZ.selectedIndex].value/1440;

    // Convert days to sols:

    solsSince = (daysSince - EPOCH_OFFSET) / MARS_TO_EARTH_DAYS;

    solsSince +=
      document.calc.mTZ.options[document.calc.mTZ.selectedIndex].value/1440;

    // Convert back to date, and put it it form:
    setMarsDateFromSols(solsSince);
}

function convMarsToEarth()
{
    var solsSince, daysSince, partialDay;
    var eYear, eMonth, eDay;

    // Range checking:
    if(document.calc.mMonth.value < 1
     || document.calc.mMonth.value > 24)
    {
        alert("Er is nog geen maand ingevuld...");
        return;
    }

    if(document.calc.mDay.value < 1
     || document.calc.mDay.value > 28
     || (document.calc.mMonth.value % 6 == 0
       && document.calc.mDay.value == 28
       && !(document.calc.mMonth.value == 24
         && isMartianLeapYear(document.calc.mYear.value))))
    {
        alert("Zoveel dagen zitten er niet in deze maand.");
        return;
    }

    // Convert Martian date to sols:

    solsSince = getMarsSolsFromForm();

    solsSince -=
      document.calc.mTZ.options[document.calc.mTZ.selectedIndex].value/1440;

    // Convert sols to days:

    daysSince = solsSince*MARS_TO_EARTH_DAYS + EPOCH_OFFSET
      + ROUND_UP_SECOND;

    if(document.calc.eTZ.options[document.calc.eTZ.selectedIndex].text == "Plaatselijke")
      daysSince -= (new Date()).getTimezoneOffset()/1440;
    else
      daysSince -=
        document.calc.eTZ.options[document.calc.eTZ.selectedIndex].value/1440;

    // Convert back to date, and put it it form:
    setEarthDateFromDays(daysSince);
}

function daysInEarthYear(year)
{
    if(isEarthLeapYear(year)) return 366;
    else return 365;
}

function isEarthLeapYear(year)
{
    if((year % 400) == 0) return true;
    if((year % 100) == 0) return false;
    if((year %   4) == 0) return true;
    return false;
}

function getMartianSeasonFromSol(sol)
  {
    if(sol < 167) return 0;
    if(sol < 334) return 1;
    if(sol < 501) return 2;
    return 3;
  }

function daysInMartianYear(year)
{
    if(isMartianLeapYear(year)) return 669;
    else return 668;
}

function isMartianLeapYear(year)
{
    if((year % 500) == 0) return true;
    if((year % 100) == 0) return false;
    if((year %  10) == 0) return true;
    if((year %   2) == 0) return false;
    return true;
}

function twoDigit(n)
{
  if(n<10) return "0"+Math.floor(n);
  else return Math.floor(n);
}

function insertNow()
{
    d = new Date();

    if(d.getYear()>1999) document.calc.eYear.value = d.getYear();
    else document.calc.eYear.value = d.getYear() + 1900;

    document.calc.eMonth.value= twoDigit(d.getMonth() + 1);
    document.calc.eDay.value  = twoDigit(d.getDate());
    document.calc.eHour.value = d.getHours();
    document.calc.eMin.value  = twoDigit(d.getMinutes());
    document.calc.eSec.value  = twoDigit(d.getSeconds());
    document.calc.eTZ.selectedIndex = 1;    // set Time Zone to local

    convEarthToMars();
}


