#include "timer.h"

#include <stdio.h>
#include <iostream.h>

#include <math.h>           // modf
#include "sys/time.h"       // struct timeval
#include "slalib/slalib.h"  // slacldj

void Timer::SetTimer(int tv_sec, double tv_usec)
{
    fSecs = tv_sec;
    fMs = tv_usec;

    SetMjd((fMs+fSecs)/(60*60*24) + 40587);

    fSec  = tv_sec%60;
    tv_sec /= 60;

    fMin = tv_sec%60;
    tv_sec /= 60;

    fHor = tv_sec%24;
    tv_sec /= 24;

//    fDiv = fmod((fMs+fSecs)/(60*60*24), 1.0);
}

void Timer::GetTimeval(struct timeval *tv) const
{
    tv->tv_sec  = fSecs;
    tv->tv_usec = (__suseconds_t)fMs;
}

/*
void Timer::Set(const long mjd)
{
    SetMjd(mjd);

    //
    // Express day in Gregorian calendar
    //  (taken from slalib slaDjcl)
    //
    const long jd   = mjd + 2400001;
    const long n4   = (((((jd*4-17918)/146097)*6)/4+1)/2+jd-37)*4;
    const long nd10 = (((n4-237)%1461)/4)*10+5;

    fYea = n4/1461 - 4712;
    fMon = ((nd10/306+2)%12) + 1;
    fDay = (nd10%306)/10 + 1;
}
*/
void Timer::SetTimer(const struct timeval *tv)
{
    SetTimer(tv->tv_sec, (double)tv->tv_usec/1000000.0);
}

Timer::Timer(double t)
{
    double inte;
    double frac = modf(t, &inte);
    SetTimer(inte, frac);
}

Timer::Timer(struct timeval *tv)
{
    SetTimer(tv);
}

Timer::Timer(const Timer &t)
{
    fMs   = t.fMs;
    fDiv  = t.fDiv;
    fSec  = t.fSec;
    fSecs = t.fSecs;
    fMin  = t.fMin;
    fHor  = t.fHor;
    fDay  = t.fDay;
    fMon  = t.fMon;
    fYea  = t.fYea;
    fMjd  = t.fMjd;
}

void Timer::SetMjd(double mjd)
{
    //
    // Express day in Gregorian calendar
    //  (taken from slalib slaDjcl)
    //
    fMjd = mjd;

    const long jd   = (long)mjd + 2400001;
    const long n4   = (((((jd*4-17918)/146097)*6)/4+1)/2+jd-37)*4;
    const long nd10 = (((n4-237)%1461)/4)*10+5;

    fYea = n4/1461 - 4712;
    fMon = ((nd10/306+2)%12) + 1;
    fDay = (nd10%306)/10 + 1;

    fDiv = fmod(mjd, 1.0);

    mjd -= 40587;

    mjd *= 24;
    fHor = (int)fmod(mjd, 24);

    mjd *= 60;
    fMin = (int)fmod(mjd, 60);

    mjd *= 60;
    fSec = (int)fmod(mjd, 60);

    fMs = fmod(mjd * 1000, 1000)/1000;
}

double Timer::Now() //[s]
{
    struct timeval tv;
    gettimeofday(&tv, NULL);

    SetTimer(&tv);

    return fMs+fSecs;
}

Timer::operator double() const //[s]
{
    return fMs+fSecs;
}

void Timer::Print()
{
    cout << fSec << "s +" << fMs << "s" << endl;
}

const char *Timer::GetTimeStr()
{
    sprintf(fDateStr, "%d/%02d/%02d %d:%02d:%02d.%06li",
            fYea, fMon, fDay, fHor, fMin, fSec, (long)(1000000.0*fMs));

    return fDateStr;
}

ostream &operator<<(ostream &out, Timer &t)
{
    char text[256];

    sprintf(text, "%d/%02d/%02d %d:%02d:%02d.%01li",
            t.fYea, t.fMon, t.fDay, t.fHor, t.fMin, t.fSec, (long)(10.0*t.fMs));

    out << text;
    return out;
}
