/** @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.  They use the UNIX timeval time system as the
 *  base upon which International Atomic Time (TAI) and Universal Time Coordinated (UTC) are calculated.
 *
 *  @author Ross Harman, MHPCC
 *
 *  @version $Revision: 1.20 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2004-12-16 18:52:51 $
 *
 *  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;


/** Initialize time data.
 *
 * Reads config and data files associated with various time conversions.
 *
 * @return  bool: True for success, false for failure.
 */
psBool p_psTimeInit(const char *fileName);

/** Free memory persistant time data.
 *
 * Frees time data to be held in memory until the end of successful program execution.
 *
 * @return  void: void.
 */
psBool p_psTimeFinalize(void);

/** Allocate time struct.
 *
 * Allocates an empty time struct. User must specify the psTimeType (PS_TIME_TAI or PS_TIME_UTC) in the argument.
 * The seconds and microseconds members of the struct are set to zero.
 *
 * @return  psTime*: Struct with empty time.
 */
psTime* psTimeAlloc(
    psTimeType type                     ///< Type of time to create (UTC or TAI).
);

/** 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  psS64: leapseconds added between given times
 */
psS64 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.
);

/** Adds delta to time. Result is in TAI time.
 *
 *  Adds delta to time. Input time is converted to TAI format if necessary.
 *
 *  @return  psTime*: time.
 */
psTime* psTimeMath(
    const psTime *time,                 ///< Time.
    psF64 delta                         ///< Time delta.
);

/** Determine difference between two times. Result is in TAI time.
 *
 *  Determine difference between two times. Input times are converted to TAI format if necessary.
 *
 *  @return psF64: Time difference.
 */
psF64 psTimeDelta(
    const psTime *time1,                ///< First time.
    const psTime *time2                 ///< Second time.
);

/// @}

#endif
