/*******************************************************************************
 * JMMC project ( http://www.jmmc.fr ) - Copyright (C) CNRS.
 ******************************************************************************/
/**
 * @file
 * Useful functions related to date.
 * 
 * Routines to convert to and from ISO 8601 date to Modified Julian Day
 * Based on formulae by Tom Van Flandern in the UseNet newsgroup sci.astro.
 * cast into C by Raymond Gardner.
 */

#define _POSIX_SOURCE 1

/*
 * System Headers
 */
#include <stdlib.h>
#include <string.h>

/*
 * Local Headers
 */
#include "amdlib.h"
#include "amdlibProtected.h"

/*
 * Local function
 */
static void amdlibJDNL2YMD(int jdn, int *yy, int *mm, int *dd);

/*
 * Protected functions
 */

/**
 * Return the radians equivalent of a input double in sexagesimal coding 
 * (like -hhmmss.sss or dddmmss.ss). The 24 (hours) or 180 (degrees) flavor
 * is given by the code parameter.
 *  *
 * @param value the sexagesimal value as a double
 * @param code an int code either 24 or 180 telling if these are hours 
 * or degrees.
 * 
 * @return an angle in radians in double precision.
 */
double amdlibSexagToRad(double value, int code)
{
    int hour=0, min=0, sign;
    double dh, dm, val, tmp;
    double second=0.0;
    val=value;
    sign=1;
    
    if (val<0.0) 
    {
        sign=-1;
        val=-1*val;
    }
    hour=val;
    dh=hour;
    dh/=10000.0;
    hour=dh;
    val=val-hour*10000.0;
    min=val;
    dm=min;
    dm/=100.0;
    min=dm;
    second=val-min*100;
    tmp=sign*(hour+min/60.0+second/3600.0);
    if(code==24)
    {
        tmp=tmp*15; 
    }
    tmp=tmp*M_PI/180.0;
    return(tmp);
}

/**
 * Convert Modified Julian Day date to Standard ISO date
 *
 * This function convert the given Modified Julian day date to ISO Standard date
 * and format this date as string in the following format
 * "YYYY-MM-DDThh:mm:ss.ssss".
 *
 * @param mjd Modified Julian Day date.
 *
 * @return
 * Standard ISO date as string
 */
char *amdlibMJD2ISODate(double mjd)
{
    int day=0, year=0, month=0;
    int hour=0, min=0;
    double second=0.0;
    
    /* Julian date */
    int jdn;
    double fd;
    static char isoDate[32];
    
    amdlibLogTrace("MJD2ISODate()"); 

    memset (isoDate, '\0', sizeof(*isoDate));

    /* Get the integral value; integral number of days */
    jdn =(int)mjd;

    /* Get the decimal value */
    fd  = mjd-jdn;
    
    /* And convert it in hours, minutes and seconds */ 
    fd  *= 24.0;
    hour = (int)fd;
    fd  -= hour;
    fd  *= 60.0;
    min  = (int)fd;
    fd  -= min;
    second = fd * 60.0;

    /* Convert MJD to JD */
    jdn += 2400001;

    /* Get year, month and day form JD */
    amdlibJDNL2YMD(jdn, &year, &month, &day);
 
    /* aramirez-20060720                    */
    /* Changed seconds format 6.4f -> 07.4f */
    sprintf(isoDate,"%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%07.4f", 
            year, month, day ,hour,min,second);

    return (isoDate);
}

/**
 * Convert Julian Day date to year, month and day 
 *
 * @param jdn Julian Day date.
 * @param yy year.
 * @param mm month.
 * @param dd day.
 */
void amdlibJDNL2YMD(int jdn, int *yy, int *mm, int *dd)
{
    int x, z, m, d, y;
    int daysPer400Years = 146097L;
    int fudgedDaysPer4000Years = 1460970L + 31;

    amdlibLogTrace("amdlibJDNL2YMD()");

    x = jdn + 68569L;
    z = 4 * x / daysPer400Years;
    x = x - (daysPer400Years * z + 3) / 4;
    y = 4000 * (x + 1) / fudgedDaysPer4000Years;
    x = x - 1461 * y / 4 + 31;
    m = 80 * x / 2447;
    d = x - 2447 * m / 80;
    x = m / 11;
    m = m + 2 - 12 * x;
    y = 100 * (z - 49) + y + x;

    *yy = (int)y;
    *mm = (int)m;
    *dd = (int)d;

    if (*yy <= 0)  
    {
        (*yy)--;  /* Adjust Before Christ(BC) years */
    }
}


/*___oOo___*/
