/** @file  psTime.h
 *
 *  @brief Definitions for time, time utilities, and conversion functions for use with psLib astronomy
 *  functions.
 *
 *  A collection of functions are required by psLib to manipulate time data. These functions primarily consist
 *  of conversions between specific time formats.  PSLib currently uses the UNIX timeval time system as the
 *  base upon which International Atomic Time (TAI) and Universal Time Coordinated (UTC) are calculated. TAI
 *  time varies over time due to the earth's rotation and the movement of the continental plates. It is
 *  currentls 32 seconds faster than UTC/timeval time. The conversion between TAI and UTC time for other dates
 *  is given in the table below, which comes from:
 *
 *  ftp://maia.usno.navy.mil/ser7/tai-utc.dat
 *
 *  This table is placed into a static array and used by the psTime functions for conversions.
 *
 *   1961 JAN  1 =JD 2437300.5  TAI-UTC=   1.4228180 S + (MJD - 37300.) X 0.001296 S
 *   1961 AUG  1 =JD 2437512.5  TAI-UTC=   1.3728180 S + (MJD - 37300.) X 0.001296 S
 *   1962 JAN  1 =JD 2437665.5  TAI-UTC=   1.8458580 S + (MJD - 37665.) X 0.0011232S
 *   1963 NOV  1 =JD 2438334.5  TAI-UTC=   1.9458580 S + (MJD - 37665.) X 0.0011232S
 *   1964 JAN  1 =JD 2438395.5  TAI-UTC=   3.2401300 S + (MJD - 38761.) X 0.001296 S
 *   1964 APR  1 =JD 2438486.5  TAI-UTC=   3.3401300 S + (MJD - 38761.) X 0.001296 S
 *   1964 SEP  1 =JD 2438639.5  TAI-UTC=   3.4401300 S + (MJD - 38761.) X 0.001296 S
 *   1965 JAN  1 =JD 2438761.5  TAI-UTC=   3.5401300 S + (MJD - 38761.) X 0.001296 S
 *   1965 MAR  1 =JD 2438820.5  TAI-UTC=   3.6401300 S + (MJD - 38761.) X 0.001296 S
 *   1965 JUL  1 =JD 2438942.5  TAI-UTC=   3.7401300 S + (MJD - 38761.) X 0.001296 S
 *   1965 SEP  1 =JD 2439004.5  TAI-UTC=   3.8401300 S + (MJD - 38761.) X 0.001296 S
 *   1966 JAN  1 =JD 2439126.5  TAI-UTC=   4.3131700 S + (MJD - 39126.) X 0.002592 S
 *   1968 FEB  1 =JD 2439887.5  TAI-UTC=   4.2131700 S + (MJD - 39126.) X 0.002592 S
 *   1972 JAN  1 =JD 2441317.5  TAI-UTC=  10.0       S + (MJD - 41317.) X 0.0      S
 *   1972 JUL  1 =JD 2441499.5  TAI-UTC=  11.0       S + (MJD - 41317.) X 0.0      S
 *   1973 JAN  1 =JD 2441683.5  TAI-UTC=  12.0       S + (MJD - 41317.) X 0.0      S
 *   1974 JAN  1 =JD 2442048.5  TAI-UTC=  13.0       S + (MJD - 41317.) X 0.0      S
 *   1975 JAN  1 =JD 2442413.5  TAI-UTC=  14.0       S + (MJD - 41317.) X 0.0      S
 *   1976 JAN  1 =JD 2442778.5  TAI-UTC=  15.0       S + (MJD - 41317.) X 0.0      S
 *   1977 JAN  1 =JD 2443144.5  TAI-UTC=  16.0       S + (MJD - 41317.) X 0.0      S
 *   1978 JAN  1 =JD 2443509.5  TAI-UTC=  17.0       S + (MJD - 41317.) X 0.0      S
 *   1979 JAN  1 =JD 2443874.5  TAI-UTC=  18.0       S + (MJD - 41317.) X 0.0      S
 *   1980 JAN  1 =JD 2444239.5  TAI-UTC=  19.0       S + (MJD - 41317.) X 0.0      S
 *   1981 JUL  1 =JD 2444786.5  TAI-UTC=  20.0       S + (MJD - 41317.) X 0.0      S
 *   1982 JUL  1 =JD 2445151.5  TAI-UTC=  21.0       S + (MJD - 41317.) X 0.0      S
 *   1983 JUL  1 =JD 2445516.5  TAI-UTC=  22.0       S + (MJD - 41317.) X 0.0      S
 *   1985 JUL  1 =JD 2446247.5  TAI-UTC=  23.0       S + (MJD - 41317.) X 0.0      S
 *   1988 JAN  1 =JD 2447161.5  TAI-UTC=  24.0       S + (MJD - 41317.) X 0.0      S
 *   1990 JAN  1 =JD 2447892.5  TAI-UTC=  25.0       S + (MJD - 41317.) X 0.0      S
 *   1991 JAN  1 =JD 2448257.5  TAI-UTC=  26.0       S + (MJD - 41317.) X 0.0      S
 *   1992 JUL  1 =JD 2448804.5  TAI-UTC=  27.0       S + (MJD - 41317.) X 0.0      S
 *   1993 JUL  1 =JD 2449169.5  TAI-UTC=  28.0       S + (MJD - 41317.) X 0.0      S
 *   1994 JUL  1 =JD 2449534.5  TAI-UTC=  29.0       S + (MJD - 41317.) X 0.0      S
 *   1996 JAN  1 =JD 2450083.5  TAI-UTC=  30.0       S + (MJD - 41317.) X 0.0      S
 *   1997 JUL  1 =JD 2450630.5  TAI-UTC=  31.0       S + (MJD - 41317.) X 0.0      S
 *   1999 JAN  1 =JD 2451179.5  TAI-UTC=  32.0       S + (MJD - 41317.) X 0.0      S
 *
 *  @author Ross Harman, MHPCC
 *
 *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2004-10-12 01:34:09 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */

