#include "raw_proto.h"

/* decimal_date *********************************************
* INPUT:    dt          pointer to DateTime struct          *
* OUTPUT:   long int    decimal coded date in YYMMDD format *
* PURPOSE:                                                  *
* to convert DateTime date information into a long int      *
* for compact storage in data file header                   *
************************************************************/
long int decimal_date(DateTime *dt)
{
    return(dt->mday + 100 * dt->mon + 10000 * dt->yr);
}

/* decimal_time *************************************************
* INPUT:    dt           pointer to DateTime struct             *
* OUTPUT:   long int     decimal coded time in HHMMSSs format   *
* PURPOSE:                                                      *
* to convert DateTime date information into a long int          *
* for compact storage in data file header                       *
****************************************************************/
long int decimal_time(DateTime *dt)
{
    return(dt->tsec + 10 * dt->sec + 1000 * dt->min + 100000 * dt->hr);
}

/* decode_ao_time *******************************************
* INPUT:      phdr        pointer to long int header array  *
* RETURNS:    DateTime    time struct for current header    *
* PURPOSE:                                                  *
* provide year,day in year,hour,minute, second,             *
* tenth of second, leap year from the computer (H1000)      *
* date: DDMMYY time: HHMMSST                                *
************************************************************/
DateTime decode_ao_time(long int *phdr)
{
    DateTime htime;
    long int tmp;

    /* year, determine if leap year */
    tmp = phdr[3];
    htime.yr = 1900 + (tmp % 100);
    htime.leap = is_leap(&htime);

    tmp /= 100;
    /* month */
    htime.mon = (tmp % 100);
    
    /* day in month & day in year */
    htime.mday = tmp/100;
    if(htime.mday && htime.mon) get_day_in_year(&htime);
    
    tmp = phdr[4];

    /* tenths of seconds */
    htime.tsec = tmp%10;

    tmp /= 10;

    /* seconds */
    htime.sec = tmp%100;

    tmp /= 100;

    /* minutes */
    htime.min = tmp%100;

    /* hours */
    htime.hr = tmp/100;

#ifdef DEBUG_DT
    printf_time(&htime,"date_time: decode_harris_time: DEBUGGING");
#endif /* DEBUG_DT */

    return(htime);
}

/* decode_ao_stop_time **************************************
* INPUT:      phdr        pointer to long int header array  *
* RETURNS:    DateTime    time struct for current header    *
* PURPOSE:                                                  *
* provide year,day in year,hour,minute, second,             *
* tenth of second, leap year from the computer (H1000)      *
* date: DDMMYY time: HHMMSST                                *
************************************************************/
DateTime decode_ao_stop_time(long int *phdr)
{
    DateTime htime;
    long int tmp;

    /* year, determine if leap year */
    tmp = phdr[12];
    htime.yr = 1900 + (tmp % 100);
    htime.leap = is_leap(&htime);

    tmp /= 100;
    /* month */
    htime.mon = (tmp % 100);
    
    /* day in month & day in year */
    htime.mday = tmp/100;
    if(htime.mday && htime.mon) get_day_in_year(&htime);
    
    tmp = phdr[4];

    /* tenths of seconds */
    htime.tsec = tmp%10;

    tmp /= 10;

    /* seconds */
    htime.sec = tmp%100;

    tmp /= 100;

    /* minutes */
    htime.min = tmp%100;

    /* hours */
    htime.hr = tmp/100;

#ifdef DEBUG_DT
    printf_time(&htime,"date_time: decode_harris_time: DEBUGGING");
#endif /* DEBUG_DT */

    return(htime);
}

