/************************************************/
/* Constants and functions for the WATCH module */
/************************************************/

#ifndef WATCH_LOADED
#include "watch.h"
#endif

#include <time.h>

/*****  Time handling constants *****
      The time handling routines use constants that are set to their 
      usual values except in SIMUL mode where they are set to artificially 
      low values (setting the 10 minutes position becomes impossible).
*/

#ifdef SIMUL

#define SECONDS_PER_MINUTE 2
#define MINUTES_PER_10MN 2
#define MINUTES_PER_HOUR 2
#define HOURS_PER_DAY 2
#define PM_VALUE 1
#define DAYS_PER_WEEK 2
#define MONTHS_PER_YEAR 2

static short monthlength [] = {2, 2};

#else

#define SECONDS_PER_MINUTE 60
#define MINUTES_PER_10MN 10
#define MINUTES_PER_HOUR 60
#define HOURS_PER_DAY 24
#define PM_VALUE 12
#define DAYS_PER_WEEK 7
#define MONTHS_PER_YEAR 12

static short monthlength [] = {31,28,31,30,31,30,31,31,30,31,30,31};

#endif

/***** The printing functions for simulation *****/

#if  defined SIMUL || defined SIMULRT

static char *day_names [7] = {"SU","MO","TU","WE","TH","FR","SA"};

char* _WATCH_TIME_TYPE_to_text (wt)
WATCH_TIME_TYPE wt; {
   static char res[22];
   sprintf (res, "%s %d-%d %d:%d:%d%s",
                 day_names[wt.day_in_week],
                 wt.month+1,
                 wt.day,
                 (wt.mode12h ? ((wt.hours % PM_VALUE ==0) ?
                                    PM_VALUE :
                                    wt.hours % PM_VALUE)
                             : wt.hours),
                 wt.minutes,
                 wt.seconds,
                (wt.mode12h
                         ? ((wt.hours>=PM_VALUE) ? " PM" : " AM") 
                         : " 24H"));
   return res;
}

static char *position_name [7] = {"seconds", "hours", "10 minutes",
                                  "minutes", "month", "day", "day name"};

char* _WATCH_TIME_POSITION_to_text (wtp)
WATCH_TIME_POSITION wtp; {
   static char res[12];
   sprintf (res, "%s", position_name[wtp]);
   return res;
}

#endif

/***** The INITIAL_WATCH_TIME constant *****

The INITIAL_WATCH_TIME constant is declared here and
initialized in the main program, using the function GET_INITIAL_WATCH_TIME,
unless in SIMUL mode where it is initialized here.
*/

#ifdef SIMUL 

static WATCH_TIME_TYPE INITIAL_SIMUL_WATCH_TIME = 
      {0, 0, 1, PM_VALUE, 0, 0, 0};

#else

WATCH_TIME_TYPE INITIAL_WATCH_TIME;

#endif

WATCH_TIME_TYPE GET_INITIAL_WATCH_TIME () {
   WATCH_TIME_TYPE wt;
#ifdef SIMUL
   return INITIAL_SIMUL_WATCH_TIME;
#else
   struct tm *ptm;
   long tloc;
   time(&tloc);
   ptm=localtime(&tloc);
   wt.day_in_week = ptm->tm_wday;
   wt.month = ptm->tm_mon;
   wt.day = ptm->tm_mday;
   wt.hours = ptm->tm_hour;
   wt.minutes = ptm->tm_min;
   wt.seconds = ptm->tm_sec;
   wt.mode12h = 0;
   return(wt);
#endif
}

/***** The INCREMENT_WATCH_TIME function} *****/

WATCH_TIME_TYPE INCREMENT_WATCH_TIME (wt)
WATCH_TIME_TYPE wt; {
   wt.seconds ++;
   if (wt.seconds == SECONDS_PER_MINUTE) {
      wt.seconds = 0;
      wt.minutes ++;
      if (wt.minutes == MINUTES_PER_HOUR) {
         wt.minutes = 0;
         wt.hours ++;
         if (wt.hours == HOURS_PER_DAY) {
            wt.hours = 0;
            wt.day ++;
            wt.day_in_week = (wt.day_in_week+1) % DAYS_PER_WEEK;
            if (wt.day > monthlength[wt.month]) {
               wt.day = 1;
               wt.month = (wt.month+1) % MONTHS_PER_YEAR;
            }
         }
      }
   }
   return wt;
}

