/* Event handling routines for Reminder */

/* $Id: Events.c,v 1.5 93/03/06 16:30:07 Matti_Rintala Exp $ */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

#include <exec/types.h>
#include <exec/lists.h>

#include <exec/exec.h>
#include <libraries/reqtools.h>

#ifdef __SASC
#include <proto/exec.h>
#include <proto/reqtools.h>
#endif

#ifdef _DCC
#include <clib/exec_protos.h>
#include <clib/reqtools_protos.h>
#endif

#include "Globals.h"
#include "Events.h"

static char *monthabbrv =
  "***\0Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0";

static char *wdayabbrv = "***\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0Sun\0";

static int checkdate(void);
static void makeentry(char *entry);



/* Eventlist holds the event database, initially empty */
static struct List Eventlist = {
  (struct Node *)&Eventlist.lh_Tail,
  NULL,
  (struct Node *)&Eventlist.lh_Head
  };

static void DeleteEventlist(void);

/* InitEvents initialized the events database */
struct List *InitEvents(void) {

  /* Only ensure that Eventlist is deleted on exit */
  atexit(DeleteEventlist);

  /* Return pointer to Eventlist */
  return &Eventlist;
}

static void DeleteEventlist(void) {

  struct EventNode *node;

  while ((node = (struct EventNode *)RemTail(&Eventlist)) != NULL)
    free(node);

  eventno = 0;			/* There are no events now */

}

/* AddEvent adds a new event to list */
struct List *AddEvent(void) {

  struct EventNode *newevent;

  /* Check that the date is correct */
  if (!checkdate()) {
    /* If not, tell the user that */
    rtEZRequestTags("Cannot add event,\ninvalid date.", "OK", NULL, NULL,
		    RT_LockWindow, (Tag)TRUE, TAG_END);
    /* Return with unchanged list */
    return &Eventlist;
  }

  /* Make a new list node */
  if ((newevent = malloc(sizeof(struct EventNode))) == NULL) {
    rtEZRequestTags("Cannot get memory\nfor new event!", "OK", NULL, NULL,
		    RT_LockWindow, (Tag)TRUE, TAG_END);
    return &Eventlist;
  }

  /* Generate entry text */
  makeentry(newevent->entry);
  newevent->node.ln_Name = newevent->entry;

  /* Set Acknowledgement date to 1-Jan-1990 */
  newevent->aday = 1; newevent->amonth = 1; newevent->ayear = 1990;

  /* Set other fields from globals */
  newevent->day = day; newevent->month = month; newevent->year = year;
  newevent->wday = wday;
  newevent->before = before; newevent->after = after;
  newevent->autodelete = autodelete;
  strcpy(newevent->text, text);

  /* Add new entry to tail of list */
  AddTail(&Eventlist, (struct Node *)newevent);

  changed = 1;		/* Database has changed */
  eventno++;			/* One more event now exists */

  /* Return pointer to list */
  return &Eventlist;
}

/* Getevent gets data from selected event */
void GetEvent(void) {

  struct EventNode *node;
  int i;

  /* First find the appropriate node */
  node = (struct EventNode *)Eventlist.lh_Head;
  for (i = 0 ; i < event; i++)
    node = (struct EventNode *)node->node.ln_Succ;

  /* Then get the appropriate data */
  wday = node->wday; day = node->day; month = node->month; year = node->year;
  before = node->before; after = node->after;
  autodelete = node->autodelete;
  strcpy(text, node->text);

}

/* UpdateEvent updates an existing event */
struct List *UpdateEvent(void) {

  struct EventNode *node;
  int i;

  /* First find the appropriate node */
  node = (struct EventNode *)Eventlist.lh_Head;
  for (i = 0 ; i < event; i++)
    node = (struct EventNode *)node->node.ln_Succ;

  /* Generate entry text */
  makeentry(node->entry);
  node->node.ln_Name = node->entry;

  /* Set Acknowledgement date to 1-Jan-1990 */
  node->aday = 1; node->amonth = 1; node->ayear = 1990;

  /* Set other fields from globals */
  node->day = day; node->month = month; node->year = year;
  node->wday = wday;
  node->before = before; node->after = after;
  node->autodelete = autodelete;
  strcpy(node->text, text);

  changed = 1;		/* Database has changed */

  return &Eventlist;
}

/* RemoveEvent removes an existing event */
struct List *RemoveEvent(void) {

  struct EventNode *node;
  int i;

  /* First find the appropriate node */
  node = (struct EventNode *)Eventlist.lh_Head;
  for (i = 0 ; i < event; i++)
    node = (struct EventNode *)node->node.ln_Succ;

  /* Remove the node */
  Remove((struct Node *)node);

  /* Free the memory */
  free(node);