#ifndef PSTIME_H
#define PSTIME_H

#include <time.h>
#include <sys/types.h>
#include <sys/time.h>

#include "psType.h"
#include "psImage.h"

struct psSphere;

/// @addtogroup Time
/// @{


/** Time type.
 *
 * Enumeration for psTime types, TAI or UTC time.
 */
typedef enum {
    PS_TIME_TAI,        ///< Temps Atomique International (TAI) time (time with leapseconds).
    PS_TIME_UTC,        ///< Universal Time Coordinated (UTC) time (time without leapseconds).
} psTimeType;

/** Definition of psTime.
 *
 *  The psTime struct is used by psLib to represent time values critical to
 *  astronomical calculations.  This structure represents a time which is
 *  equivalent to TAI (International Atomic Time) and is measured in both
 *  seconds and microseconds.
 */
typedef struct psTime
{
    psS64 sec;                          ///< Seconds since epoch, Jan 1, 1970.
    psU32 usec;                         ///< Microseconds since last second.
    psTimeType type;                    ///< Type of time.
}
psTime;

/** Get current time.
 *
 * Gets current time from the system clock. User must specify the psTimeType (PS_TIME_TAI or PS_TIME_UTC) in
 * the argument.
 *
 *  @return  psTime*: Struct with current time.
 */
psTime* psTimeGetTime(
    psTimeType type                     ///< Type of time to get (UTC or TAI).
);

/** Convert psTime to UTC or TAI time.
 *
 *  Converts psTime to UTC or TAI time based on the psTimeType argument.
 *
 *  @return  psTime*: Pointer to psTime.
 */
psTime* psTimeConvert(
    psTime *time,                       ///< Time to be converted.
    psTimeType type                     ///< Type to be converted to.
);

/** Convert psTime to Local Mean Sidereal Time (LST).
 *
 *  Converts psTime at the given longitude to LST time. If the input time is not in UTC format, then it is
 *  converted.
 *
 *  @return  double: LST Time.
 */
double psTimeToLST(
    psTime *time,                       ///< psTime to be converted.
    double longitude                    ///< Longitude.
);

/** Determine UT1 - UTC from table lookup.
 *
 *  This function is necessary to for various SLALIB functions.
 *
 *  @return  double: Time difference.
 */
double psTimeGetUT1Delta(
    const psTime *time                  ///< psTime to be looked up.
);

/** Determine TAI - UTC from table lookup.
 *
 *  This function is necessary to for various psTime functions.
 *
 *  @return  double: Time difference.
 */
double psTimeGetTAIDelta(
    const psTime *time                  ///< psTime to be looked up.
);

/** Determine polar coordinates at a given time.
 *
 *  Determines the orientation of the polar axis at the given time.
 *
 *  @return  psSphere*: Spherical coordinates of Earth's polar axias.
 */