/* decode_harris_time ***************************************
* INPUT:      phdr        pointer to long int header array  *
* RETURNS:    DateTime    time struct for current header    *
* PURPOSE:                                                  *
* provide year,day in year,hour,minute, second,             *
* tenth of second, leap year from the computer (H100)       *
************************************************************/
DateTime decode_harris_time(long int *phdr)
{
    DateTime htime;
    long int tmp;

    /* year, determine if leap year */
    htime.yr = (phdr[3] >> 12) & 0xfff;
    htime.leap = is_leap(&htime);

    /* day in year */
    htime.yday = (phdr[3] & 0xfff);

    tmp = (phdr[4] & 0xffffff);

    /* tenths of seconds */
    htime.tsec = tmp%10;

    tmp /= 10;

    /* seconds */
    htime.sec = tmp%60;

    tmp /= 60;

    /* minutes */
    htime.min = tmp%60;

    /* hours */
    htime.hr = tmp/60;

#ifdef DEBUG_DT
    printf_time(&htime,"date_time: decode_harris_time: DEBUGGING");
#endif /* DEBUG_DT */

    return(htime);
}

/* decode_irig_time *****************************************
* INPUT:    pd            pointer to long int header array  *
* RETURNS:  DateTime      time struct for current header    *
* PURPOSE:                                                  *
* provide day in year, hr, min, sec info. from IRIG clock   *
 ***********************************************************/
DateTime decode_irig_time(long int *pd)
{
    DateTime irig;
    
    /* set these to 0 since undefined */
    irig.yr = 0;
    irig.tsec = 0;
    
    /* day in year */
    irig.yday = ((pd[14] & 0x0001e000) >> 13) +
                ((pd[14] & 0x001e0000) >> 17) * 10 +
                ((pd[14] & 0x00600000) >> 21) * 100;

    /* hours */
    irig.hr = ((pd[14] & 0x0780) >> 7) + ((pd[14] & 0x1800) >> 11) * 10;

    /* minutes */
    irig.min = (pd[14] & 0x0f) + ((pd[14] & 0x70) >> 4) * 10;

    /* seconds */
    irig.sec = ((pd[15] & 0x700000) >> 20) * 10 + ((pd[15] & 0x0f0000) >> 16);

#ifdef DEBUG_DT
    printf_time(&irig,"date_time: decode_irig_time: DEBUGGING");
#endif /* DEBUG_DT */

    return(irig);
}

/* get_day_in_month *****************************************
* INPUT:    t    A pointer to a time struct                 *
* PURPOSE:                                                  *
* Corrects the month and day in month from the day in year. *
************************************************************/
void get_day_in_month(DateTime *t)
{
    int leaped, tmpDay;
    
    if(t->yday < 1)
        printf("Get_day_in_month: Day is less than 1, %ld\n",t->yday);
    
    /* take leap day away from count if past Feb 1,
     * this helps to avoid extra adds in the following if statements
     */
    leaped = 0;
    tmpDay = t->yday;
    
    if(t->leap == 1 && t->yday > 32)
    {
        tmpDay -= 1;
        leaped = 1;
    }
    
    if(tmpDay < 32)
    {
        t->mon = 1;
        t->mday = tmpDay;        
    }
    else if ((tmpDay > 31) && (tmpDay < 60))
    {
        t->mon = 2;
        t->mday = tmpDay - 31;
        /* Now add day to february if taken away */
        t->mday += leaped;
    }
    else if ((tmpDay > 59) && (tmpDay < 91))
    {
        t->mon = 3;
        t->mday = tmpDay - 59;
    }
    else if ((tmpDay > 90) && (tmpDay < 121))
    {
        t->mon = 4;
        t->mday = tmpDay - 90;
    }
    else if ((tmpDay > 120) && (tmpDay < 152))
    {
        t->mon = 5;
        t->mday = tmpDay - 120;
    }
    else if ((tmpDay > 151) && (tmpDay < 182))
    {
        t->mon = 6;
        t->mday = tmpDay - 151;
    }
    else if ((tmpDay > 181) && (tmpDay < 213))
    {
        t->mon = 7;
        t->mday = tmpDay - 181;
    }
    else if ((tmpDay > 212) && (tmpDay < 244))
    {
        t->mon = 8;
        t->mday = tmpDay - 212;
    }
    else if ((tmpDay > 243) && (tmpDay < 274))
    {
        t->mon = 9;
        t->mday = tmpDay - 243;
    }
    else if ((tmpDay > 273) && (tmpDay < 305))
    {
        t->mon = 10;
        t->mday = tmpDay - 273;
    }
    else if ((tmpDay > 304) && (tmpDay < 335))
    {
        t->mon = 11;
        t->mday = tmpDay - 304;
    }
    else
    {
        t->mon = 12;
        t->mday = tmpDay - 334;
    }
}