  changed = 1;			/* Database has changed */
  eventno--;			/* Now there are one less events */

  return &Eventlist;
}

/* LoadEvents loads the event database from file. It returns TRUE if it fails. */
int LoadEvents(const char *filename) {

  FILE *infile;
  struct EventNode *node;

  /* Try to open the file */
  if ((infile = fopen(filename, "rb")) == NULL) 
    return TRUE;

  /* Skip the timestamp */
  fseek(infile, sizeof(time_t), SEEK_SET);

  /* Read events from file */
  while (TRUE) {
    /* Get memory for event */
    if ((node = malloc(sizeof(struct EventNode))) == NULL) {
      rtEZRequestTags("Insufficient memory!", "OK", NULL, NULL,
		      RT_LockWindow, (Tag)TRUE, TAG_END);
      break;
    }

    /* Read event part of it from file */
    while (TRUE) {
      fread(&node->entry, 1, sizeof(struct EventNode)-sizeof(struct Node), infile);
      /* If end-of-file occurred, stop looping */
      if (feof(infile))
	break;
      /* Stop looping also, if event is not deleted */
      if (strcmp(node->entry, DELETEDSTR))
	break;
      else
	changed = 2;		/* Deleted entrys should be swept away */
    }
    /* If end-of-file occurred, stop looping */
    if (feof(infile))
      break;

    /* Set name of event and add it to Eventlist */
    node->node.ln_Name = node->entry;
    AddTail(&Eventlist, (struct Node *)node);
    eventno++;			/* One more event */
  }

  /* Free the extra node left (freeing NULL is allowed) */
  free(node);

  fclose(infile);

  return FALSE;
}

/* SaveEvents saves event database to file. It returns TRUE if it fails. */
int SaveEvents(const char *filename) {

  FILE *outfile;
  struct EventNode *node;
  void *ptr;
  int size;
  BOOL success = TRUE;
  struct tm tm_stamp = {0, 0, 0, 1, 0, 90, 0, 0, 0};
  time_t stamp;
  
  /* First try to open the file */
  if ((outfile = fopen(filename, "wb")) == NULL)
    return 1;

  /* Write timestamp for 1.1.1990 */
  stamp = mktime(&tm_stamp);
  if (fwrite(&stamp, 1, sizeof(time_t), outfile) != sizeof(time_t)) {
    success = FALSE;
  }
  else {
    node = (struct EventNode *)Eventlist.lh_Head;
    for (; node->node.ln_Succ != NULL;
	 node = (struct EventNode *)node->node.ln_Succ) {
      /* Get starting address of Reminder data and calculate size */
      ptr = &node->entry;
      size = sizeof(struct EventNode) - sizeof(struct Node);
      /* Write the node information to file */
      if (fwrite(ptr, 1, size, outfile) != size) {
	/* If failed, abort */
	success = FALSE;
	break;
      }
    }
  }

  /* Close the file and exit */
  fclose(outfile);

  return !success;
}

  

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

/* checkdate checks that the date is valid */
static int checkdate(void) {

  short testyear, testmonth;
  /* Check month */
  if (month > 12)
    return 0;

  /* If day is ANY, date is ok */
  if (day == 0)
    return 1;

  /* Get appropiate values for test variables */
  if (year == 0) testyear = 1996; /* Leap year */
  else testyear = year;

  if (month == 0) testmonth = 1; /* Month with 31 days */
  else testmonth = month;
    
  /* Check day */
  if (day > (monthlist[testmonth-1] + ((testmonth == 2 && testyear%4 == 0) ?
				     ((testyear%400 == 0) ? 0 : 1) :
				     0)))
    return 0;

  return 1;
}

/* makeentry makes an appropriate entry line for Eventlist gadget */
static void makeentry(char *entrystart) {

  char *entry = entrystart;

  /* Start with day of the week */
  strcpy(entry, wdayabbrv+4*wday);
  entry += 3;			/* Skip of the day */
  *entry++ = ' ';

  /* If day is ANY, use **, otherwise the day number */
  if (day == 0) {
    *entry++ = '*';
    *entry++ = '*';
  }
  else {
    sprintf(entry, "%02d", day);
    entry += 2;			/* Skip over the number */
  }

  *entry++ = '-';
  /* Then month name */
  strcpy(entry, monthabbrv+4*month);
  entry += 3;			/* Skip over month */
  *entry++ = '-';

  /* Then year */
  if (year == 0) {
    *entry++ = '*';
    *entry++ = '*';
    *entry++ = '*';
    *entry++ = '*';
  }
  else {
    sprintf(entry, "%4d", year);
    entry += 4;			/* Skip over year */
  }

  *entry++ = ' ';

  /* Then copy rest with text */
  strncpy(entry, text, ENTRYLEN-(entry-entrystart));
}