/***** The TOGGLE_24H_MODE_IN_WATCH_TIME\ function *****/

WATCH_TIME_TYPE TOGGLE_24H_MODE_IN_WATCH_TIME (wt)
WATCH_TIME_TYPE wt; {
   wt.mode12h = ! wt.mode12h;
   return wt;
}

/***** The NEXT_WATCH_TIME_POSITION function *****/

WATCH_TIME_POSITION NEXT_WATCH_TIME_POSITION (wtp)
WATCH_TIME_POSITION wtp; {
   return((wtp+1)%7);
}

/***** The SET_WATCH_TIME function *****/

WATCH_TIME_TYPE SET_WATCH_TIME (wt,wtp)
WATCH_TIME_TYPE wt; 
WATCH_TIME_POSITION wtp; {
   switch (wtp) {
      case 0 : /* seconds */
         wt.seconds=0;
         break;
      case 1 : /* hours */
         wt.hours = (wt.hours+1) % HOURS_PER_DAY;
         break;
      case 2 : /* 10 minutes */
         wt.minutes = (wt.minutes >= MINUTES_PER_HOUR-MINUTES_PER_10MN
                           ? wt.minutes-(MINUTES_PER_HOUR-MINUTES_PER_10MN)
                           : wt.minutes+MINUTES_PER_10MN);
         break;
      case 3 : /* minutes */
         wt.minutes = (wt.minutes % MINUTES_PER_10MN == MINUTES_PER_10MN-1
                               ? wt.minutes-(MINUTES_PER_10MN-1)
                               : wt.minutes+1);
         break;
      case 4 : /* month */
         wt.month = (wt.month+1) % MONTHS_PER_YEAR;
         break;
      case 5 : /* day */
         wt.day = (wt.day == monthlength[wt.month]
                               ? 1
                               : wt.day+1 );
         break;
      case 6 : /* day in week */
         wt.day_in_week = (wt.day_in_week+1) % DAYS_PER_WEEK;
         break;
   }
   return wt;
}

/***** The INCREMENT_WATCH_TIME_IN_SET_MODE function *****
      The incrementation is done only up to the watch time position 
      being currently set.
*/

WATCH_TIME_TYPE INCREMENT_WATCH_TIME_IN_SET_MODE (wt,wtp)
WATCH_TIME_TYPE wt;
WATCH_TIME_POSITION wtp; {
   wt.seconds ++;
   if (wt.seconds == SECONDS_PER_MINUTE) {
      wt.seconds = 0;
      if (wtp == 3) return wt; /* in set minutes mode */
      if (wtp == 2) {  /* set 10 minutes mode */
#ifdef SIMUL
         return wt;
#else
         if (wt.minutes % 10 == 9) wt.minutes -= 9;
         else 
         wt.minutes ++;
         return wt;
#endif
      }
      wt.minutes ++;
      if (wt.minutes == MINUTES_PER_HOUR) {
         wt.minutes = 0;
         if (wtp == 1) return wt; /* set hours mode */
         wt.hours ++;
         if (wt.hours == HOURS_PER_DAY) {
            wt.hours = 0;
            if (wtp == 4 || wtp == 6) return wt; /* set day mode */
            wt.day ++;
            wt.day_in_week = (wt.day_in_week+1) % DAYS_PER_WEEK;
            if (wt.day > monthlength[wt.month]) {
               wt.day = 1;
               if (wtp == 5) return wt;   /* set month mode */
               wt.month = (wt.month+1) % MONTHS_PER_YEAR;
            }
         }
      }
   }
   return wt;
}

/***** The WATCH_BEEP function *****/

WATCH_BEEP (wt, b)
WATCH_TIME_TYPE wt; {
   return ((b && (wt.seconds == 0) && (wt.minutes==0)) ?
         WATCH_BEEP_VALUE : NO_BEEP_VALUE);
}

