/* Date Requester Package
 * Author:		Mark R. Rinfret
 * Description:
 *		This source file contains a canned date requester routine which
 * supports time and date entry in MM/DD/YY HH:MM:SS notation (time is
 * optional) to a DateStamp structure.  This package is dependent upon
 * the package "MRDates.c" (same author) for DateStamp/string conversions.
 *
 * History:		(most recent change first)
 *
 * 08/18/87 -MRR- Added up/down arrows to gadgetry
 * 07/20/87 -MRR- Created this file.
 */


#include <intuition/intuition.h> 
#include <intuition/intuitionbase.h> 
#include <libraries/dosextens.h> 
#include <graphics/gfxbase.h> 
#include <graphics/gfx.h> 
#include <graphics/display.h> 

#include <graphics/text.h> 
#include <functions.h>

#include <ctype.h> 
#include <MRDates.h>

#define DATEREQWIDTH	260
#define DATEREQHEIGHT	80

/**********************************************************************
 *                    Gadget Structure Definitions
 * 
 * Some of the following structures were defined using EGAD! 
 * (by the Programmer's Network) and further modified by the author.
 * 
 **********************************************************************/

/*  Gadget ID Definitions */

#define DATEGAD 		0
#define UPMONTHGAD		1
#define UPDAYGAD		2	
#define UPYEARGAD		3
#define UPHOURGAD		4
#define UPMINGAD		5
#define UPSECGAD		6
#define DOWNMONTHGAD	7
#define DOWNDAYGAD		8
#define DOWNYEARGAD		9
#define DOWNHOURGAD		10
#define DOWNMINGAD		11
#define DOWNSECGAD		12
#define NOWGAD			13
#define OKGAD			14

/**********************************************************************
 *  Text attribute structures used in rendering IntuiTexts
 **********************************************************************/


static char def_font[] ="topaz.font";

static struct TextAttr TxtAt_Plain = { 
	(UBYTE *)def_font, 8, FS_NORMAL, FPF_ROMFONT
	};




/**********************************************************************
 *  String information for the dategad string gadget.
 **********************************************************************/

static UBYTE dategad_sbuf_1[19] = "00/00/00 00:00:00";
static UBYTE dategad_ubuf_1[19];

static struct StringInfo dategad_txstr_1 = {
  dategad_sbuf_1, dategad_ubuf_1, 	/* Buffer, UndoBuffer  */
  0, 18, 0,  						/* BufferPos, MaxChars, DispPos   */
  0, 18,      						/* UndoPos, NumChars */
  0, 0, 0,  						/* DispCount, CLeft, CTop */
  0x0, 0,   						/* LayerPtr, LongInt */
  0x0        						/* AltKeyMap */
};


/**********************************************************************
 *  Gadget Structure definition for the dategad gadget.
 **********************************************************************/

static struct Gadget dategad = {
  NULL,     /* NextGadget pointer */
  64, 50,    /* LeftEdge, TopEdge  */
  8 * 17,						/* Width (8 pixels * 17 characters) */
  8,    						/* Height      */
   GADGHCOMP, 					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | STRGADGET, 		/* GadgetType */
	NULL,						/* GadgetRender - no border */
  NULL,    						/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  (APTR)&dategad_txstr_1,   	/* SpecialInfo */
  DATEGAD,    					/* GadgetID */
  NULL							/* UserData Pointer */
};

static struct IntuiText nowtext = {
	1, 0,						/* FrontPen / BackPen */
	JAM2,						/* DrawMode */
	0,							/* LeftEdge */
	0,							/* TopEdge */
	&TxtAt_Plain,				/* ITextFont */
	(UBYTE *) "NOW",			/* IText */
	NULL						/* NextText */
	};

static struct Gadget nowgad = {
  &dategad,	     				/* NextGadget pointer */
  220, 50,    					/* LeftEdge, TopEdge  */
  24, 8,    					/* Width, Height      */
   GADGHCOMP,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  NULL,							/* GadgetRender */
  NULL,							/* SelectRender */
  &nowtext,						/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  NOWGAD,  						/* GadgetID */
  NULL							/* UserData Pointer */
};

static struct IntuiText oktext = {
	1, 0,						/* FrontPen / BackPen */
	JAM2,						/* DrawMode */
	0,							/* LeftEdge */
	0,							/* TopEdge */
	&TxtAt_Plain,				/* ITextFont */
	(UBYTE *) "OK",						/* IText */
	NULL						/* NextText */
	};
		
