/* Gadget utilities for Reminder */

/* $Id: Gadutil.c,v 1.7 1993/04/08 20:15:17 Matti_Rintala Exp $ */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>

#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>

#include <dos/dos.h>

#include <libraries/gadtools.h>

#ifdef __SASC
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/dos.h>
#endif

#ifdef _DCC
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/dos_protos.h>

/* DICE does not have difftime(), although its prototype is in time.h. This is
   a bug in DICE, so we'll have to declare difftime() as macro */
#define difftime(a,b) ((double)(a) - (double)(b))
#endif


#include "Gadfunc.h"
#include "Globals.h"
#include "CalcDate.h"
#include "Gadutil.h"

static int matchstr(const char *matched, const char *str);

/* CheckInt checks that the contents of an integer gadget is valid and undos
   the contents if it is not. If data is valid, it is stored into a given
   integer variable. */

int CheckInt(struct Gadget *gad, int minval, int maxval, short *var) {

  struct StringInfo *strinf;	/* pointer to gadgets StringInfo */

  strinf = (struct StringInfo *)gad->SpecialInfo;

  /* Check if the value is out of range */
  if (*strinf->Buffer == '\0') {
    /* Null entry is valid, marked with 0 */
    *var = 0;
    return 0;
  }

  if (strinf->LongInt < minval || strinf->LongInt > maxval) {
    /* Out of range, so put old value back */
    /* SetInt(gad, *var); */
    DisplayBeep(NULL);
    return 1;			/* No valid data found */
  }
  else {
    /* Set the new value to variable */
    *var = strinf->LongInt;
    return 0;			/* Valid data found */
  }
}

/* CheckMonth checks that the month value entered by user is correct.
   It sets the string gadget to new month value selected from the list. */
int CheckMonth(void) {

  struct Gadget *gad = MainGadgets[GDX_Month];
  struct StringInfo *strinf = (struct StringInfo *)gad->SpecialInfo;
  char *tail;
  int mnth;
  struct Node *node; /* Month names */

  /* If string is empty, it is valid */
  if (*(strinf->Buffer) == '\0') {
    mnth = 0;
  }
  else {
    /* Check if the value entered is a number */
    mnth = strtol(strinf->Buffer, &tail, 10);
    if (mnth < 1 || mnth > 12 || *tail != '\0') {
      /* If it is not a valid number, check if it is a month name */
      for (mnth = 1, node = (struct Node *)MonthList0List.mlh_Head;
	   node != (struct Node *)MonthList0List.mlh_Tail;
	   mnth++, node = node->ln_Succ) {

	/* If name checks, exit loop */
	if (matchstr(strinf->Buffer, node->ln_Name))
	  break;
      }
      /* If no match found, set previous value and fail */
      if (node == (struct Node *)MonthList0List.mlh_Tail) {
	/* SetMonth(month); */
	DisplayBeep(NULL);
	return 1;
      }

      /* Check for ANY */
      if (mnth == 13) mnth = 0;

    }
  }
  /* Update string gadget contents */
  SetMonth(mnth);

  /* Update global month-variable */
  month = mnth;

  return 0;
}

/* CheckText checks the text (not currently) and stores it into global variable */
int CheckText(void) {

  struct StringInfo *strinf = (struct StringInfo *)MainGadgets[GDX_Text]->SpecialInfo;

  /* Simply copy the text */
  strncpy(text, strinf->Buffer, TEXTLEN);

  return 0;
}
 
/* CheckPort checks the port (not currently) and stores it into global variable */
int CheckPort(void) {

  struct StringInfo *strinf =
    (struct StringInfo *)MainGadgets[GDX_ARexxPort]->SpecialInfo;

  /* Simply copy the text */
  strncpy(arexxport, strinf->Buffer, AREXXPORTLEN);

  return 0;
}
 
/* CheckCom checks the com (not currently) and stores it into global variable */
int CheckCom(void) {

  struct StringInfo *strinf =
    (struct StringInfo *)MainGadgets[GDX_ARexxCom]->SpecialInfo;

  /* Simply copy the text */
  strncpy(arexxcom, strinf->Buffer, AREXXCOMLEN);

  return 0;
}
 