/* get_day_in_year ******************************************
* INPUT:    t    a pointer to a time struct                 *
* PURPOSE:                                                  *
* Corrects the day in year from the month and day in month. *
************************************************************/
void get_day_in_year(DateTime *t)
{
    if(t->mday > 31)
        printf("Get_day_in_year: Day exceeds expected limit: %ld > 31\n",t->mday);
    
    switch(t->mon)
    {
        case 1:
            t->yday = t->mday;
            break;
        case 2:
            t->yday = t->mday + 31;
            break;
        case 3:
            t->yday = t->mday + 59 + t->leap;
            break;
        case 4:
            t->yday = t->mday + 90 + t->leap;
            break;
        case 5:
            t->yday = t->mday + 120 + t->leap;
            break;
        case 6:
            t->yday = t->mday + 151 + t->leap;
            break;
        case 7:
            t->yday = t->mday + 181 + t->leap;
            break;
        case 8:
            t->yday = t->mday + 212 + t->leap;
            break;
        case 9:
            t->yday = t->mday + 243 + t->leap;
            break;
        case 10:
            t->yday = t->mday + 273 + t->leap;
            break;
        case 11:
            t->yday = t->mday + 304 + t->leap;
            break;
        case 12:
            t->yday = t->mday + 334 + t->leap;
            break;
        default:
            printf_exit("date_time: get_day_in_year: Error in month %ld\n",t->mon);
            break;
    }
}

/* get_input_time *******************************************
* INPUT:    str            input time string                *
* RETURNS:  DateTime       date record                      *
* PURPOSE:                                                  *
* converts input time in mmddhhmmss format into a DateTime. *
************************************************************/
DateTime get_input_time(char *str)
{
    DateTime dt;
    
    if(sscanf(str,"%ld/%ld/%ld,%ld:%ld:%ld",
                    &dt.yr,&dt.mon,&dt.mday,
                    &dt.hr,&dt.min,&dt.sec) != 6)
        printf_exit("date_time: get_input_time: Error decoding input time.\n",0L);
    
    if(dt.yr < 60) dt.yr += 2000;
    else if (dt.yr < 100) dt.yr += 1900;
    
    dt.tsec = 0;
    
    dt.leap = is_leap(&dt);
    get_day_in_year(&dt);

    return(dt);
}

/* is_leap **************************************************
* INPUT:    dt        a pointer to a time struct            *
* RETURNS:  int       1 for leap year, 0 otherwise.         *
* PURPOSE:                                                  *
* Returns 1 if leap year, 0 if not. Make sure that the year *
* is correct before using this routine: correct IRIG yr.    *
************************************************************/
int is_leap(DateTime *dt)
{
    long int tmp;
    
    tmp = dt->yr;
    
    if(!(tmp%4))
    {
        if(!(tmp%100))
        {
            if(!(tmp%400)) return(1);
        }
        else
        {
            return(1);
        }
    }
    
    return(0);
}

/* printf_time **************************************
* INPUT:    t        A pointer to a time struct     *
*           label    A string label to print out    *
* PURPOSE:                                          *
* print out time struct info with preceeding label. *
****************************************************/
void printf_time(DateTime *t, char *label)
{
    printf("%s:\n",label);
    printf("Date: %ld/%ld/%ld - %ld/%ld\n",t->yr,t->mon,t->mday,t->yr,t->yday);
    printf("Time: %2ld:%02ld:%02ld.%1ld\n",t->hr,t->min,t->sec,t->tsec);
}

/* seconds **************************************************
* INPUT:    t           a pointer to a time struct          *
* RETURNS:  long int    seconds in year.                    *
* PURPOSE:                                                  *
* converts day in year info into seconds in year, make sure *
* day of year (yday) is correct when using this routine     *
************************************************************/
long int seconds(DateTime *t)
{
    return((t->yday - 1) * 86400 + t->hr * 3600 + t->min * 60 + t->sec);
}
