/*-
 * $Id: date.c,v 1.2 90/02/03 17:00:25 Rhialto Exp $
 * $Log:       date.c,v $
 * Revision 1.2  90/02/03  17:00:25  Rhialto
 * 0x21 -> DATE_MIN
 * 
 * Revision 1.1  89/12/17  20:03:37  Rhialto
 * Initial revision
 *
 * DATE.C
 *
 * Two date conversion routines: DateStamp <-> MSDOS date/time.
 *
 * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
 * not be used or copied without a licence.
 */

#include <libraries/dos.h>
#include "han.h"

#define BASEYEAR           1978
#define DAYS_PER_YEAR      365
#define HOURS_PER_DAY      24
#define MINUTES_PER_HOUR    60
#define SECONDS_PER_MINUTE  60

#define DAYS_PER_WEEK      7
#define MONTHS_PER_YEAR     12

#define MINUTES_PER_DAY     (MINUTES_PER_HOUR * HOURS_PER_DAY)
#define SECONDS_PER_DAY     ((long) SECONDS_PER_MINUTE * \
                            MINUTES_PER_HOUR * HOURS_PER_DAY)

#define LeapYear(year)  ((year & 3) == 0)   /* From 1-Mar-1901 to 28-Feb-2100 */

int daycount[MONTHS_PER_YEAR] = {
       31,     28,    31,    30,    31,    30,
       31,     31,    30,    31,    30,    31
};

void
ToDateStamp(datestamp, date, time)
struct DateStamp *datestamp;
word date;
word time;
{
    {
       int hours, minutes, seconds;

       seconds = (time & 31) * 2;
       time >>= 5;
       minutes = time & 63;
       time >>= 6;
       hours = time;

       datestamp->ds_Minute = MINUTES_PER_HOUR * hours + minutes;
       datestamp->ds_Tick = TICKS_PER_SECOND * seconds;
    }

    {
       ulong i, j, t;
       int year, month, day;

       if (date < DATE_MIN)
           date = DATE_MIN;

       day = date & 31;
       date >>= 5;
       month = (date & 15) - 1;
       date >>= 4;
       year = date + 1980;

       if ((unsigned)month > 11 ||
           (unsigned)day > (unsigned)daycount[month]) {
           day = 31;
           month = 11;
           year = 1979;
       }

       j = year - BASEYEAR;

       /* Get the next lower full leap period (4 years and a day) since ... */
       t = (year - BASEYEAR) & ~3;
       i = t;
       t = (t / 4) * (4 * DAYS_PER_YEAR + 1);

       /* t now is the number of days in 4 whole years since ... */

       /*dbprintf(("ly0: i=%ld(%ld) j=%ld(%ld) t=%ld\n", i, i+BASEYEAR,j,j+BASEYEAR, t));*/
       while (i < j) {
           /*dbprintf(("ly1: i=%ld(%ld) j=%ld(%ld) t=%ld\n", i, i+BASEYEAR,j,j+BASEYEAR, t));*/
           t += DAYS_PER_YEAR;
           if (LeapYear(i + BASEYEAR)) {
               /*dbprintf(("leap year\n"));*/
               t++;
           }
           i++;
       }

       /* t now is the number of days in whole years since ... */

       /*dbprintf(("m0:  i=%ld j=%ld t=%ld\n", i, j, t));*/
       for (i = 0; i < month; i++) {
           /*dbprintf(("m1: i=%ld j=%ld t=%ld\n", i, j, t));*/
           t += daycount[i];
           if (i == 1 && LeapYear(year)) {
               t++;
           }
       }

       /* t now is the number of days in whole months since ... */

       t += day - 1;

       /* t now is the number of days in whole days since ... */

       datestamp->ds_Days = t;
    }
}

void
ToMSDate(date, time, datestamp)
word *date;
word *time;
register struct DateStamp *datestamp;
{
    {
       word hours, minutes, seconds;

       hours = datestamp->ds_Minute / MINUTES_PER_HOUR;
       minutes = datestamp->ds_Minute % MINUTES_PER_HOUR;
       seconds = datestamp->ds_Tick / TICKS_PER_SECOND;

       *time = (hours << 11) | (minutes << 5) | (seconds / 2);
    }
    {
       register long days, i, t;
       int year, month, day;

       days = datestamp->ds_Days;

       year = BASEYEAR + (days/(4*DAYS_PER_YEAR+1)) * 4;
       days %= 4 * DAYS_PER_YEAR + 1;
       while (days) {
               t = DAYS_PER_YEAR;
               if (LeapYear(year))
                       t++;
               if (days < t)
                       break;
               days -= t;
               year++;
       }
       days++;
       for (i = 0; i < MONTHS_PER_YEAR; i++) {
               t = daycount[i];
               if (i == 1 && LeapYear(year))
                       t++;
               if (days <= t)
                       break;
               days -= t;
       }
       month = i + 1;
       day = days;

       *date = ((year - 1980) << 9) | (month << 5) | day;
    }
}