struct psSphere* psTimeGetPoleCoords(
                const psTime *time                  ///< psTime determine polar orientation.
            );

/** Calculate the number of leapseconds between two times.
 *
 *  Calculates the number of leapseconds between two times.
 *
 *  @return  long: leapseconds added between given times
 */
long psTimeLeapseconds(
    const psTime* time1,                ///< First input time.
    const psTime* time2                 ///< Second input time.
);

/** Convert psTime to Julian date time.
 *
 *  Converts psTime to Julian date (JD) time. This function does not add or subtract leapseconds.
 *
 *  @return  double: Julian Date (JD) time.
 */
double psTimeToJD(
    const psTime* time                  ///< Input time to be converted.
);
/** Convert psTime to modified Julian date time.
 *
 *  Converts psTime to modified Julian date (MJD) time. This function does not add or subtract leapseconds.
 *
 *  @return  double: Modified Julian Days (MJD) time.
 */
double psTimeToMJD(
    const psTime* time                  ///< Input time to be converted.
);

/** Convert psTime to ISO8601 formatted string.
 *
 *  Converts psTime to a null terminated string in the form of YYYY-MM-DDThh:mm:ss.sss. This function does not
 *  add or subtract leapseconds.
 *
 *  @return  char*: Pointer null terminated array of chars in ISO time.
 */
char* psTimeToISOTime(
    const psTime* time                  ///< Input time to be converted.
);

/** Convert psTime to timeval time.
 *
 *  Converts psTime to timeval time. This function does not add or subtract leapseconds.
 *
 *  @return  timeval: timeval struct time.
 */
struct timeval psTimeToTimeval(
                const psTime* time                  ///< Input time to be converted.
            );

/** Convert psTime to tm time.
 *
 * Converts psTime to tm time. This function is based on a Perl algorithm availble in the Pan-STARRS Image
 * processing Algorithm Design Description (ADD). This function does not add or subtract leapseconds.
 *
 *  @return  tm: tm struct time.
 */
struct tm* psTimeToTM(
                const psTime *time                  ///< Input time to be converted.
            );

/** Convert JD to psTime.
 *
 *  Converts JD time to psTime. This function does not add or subtract leapseconds.
 *
 *  @return  psTime: time.
 */
psTime* psTimeFromJD(
    double time                         ///< Input time to be converted.
);

/** Convert MJD to psTime.
 *
 *  Converts MJD time to psTime. This function does not add or subtract leapseconds.
 *
 *  @return  psTime: time.
 */
psTime* psTimeFromMJD(
    double time                         ///< Input time to be converted.
);

/** Convert ISO to psTime.
 *
 *  Converts ISO time to psTime. This function does not add or subtract leapseconds.
 *
 *  @return  psTime*: time
 */
psTime* psTimeFromISOTime(
    const char* time                    ///< Input time to be converted.
);

/** Convert timeval to psTime.
 *
 *  Converts timeval time to psTime. This function does not add or subtract leapseconds.
 *
 *  @return  psTime*: time.
 */
psTime* psTimeFromTimeval(
    const struct timeval *time          ///< Input time to be converted.
);

/** Convert tm time to psTime.
 *
 *  Converts tm time to psTime. This function is based on a Perl algorithm availble in the Pan-STARRS Image
 * processing Algorithm Design Description (ADD). This function does not add or subtract leapseconds.
 *
 *  @return  psTime*: time.
 */
psTime* psTimeFromTM(
    const struct tm *time               ///< Input time to be converted.
);

/** Add two TAI times.
 *
 *  Adds two TAI times. This function does not add or subtract leapseconds.
 *
 *  @return  psTime*: time.
 */
psTime* psTimeAdd(
    const psTime *tai1,                 ///< First TAI time.
    const psTime *tai2                  ///< Second TAI time.
);

/** Subtract two TAI times.
 *
 *  Subtracts two TAI times. This function does not add or subtract leapseconds.
 *
 *  @return  psTime*: time.
 */
psTime* psTimeSubtract(
    const psTime *tai1,                 ///< First TAI time.
    const psTime *tai2                  ///< Second TAI time.
);


/** Find delta of two TAI times.
 *
 *  Finds the absolute difference of two TAI times. This function does not add or subtract leapseconds.
 *
 *  @return  psTime*: time.
 */
psTime* psTimeDelta(
    const psTime *tai1,                 ///< First TAI time.
    const psTime *tai2                  ///< Second TAI time.
);

/// @}

#endif