static struct Gadget okgad = {
  &nowgad,	     				/* NextGadget pointer */
  30, 50,    					/* LeftEdge, TopEdge  */
  16, 8,    					/* Width, Height      */
   GADGHNONE,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  NULL,							/* GadgetRender */
  NULL,							/* SelectRender */
   &oktext,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  OKGAD,   						/* GadgetID */
  NULL							/* UserData Pointer */
};

/* These coordinate pairs define the border of the up-arrow gadgets. */

static SHORT upborder_pairs[] = {
	7, 0,
	14, 7,
	0, 7,
	7, 0
	};


/* The up-arrow border definition. */

static struct Border upborder = {
	-1, -1,	/* LeftEdge, TopEdge */
	1, 2,   /* FrontPen, BackPen */
	JAM1,	/* DrawMode */
	4, 		/* number of pairs */
	(SHORT *) &upborder_pairs,
	NULL	/* NextBorder */
	};


/* These coordinate pairs define the border of the down-arrow gadgets. */

static SHORT downborder_pairs[] = {
	0, 0,
	14, 0,
	7, 7,
	0, 0
	};

/* The down-arrow border definition. */

static struct Border downborder = {
	-1, -1,	/* LeftEdge, TopEdge */
	1, 2,   /* FrontPen, BackPen */
	JAM1,	/* DrawMode */
	4, 		/* number of pairs */
	(SHORT *) &downborder_pairs,
	NULL	/* NextBorder */
	};


/**********************************************************************
 *  Gadget Structure definition for the upsec gadget.
 **********************************************************************/

/* Each component of the date and time can be incremented/decremented
 * by clicking on the appropriate up or down arrow gadgets.
 */