/* SetInt sets an integer gadget to new value */
void SetInt(struct Gadget *gad, short newval) {

  struct StringInfo *strinf;

  /* Get the gadgets StringInfo */
  strinf = (struct StringInfo *)gad->SpecialInfo;

  RemoveGList(MainWnd, gad, 1);	/* Remove the gadget from window */
  if (newval == 0) {
    /* Value 0 is represented with empty gadget */
    *strinf->Buffer = '\0';
  }
  else {
    sprintf(strinf->Buffer, "%d", newval); /* Put the new value to gadget */
    strinf->LongInt = newval;
    strinf->BufferPos = 0;
    strinf->DispPos = 0;
  }
  AddGList(MainWnd, gad, ~0, 1, NULL); /* Put gadget back to window */
  RefreshGList(gad, MainWnd, NULL, 1); /* Refresh the gadget */
}

/* SetYear sets the Year gadget to new value */
void SetYear(short newval) {

  SetInt(MainGadgets[GDX_Year], newval);
}

/* SetDay sets the Day gadget to new value */
void SetDay(short newval) {

  SetInt(MainGadgets[GDX_Day], newval);
}

/* SetBefore sets the Before gadget to new value */
void SetBefore(short newval) {

  SetInt(MainGadgets[GDX_Before], newval);
}

/* SetAfter sets the After gadget to new value */
void SetAfter(short newval) {

  SetInt(MainGadgets[GDX_After], newval);
}

