
#include "ObsCoreTime.hpp"

#include "io.hpp"

#include <cmath> // isnan() needed

using namespace std;


const std::string SqlNull = "NULL";
const unsigned long SecsInDay = 86400;

//----------------------------------------------------------------
// ISO8601 -> Modified Julian Date
//----------------------------------------------------------------

double fitsdate2MJD(const string fitsdate)
{
   LOG_trace(__func__);

   int y,M,d,h,m;
   float s;
   sscanf(fitsdate.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s);

   LOG_STREAM<<"DBGTIME: "<<fitsdate<< " : " << y << " " << M << " " << d << " t " << h << " " << m << " " << s << endl;

   unsigned long jdn = (1461 * (y + 4800 + (M-14)/12))/4 + \
                       (367  * (M - 2 - 12*((M-14)/12)))/12 - \
                       (3    * ((y + 4900 + (M - 14)/12)/100))/4 + d - 32075 ;

   double mjd = (double)jdn;

   double ttt = (h-12)/24.0 + m/1440.0 + s/86400.0;

   mjd += ttt;

   LOG_STREAM << "DBGTIME MJD: " << mjd << endl;

   return mjd;
}



//----------------------------------------------------------------
// FIXME if use map<> and returns strings:
// also Card-not-present case handled by setting SqlNull in ObsCore
//----------------------------------------------------------------
obscore::ObsCoreTime obscore::calcObsCoreTime(std::string DATEOBS, std::string DATEEND)
{
   struct obscore::ObsCoreTime ocTime;

   if(!DATEOBS.empty())
   {
      ocTime.t_min = fitsdate2MJD(DATEOBS.c_str());
      if(std::isnan(ocTime.t_min))
      {
         LOG_STREAM << "DBGTIME t_min in NaN : " << ocTime.t_min << endl;
         ocTime.t_min_str = SqlNull;
      }
      else if (ocTime.t_min < 0.0)
      {
         LOG_STREAM << "DBGTIME t_min is negative : " << ocTime.t_min << endl;
         ocTime.t_min_str = SqlNull;
      }
      else
      {
         ocTime.t_min_str = to_string(ocTime.t_min);
      }
   }
   else
   {
      ocTime.t_min_str = SqlNull;
   }

   if(!DATEEND.empty())
   {
      ocTime.t_max = fitsdate2MJD(DATEEND.c_str());
      if(std::isnan(ocTime.t_max))
      {
         LOG_STREAM << "DBGTIME t_max in NaN : " << ocTime.t_max << endl;
         ocTime.t_max_str = SqlNull;
      }
      else if (ocTime.t_max < 0.0)
      {
         LOG_STREAM << "DBGTIME t_max is negative : " << ocTime.t_max << endl;
         ocTime.t_max_str = SqlNull;
      }
      else
      {
         ocTime.t_max_str = to_string(ocTime.t_max);
      }
   }
   else
   {
      ocTime.t_max_str = SqlNull;
   }

   if( 0)//t_min_str.compare(SqlNull) && t_max_str.compare(SqlNull) )
   {
      double dSecsInDay = double(SecsInDay);
      ocTime.t_exptime = (ocTime.t_max - ocTime.t_min) * dSecsInDay; // [sec]
      ocTime.t_exptime_str = to_string(ocTime.t_exptime);
   }
   else
   {
      ocTime.t_exptime_str = SqlNull;
   }

   // FIXME not implemented: need to define on how to calc

   ocTime.t_resolution_str  = SqlNull;
   ocTime.t_xel_str         = SqlNull;
   /*
      DEBUG_STREAM<<"DBGTIME: "
      << ocTime.t_min
      << " "
      << ocTime.t_max
      << " -> "
      << ocTime.t_exptime
      << endl;
      */
   return ocTime;
}