static struct Gadget downsecgad = {
  &okgad,     					/* NextGadget pointer */
  184, 60,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,						/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &downborder,			/* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  DOWNSECGAD,   				/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upmin gadget.
 **********************************************************************/

static struct Gadget downmingad = {
  &downsecgad,     				/* NextGadget pointer */
  160, 60,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &downborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  DOWNMINGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the uphour gadget.
 **********************************************************************/

static struct Gadget downhourgad = {
  &downmingad,     				/* NextGadget pointer */
  136, 60,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &downborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  DOWNHOURGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upyear gadget.
 **********************************************************************/

static struct Gadget downyeargad = {
  &downhourgad,     				/* NextGadget pointer */
  112, 60,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &downborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  DOWNYEARGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upday gadget.
 **********************************************************************/

static struct Gadget downdaygad = {
  &downyeargad,     				/* NextGadget pointer */
  88, 60,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &downborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  DOWNDAYGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upmonth gadget.
 **********************************************************************/

static struct Gadget downmonthgad = {
  &downdaygad,     /* NextGadget pointer */
  64, 60,    /* LeftEdge, TopEdge  */
  15, 8,    /* Width, Height      */
  /* Gadget Flags */
   NULL,
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &downborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  DOWNMONTHGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upsec gadget.
 **********************************************************************/

static struct Gadget upsecgad = {
  &downmonthgad,    				/* NextGadget pointer */
  184, 40,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &upborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  UPSECGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upmin gadget.
 **********************************************************************/

static struct Gadget upmingad = {
  &upsecgad,     				/* NextGadget pointer */
  160, 40,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &upborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  UPMINGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};
/**********************************************************************
 *  Gadget Structure definition for the uphour gadget.
 **********************************************************************/

static struct Gadget uphourgad = {
  &upmingad,     				/* NextGadget pointer */
  136, 40,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &upborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  UPHOURGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upyear gadget.
 **********************************************************************/

static struct Gadget upyeargad = {
  &uphourgad,     				/* NextGadget pointer */
  112, 40,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &upborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  UPYEARGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upday gadget.
 **********************************************************************/

static struct Gadget updaygad = {
  &upyeargad,     				/* NextGadget pointer */
  88, 40,    					/* LeftEdge, TopEdge  */
  15, 8,    					/* Width, Height      */
   NULL,					/* Gadget Flags */
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &upborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  UPDAYGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

/**********************************************************************
 *  Gadget Structure definition for the upmonth gadget.
 **********************************************************************/

static struct Gadget upmonthgad = {
  &updaygad,     /* NextGadget pointer */
  64, 40,    /* LeftEdge, TopEdge  */
  15, 8,    /* Width, Height      */
  /* Gadget Flags */
   NULL,
	RELVERIFY , 				/* Activation Flags */
  REQGADGET | BOOLGADGET,		/* GadgetType */
  (APTR) &upborder,			    /* GadgetRender */
  NULL,							/* SelectRender */
   NULL,    					/* GadgetText */
  0x0,    						/* MutualExclude */
  NULL,   						/* SpecialInfo */
  UPMONTHGAD,   					/* GadgetID */
  NULL							/* UserData Pointer */
};

static struct Requester daterequest;	/* requester for the date */

/* Date requester border 2 coordinate pairs. */

static SHORT datereq_pairs2[] = {
	8, 4, 
	DATEREQWIDTH - 8, 4, 
	DATEREQWIDTH - 8, DATEREQHEIGHT - 4,
	8, DATEREQHEIGHT - 4,
	8, 4
};

/* Date requester border 2 definition */

static struct Border datereq_bord2 = {
  -1,  -1,       /* LeftEdge, TopEdge */
  0,  2,  JAM2,  /* FrontPen, BackPen, DrawMode*/
  5,             /* Count of XY pairs */  
  (SHORT *)&datereq_pairs2, /* XY pairs */
  NULL           /* Next Border */
};

/* Date requester border 1 coordinate pairs. */

static SHORT datereq_pairs1[] = {
	4, 2, 
	DATEREQWIDTH - 4, 2, 
	DATEREQWIDTH - 4, DATEREQHEIGHT - 2,
	4, DATEREQHEIGHT - 2,
	4, 2
};

/* Date requester border 1 definition. */

static struct Border datereq_bord1 = {
  -1,  -1,       /* LeftEdge, TopEdge */
  0,  2,  JAM2,  /* FrontPen, BackPen, DrawMode*/
  5,             /* Count of XY pairs */  
  (SHORT *)&datereq_pairs1, /* XY pairs */
  &datereq_bord2 /* Next Border */
};

/* This is the definition for the prompt string (user-supplied) which
 * appears in the requester.
 */

static struct IntuiText datereqtext = {
	1, 0,						/* FrontPen / BackPen */
	JAM2,						/* DrawMode */
	20,							/* LeftEdge */
	15,							/* TopEdge */
	&TxtAt_Plain,				/* ITextFont */
	NULL,						/* IText */
	NULL						/* NextText */
	};

static initialized = 0;			/* set to 1 after initialization */

static InitDateRequest()
{
	InitRequester(&daterequest);
	daterequest.LeftEdge = 60;
	daterequest.TopEdge = 10;
	daterequest.Width = DATEREQWIDTH;
	daterequest.Height = DATEREQHEIGHT;
	daterequest.ReqGadget = &upmonthgad;
	daterequest.ReqText = &datereqtext;
	daterequest.ReqBorder = &datereq_bord1;
	daterequest.BackFill = 2;
	++initialized;
}

/* Request a date from the user.
 * Called with:
 *		window:			pointer to window structure
 *		prompt:			string to be used as the prompt text
 *		default_date:	pointer to default date or NULL
 *		date:			pointer to date result (returned)
 * Returns:
 *		status code:	0 => success, 1 => failure
 *		(actually, always returns 0 - can't leave without good date)
 */

DateRequest(window,prompt,default_date,date)
	struct Window *window; char *prompt; 
	struct DateStamp *default_date,*date;
{
	ULONG class;				/* message class */
	USHORT code;				/* message code */
	struct Gadget *gadget;		/* pointer to gadget affected */
	USHORT gadgid;				/* gadget ID */
	struct IntuiMessage *msg;	/* Intuition message pointer */
	UnpackedDS upd;				/* unpacked version of date */
	SHORT x,y;					/* mouse x and y position */

	if (!initialized)
		InitDateRequest();
	datereqtext.IText = (UBYTE *) prompt;
	if (default_date)			/* write default date in requester? */
		DS2Str(dategad_sbuf_1,"%02m/%02d/%02y %02h:%02n:%02s",
			default_date);
	else
		*dategad_sbuf_1 = '\0';

	Request(&daterequest, window);