/* SetWDay sets the Weekday gadget to given value */
void SetWDay(short newval) {

  struct Gadget *gad = MainGadgets[GDX_Weekday];

  newval = (newval != 0) ? (newval-1) : 7;

  /* Update the selection of the Weekday gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTLV_Selected, (Tag)newval, TAG_DONE);
}

/* SetMonth sets the Month gadget to given value */
void SetMonth(short newval) {

  struct Gadget *gad = MainGadgets[GDX_MonthList];

  /* Calculate correct index for gadget */
  newval = (newval != 0) ? (newval-1) : 12;
  /* Update the selection of the Month gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTLV_Selected, (Tag)newval, TAG_DONE);
}

/* SetAutodelete sets the Autodelete checkbox to given value */
void SetAutodelete(BOOL newval) {

  struct Gadget *gad = MainGadgets[GDX_Autodelete];

  /* Update the checkbox state */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTCB_Checked, (Tag)newval, TAG_DONE);
}

/* SetText sets a new value for text gadget */
void SetText(const char *newtext) {

  struct Gadget *gad = MainGadgets[GDX_Text];

  /* Update the gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTST_String, (Tag)newtext, TAG_DONE);
}

/* SetPort sets a new value for ARexxPort gadget */
void SetPort(const char *newtext) {

  struct Gadget *gad = MainGadgets[GDX_ARexxPort];

  /* Update the gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTST_String, (Tag)newtext, TAG_DONE);
}

/* SetCom sets a new value for ARexxCom gadget */
void SetCom(const char *newtext) {

  struct Gadget *gad = MainGadgets[GDX_ARexxCom];

  /* Update the gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTST_String, (Tag)newtext, TAG_DONE);
}

/* SetAMode sets a new value for ARexxMode gadget */
void SetAMode(char newmode) {

  struct Gadget *gad = MainGadgets[GDX_ARexxMode];

  /* Update the gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTMX_Active, (Tag)newmode, TAG_DONE);

  /* (De)select other ARexx gadgets depending on mode */
  GT_SetGadgetAttrs(MainGadgets[GDX_ARexxCom], MainWnd, NULL,
		    GA_Disabled, (Tag)(newmode == AREXXNMODE), TAG_DONE);
  GT_SetGadgetAttrs(MainGadgets[GDX_ARexxPort], MainWnd, NULL,
		    GA_Disabled, (Tag)(newmode != AREXXCMODE), TAG_DONE);
}

/* SetEvent sets all event gadgets */
void SetEvent(void) {

  /* Set all gadgets to new values */
  SetWDay(wday); SetDay(day); SetMonth(month); SetYear(year);
  ShowWDay();
  SetBefore(before); SetAfter(after);
  SetAutodelete(autodelete);
  SetText(text);
  SetPort(arexxport); SetCom(arexxcom); SetAMode(mode);
}

/* ShowWDay checks the event being edited and if it is not a repeating one
   and Weekday is ANY, shows the weekday of the event in the ShowWDay gadget */
void ShowWDay(void) {

  struct Gadget *gad = MainGadgets[GDX_ShowWDay];

  /* Check if ShowWDay gadget shouldn't display a weekday */
  if (day == 0 || month == 0 || year == 0 || wday != 0) {
    /* If ShowWDay gadget shows a weekday, remove it */
    if (swdaytxt != NULL) {
      swdaytxt = NULL;
      GT_SetGadgetAttrs(gad, MainWnd, NULL, GTTX_Text, (Tag)NULL, TAG_DONE);
    }
  }
  else {
    /* Otherwise calculate the new weekday */
    swdaytxt = wdayabbrv+4*weekday(day, month, year);
    /* Show value in gadget */
    GT_SetGadgetAttrs(gad, MainWnd, NULL, GTTX_Text, (Tag)swdaytxt, TAG_DONE);
  }
}

/* PressButton simulates visually the pressing of a boolean button */
void PressButton(struct Gadget *gad) {

  /* Display the gadget as selected */
  RemoveGList(MainWnd, gad, 1);	/* Remove the gadget from window */
  gad->Flags |= GFLG_SELECTED;
  AddGList(MainWnd, gad, ~0, 1, NULL); /* Put gadget back to window */
  RefreshGList(gad, MainWnd, NULL, 1); /* Refresh the gadget */
  /* Wait for 1/4 seconds */
  Delay(TICKS_PER_SECOND/4);
  /* Display the gadget as not selected */
  RemoveGList(MainWnd, gad, 1);	/* Remove the gadget from window */
  gad->Flags &= ~GFLG_SELECTED;
  AddGList(MainWnd, gad, ~0, 1, NULL); /* Put gadget back to window */
  RefreshGList(gad, MainWnd, NULL, 1); /* Refresh the gadget */
}

/* ResetEvent deselects the eventlist event */
void ResetEvent(void) {

  struct Gadget *gad = MainGadgets[GDX_Eventlist];

  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTLV_Selected, (Tag)~0, TAG_DONE);
}

/* SetEventlist sets the Eventlist gadget to given value */
void SetEventlist(int newval) {

  struct Gadget *gad = MainGadgets[GDX_Eventlist];

  /* Update the selection and top line of the Eventlist gadget */
  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTLV_Selected, (Tag)newval,
		    GTLV_Top, (Tag)newval, TAG_DONE);
}

/* DetachEventlist detached the event list from the Eventlist gadget */
void DetachEventlist(void) {

  struct Gadget *gad = MainGadgets[GDX_Eventlist];

  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTLV_Labels, (Tag)~0, TAG_DONE);
}

/* AttachEventlist attaches the given list to Eventlist gadget */
void AttachEventlist(struct List *list) {

  struct Gadget *gad = MainGadgets[GDX_Eventlist];

  GT_SetGadgetAttrs(gad, MainWnd, NULL, GTLV_Labels, (Tag)list,
		    GTLV_Selected, (Tag)~0, TAG_DONE);
}

/* matchstr checks if the first string is a prefix of the second */
static int matchstr(const char *matched, const char *str) {

  for (; *matched != '\0'; matched++, str++) {
    /* If the other string ends, no match */
    if (*str == '\0')
      return 0;
    
    /* If the strings have different characters, no match */
    if (toupper(*matched) != toupper(*str))
      return 0;
  }

  /* If we are here, the strings matched */
  return 1;
}
