/*
*  Copyright (C) 2007 David Chin
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with with program; see the file COPYING. If not, write to the
*  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
*  MA  02110-1301  USA
*/

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>

#include <lal/LALStdlib.h>
#include <lal/Date.h>
#include <lal/AVFactories.h>


int main(void)
{
  LIGOTimeGPS         gpsTime = {0, 0};
  LIGOTimeGPS         tmpGps  = {0, 0};
  struct tm           utcDate;
  CHARVector         *timestamp = NULL;
  char                refstamp[128];
  /* char                infostr[256]; */

  timestamp = XLALCreateCHARVector(128);

  /*
   * GPS 0 == 1980-01-06 00:00:00 UTC Sun
   */
  if(!XLALGPSToUTC(&utcDate, gpsTime.gpsSeconds))
    {
      fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }

  strftime(timestamp->data, timestamp->length, "%F %T UTC %a", &utcDate);

  sprintf(refstamp, "1980-01-06 00:00:00 UTC Sun");

  if (lalDebugLevel > 0)
    {
      fprintf(stderr, "refstamp  = %s\n", refstamp);
      fprintf(stderr, "timestamp = %s\n", timestamp->data);
    }

  if (strcmp(refstamp, timestamp->data) != 0)
    {
      fprintf(stderr, "XLALGPStoUTC conversion failed: wrong UTC result\n");
      fprintf(stderr, "TestGPStoUTC: date strings do not match, line %i, %s\n",
              __LINE__, "$Id$");
      XLALDestroyCHARVector(timestamp);
      return 1;
    }

  /*
   * GPS 457574400 == 1994-07-06 23:59:50 UTC Wed
   */
  gpsTime.gpsSeconds = 457574400;
  gpsTime.gpsNanoSeconds = 0;

  if(!XLALGPSToUTC(&utcDate, gpsTime.gpsSeconds))
    {
      fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }

  strftime(timestamp->data, timestamp->length, "%F %T UTC %a", &utcDate);

  sprintf(refstamp, "1994-07-06 23:59:50 UTC Wed");

  if (lalDebugLevel > 0)
    {
      fprintf(stderr, "refstamp  = %s\n", refstamp);
      fprintf(stderr, "timestamp = %s\n", timestamp->data);
    }

  if (strcmp(refstamp, timestamp->data) != 0)
    {
      fprintf(stderr, "GPStoUTC conversion failed: wrong UTC result\n");
      XLALDestroyCHARVector(timestamp);
      return 1;
    }

  /*
   * GPS 599184012 == 1998-12-31 23:59:60 UTC Thu (leap second introduced)
   */
  gpsTime.gpsSeconds = 599184012;
  gpsTime.gpsNanoSeconds = 0;

  if(!XLALGPSToUTC(&utcDate, gpsTime.gpsSeconds))
    {
      fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }

  strftime(timestamp->data, timestamp->length, "%F %T UTC %a", &utcDate);

  sprintf(refstamp, "1998-12-31 23:59:60 UTC Thu");

  if (lalDebugLevel > 0)
    {
      fprintf(stderr, "refstamp  = %s\n", refstamp);
      fprintf(stderr, "timestamp = %s\n", timestamp->data);
    }

  if (strcmp(refstamp, timestamp->data) != 0)
    {
      fprintf(stderr, "GPStoUTC conversion failed: wrong UTC result\n");
      XLALDestroyCHARVector(timestamp);
      return 1;
    }

  /*
   * UPDATEME
   * GPS 835747214 == 2006-07-01 00:00:00 (one second past expiry)
   * Expect to fail with status code 5
   * (see the static constant maxtestedGPS in src/GPStoUTC.c)
   */
  gpsTime.gpsSeconds     = 835747214; /* use maxtestedGPS + 1 */
  gpsTime.gpsNanoSeconds = 0;

  if(!XLALGPSToUTC(&utcDate, gpsTime.gpsSeconds))
    {
      fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }

  strftime(timestamp->data, timestamp->length, "%F %T UTC %a", &utcDate);

  /* UPDATEME */
  /* the date here should be one second after maxtestedGPS */
  sprintf(refstamp, "2006-07-01 00:00:00 UTC Sat");

  if (lalDebugLevel > 0)
    {
      fprintf(stderr, "refstamp  = %s\n", refstamp);
      fprintf(stderr, "timestamp = %s\n", timestamp->data);
    }

  if (strcmp(refstamp, timestamp->data) != 0)
    {
      fprintf(stderr, "GPStoUTC conversion failed: wrong UTC result\n");
      XLALDestroyCHARVector(timestamp);
      return 1;
    }


  /*
   * GPS -44000
   * should fail.  No leap seconds, yet.
   */
  gpsTime.gpsSeconds     = -44000;
  gpsTime.gpsNanoSeconds = 0;

  if(!XLALGPSToUTC(&utcDate, gpsTime.gpsSeconds))
    {
    if (XLALGetBaseErrno() != XLAL_EDOM) /* not expected error */
        {
          fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
                  __LINE__, "$Id$");
          return 1;
        }
    }
  else /* no error */
    {
      fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }
  XLALClearErrno();

  /*
   * Now, let's try converting GPS to UTC and back
   */
  gpsTime.gpsSeconds     = 701654354;
  gpsTime.gpsNanoSeconds = 0;

  if(!XLALGPSToUTC(&utcDate, gpsTime.gpsSeconds))
    {
      fprintf(stderr, "TestGPStoUTC: XLALGPSToUTC() failed, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }

  XLALGPSSet(&tmpGps, XLALUTCToGPS(&utcDate), 0);
  if (XLALGetBaseErrno() && lalDebugLevel > 0)
    {
      fprintf(stderr,
              "TestUTCtoGPS: error in XLALUTCToGPS, line %i, %s\n",
              __LINE__, "$Id$");
      return 1;
    }

  if (lalDebugLevel > 0)
    {
      fprintf(stderr, "\tgpsTime = {%d, %d}\n", gpsTime.gpsSeconds,
              gpsTime.gpsNanoSeconds);
      fprintf(stderr, "\ttmpGps  = {%d, %d}\n", tmpGps.gpsSeconds,
              tmpGps.gpsNanoSeconds);
    }


  if (tmpGps.gpsSeconds     != gpsTime.gpsSeconds ||
      tmpGps.gpsNanoSeconds != gpsTime.gpsNanoSeconds)
    {
      fprintf(stderr,
              "TestGPStoUTC: conversion from GPS to UTC and back to GPS failed, line %i, %s\n", __LINE__, "$Id$");
      return 1;
    }



  /*
   * Cleanup and exit
   */
  XLALDestroyCHARVector(timestamp);
  LALCheckMemoryLeaks();
  return 0;
}