	for (;;) {
		Wait(1L << window->UserPort->mp_SigBit);
		while (msg = (struct IntuiMessage *) GetMsg(window->UserPort)) {
			class = msg->Class;
			code = msg->Code;
			gadget = (struct Gadget *) msg->IAddress;
			x = msg->MouseX;
			y = msg->MouseY;
			ReplyMsg(msg);		/* acknowledge the message */

			switch (class) {

			case REQSET: 
				ActivateGadget(&dategad,window,&daterequest);
				break;
			
			case GADGETUP:
				gadgid = gadget->GadgetID;
				if (gadgid == NOWGAD)
					DateStamp(date);
				else if (gadgid == OKGAD)
					gadgid = DATEGAD;

				UnpackDS(date, &upd);

				switch (gadgid) {
				case DATEGAD:
					if ( ! Str2DS(dategad_sbuf_1, date) ) {
						EndRequest(&daterequest, window);
						return 0;
					}
					else
						DisplayBeep(window->WScreen); /* bad conversion */
					break;

				case UPYEARGAD:
					++upd.year;
					break;

				case DOWNYEARGAD:
					if (upd.year > 1978) --upd.year;
					break;

				case UPMONTHGAD:
					if (++upd.month > 12) upd.month = 1;
					break;

				case DOWNMONTHGAD:
					if (--upd.month < 1) upd.month = 12;
					break;

				case UPDAYGAD:
					if (upd.day < 31) ++upd.day;
					break;

				case DOWNDAYGAD:
					if (upd.day > 1) --upd.day;
					break;

				case UPHOURGAD:
					if (++upd.hour > 23) upd.hour = 0;
					break;

				case DOWNHOURGAD:
					if (--upd.hour < 0) upd.hour = 23;
					break;

				case UPMINGAD:
					if (++upd.minute > 59) upd.minute = 0;
					break;

				case DOWNMINGAD:
					if (--upd.minute < 0) upd.minute = 59;
					break;

				case UPSECGAD:
					if (++upd.second > 59) upd.second = 0;
					break;

				case DOWNSECGAD:
					if (--upd.second < 0) upd.second = 59;
					break;

				default:
					break;
				}					/* end switch(gadgid) */

				/* Reformat the new date value. */

				PackDS(date, &upd);
				if (upd.year)
					DS2Str(dategad_sbuf_1,"%02m/%02d/%02y %02h:%02n:%02s",
						date);
				else
					strcpy(dategad_sbuf_1,"00/00/00 00:00:00");
				RefreshGadgets(&dategad, window, &daterequest);
				break;

			default:
				break;			/* ignore the rest */
			}					/* end switch(class) */
		}
	}
}

/*#define DEBUG */

#ifdef DEBUG

/* --- Only compiled in the debug version --- */

#include <exec/memory.h>

/* New window structure */

struct NewWindow newwindow = {
	0,0,640,200,0,1,

/* IDCMP Flags */

	MOUSEMOVE | MENUPICK | MOUSEBUTTONS | 
	CLOSEWINDOW | GADGETDOWN | GADGETUP | REQSET, 

/* Flags */
	WINDOWCLOSE | WINDOWDEPTH | ACTIVATE | RMBTRAP | REPORTMOUSE,

	NULL,							/* First gadget */
	NULL,							/* Checkmark */
	(UBYTE *)"Date Requester Test Program",	/* Window title */
	NULL,							/* No custom streen */
	NULL,							/* Not a super bitmap window */
	0,0,640,200,					/* Not used, but set up anyway */
	WBENCHSCREEN
};
struct IntuitionBase *IntuitionBase;
struct Window *mywindow;
struct DateStamp *ds;

static struct IntuiText MoreText = {
	AUTOFRONTPEN,				/* FrontPen */
	AUTOBACKPEN,				/* BackPen */
	JAM2,						/* DrawMode */
	AUTOLEFTEDGE,				/* LeftEdge */
	AUTOTOPEDGE,				/* TopEdge */
	AUTOITEXTFONT,				/* ITextFont */
	(UBYTE *) "Want to play some more?", /* IText */
	NULL						/* NextText */
	};

static struct IntuiText YesText = {
	AUTOFRONTPEN,				/* FrontPen */
	AUTOBACKPEN,				/* BackPen */
	AUTODRAWMODE,				/* DrawMode */
	AUTOLEFTEDGE,				/* LeftEdge */
	AUTOTOPEDGE,				/* TopEdge */
	AUTOITEXTFONT,				/* ITextFont */
	(UBYTE *) "Sure!", 			/* IText */
	NULL						/* NextText */
	};

static struct IntuiText NoText = {
	AUTOFRONTPEN,				/* FrontPen */
	AUTOBACKPEN,				/* BackPen */
	JAM2,						/* DrawMode */
	AUTOLEFTEDGE,				/* LeftEdge */
	AUTOTOPEDGE,				/* TopEdge */
	AUTOITEXTFONT,				/* ITextFont */
	(UBYTE *) "Nope!", 			/* IText */
	NULL						/* NextText */
	};

main()
{
	short keep_going;

	if (!(IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library",33L))) {
		puts("Failed to open Intuition library!");
		exit(1);
	}

	ds = (struct DateStamp *)
		AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
	DateStamp(ds);				/* get current date/time */

	mywindow = OpenWindow(&newwindow);

	do {
		DateRequest(mywindow, "Enter date and time", ds, ds);
		keep_going = AutoRequest(mywindow, &MoreText, &YesText, &NoText,
						NULL, NULL, 220L, 50L);
	} while (keep_going);

	if (mywindow)
		CloseWindow(mywindow);

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);
}

#endif
