#if !defined (PS_TIME_H)
#define PS_TIME_H

/** Defines time type */
typedef enum {
    PS_TIME_TAI,                    ///< seconds since 1970-01-01T00:00:00Z (Gregorian)
    PS_TIME_UTC,                    ///< seconds since 1970-01-01T00:00:00Z (Gregorian)
} psTimeType;

/** The time */
typedef struct {
    psS64            sec;           ///< seconds, negative values represent dates before 1970
    psU32            usec;          ///< microseconds
    psTimeType       type;          ///< type of time
} psTime;


/** Get the current system time */
psTime *psTimeGetTime(psTimeType type	///< Type of time
		      );

/** Convert between time types */
psTime *psTimeConvert(psTime *time,	///< Time to convert, and output
		      psTimeType type	///< Type to convert to
    );

/** Convert to local sidereal time */
psTime *psTimeToLST(psTime *time,	///< Time to convert, and output
		    double longitude	///< Latitude for LST
    );

/** Convert from local sidereal time */
psTime *psTimeFromLST(psTime *time,	///< Time to convert, and output
		      double longitude	///< Latitude for LST
    );

/** Get UT1 - UTC */
double psTimeGetUT1Delta(const psTime *time	///< Time for which to return UT1-UTC difference
    );

/** Return pole coordinates */
psSphere *psTimeGetPoleCoords(const psTime *time ///< Time for which to return pole coordinates
    );

/** Return Julian Date */
psF64 psTimeToJD(const psTime *time);

/** Return Modified Julian Date */
psF64 psTimeToMJD(const psTime *time);

/** Return ISO time string */
char *psTimeToISOTime(const psTime *time);

/** Return a timeval structure */
timeval *psTimeToTimeval(const psTime *time);

/** Convert Julian Date to psTime */
psTime *psTimeFromJD(psF64 input);

/** Convert Modified Julian Date to psTime */
psTime *psTimeFromMJD(psF64 input);

/** Convert ISO time string to psTime */
psTime *psTimeFromISO(const char *input);

/** Convert a timeval structure to psTime */
psTime *psTimeFromTimeval(const timeval *input);

/** Add two times */
psTime *psTimeAdd(const psTime *tai1,	///< Time to which to add
		  psF64 delta		///< Number of TAI seconds to add
    );

/** Subtract two times, TAI seconds */
psF64 psTimeSub(const psTime *time1, const psTime *time2);

/** Get absolute time difference between two times */
psF64 psTimeDelta(const psTime *time1, const psTime *time2);

// A table of UT1-UTC and polar coordinates
typedef struct {
    const char *filename;		// Filename of time table
    const psF64 validFrom, validTo;	// MJDs of validity of time table
    bool loaded;			// Has the table been loaded?
    psVector *mjd;			// MJD data, type is psF64
    psVector *dut;			// delta UT = UT1 - UTC data
    psVector *xp, *yp;			// Polar motion data
} psTimeTable;

// Constructor --- don't load
psTimeTable *psTimeTableAlloc(const char *filename, // Filename of time table
			      psF64 validFrom,	// The time table is valid from this MJD
			      psF64 validTo // The time table is valid to this MJD
			      );

// Load a time table, return true for success
bool psTimeTableLoad(psTimeTable *table	// Time table to load
		     );

// Interpolate on a table, return true if given MJD is within the given range
bool psTimeTableInterpolate(const psTimeTable *table, // Table to interpolate on
			    double *xp,	// Output x_p, or NULL
			    double *yp,	// Output y_p, or NULL
			    double *dut,// Output UT1-UTC, or NULL
			    psF64 mjd	// MJD at which to interpolate
			    );

// Time tables
static psArray *timeTables;
// Time configuration
static psMetadata *timeConfig;

#endif
