/**
*** XPG - Graphical User Interface for Postgres
*** Copyright (C) 1993  Ranen Goren (ranen@cs.huji.ac.il).

*** This program is free software; you can redistribute it and/or modify
*** it under the terms of the GNU General Public License as published by
*** the Free Software Foundation; either version 2 of the License, or
*** (at your option) any later version.

*** This program is distributed in the hope that it will be useful,
*** but WITHOUT ANY WARRANTY; without even the implied warranty of
*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*** GNU General Public License for more details.

*** You should have received a copy of the GNU General Public License
*** along with this program; if not, write to the Free Software
*** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**/


#include <stdio.h>
#include <time.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h> 
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/CascadeB.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
#include <Xm/DialogS.h>
#include <Xm/TextF.h>
#include <Xm/Separator.h>
#include "xpg.h"

#ifdef MEM_DEBUG
#include "/CS/system/ranen/Src/Lib/Malloc/malloc.h"
#endif

#define MAX_YEAR_RANGE 50


typedef struct
{
    Widget shell;
    Widget monthBut,  day10But,  day1But,  yearBut,
           hour10But, hour1But, min10But, min1But;
    Widget monthItem, day10Item, day1Item, yearItem,
           hour10Item, hour1Item, min10Item, min1Item;
} menuItems;



extern void _XEditResCheckMessages();     /* for editres */


void datePopup();
void monthCB();
void day10CB();
void day1CB();
void yearCB();
void hour10CB();
void hour1CB();
void min10CB();
void min1CB();
void dateNow();
void timeNow();
void dateCancel();
void dateOk();


static char *monthNames[] = {"January",   "February",  "March", 
			     "April",     "May",       "June", 
			     "July",      "August",    "September", 
			     "October",   "November",  "December"   };



/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void datePopup(textW)
{
    relInfo *rel;
    Widget shell, mainBox, actionBox;
    Widget todayBut, nowBut, sep, okBut, cancelBut;
    Widget monthsBut, days10But, days1But, yearsBut,
           hour10But, hour1But, min10But, min1But;
    Widget *list;
    XmString compStr;
    Widget bar, months, days10, days1, years, hour10, hour1, min10, min1;
    Widget menuBut[12];
    Arg args[10];
    char buf[5];
    int i, n;
    int year1, year2;
    menuItems *items;

    setCursor(textW, XC_watch);
    XtVaGetValues(textW, XmNuserData, &rel, NULL);
    parseYearResources(rel->res.yearRangeFrom, &year1, 
		       rel->res.yearRangeTo,   &year2);
#ifdef XPG_DEBUG
    printf("from %d to %d\n", year1, year2);
#endif

    items = XtNew(menuItems);

    XtSetArg(args[0], XmNallowShellResize, False);
    items->shell = shell = XmCreateDialogShell(textW, "dateShell", args, 1);
    setWidgetPos(shell, textW, 0.5, 0, 0.5, 0);
    XtSetArg(args[0], XmNresizable, False);
    mainBox = XmCreateForm(shell, "dateMainBox", args, 1);

    n=0;
    bar = XmCreateMenuBar(mainBox, "dateMenu", args, n);
    XtManageChild(bar);

    actionBox = XtVaCreateManagedWidget("dateActionBox", 
					xmFormWidgetClass, mainBox, NULL);
    todayBut = XtVaCreateManagedWidget("dateTodayBut", 
				       xmPushButtonWidgetClass, actionBox, 
				       XmNtopAttachment,    XmATTACH_FORM,
				       XmNleftAttachment,   XmATTACH_FORM,
				       XmNrightAttachment,   XmATTACH_POSITION,
				       XmNrightPosition,     50,
				       NULL);
    XtAddCallback(todayBut, XmNactivateCallback, dateNow, items);
    
    nowBut = XtVaCreateManagedWidget("dateNowBut", 
				     xmPushButtonWidgetClass, actionBox, 
				     XmNtopAttachment,    XmATTACH_FORM,
				     XmNleftAttachment,   XmATTACH_WIDGET,
				     XmNleftWidget,       todayBut,
				     XmNrightAttachment,  XmATTACH_FORM,
				     XmNbottomAttachment, 
				                    XmATTACH_OPPOSITE_WIDGET,
				     XmNbottomWidget,     todayBut,
				     NULL);
    XtAddCallback(nowBut, XmNactivateCallback, timeNow, items);
    
    sep = XtVaCreateManagedWidget("dateSep", xmSeparatorWidgetClass, 
				  actionBox,
				  XmNtopAttachment,     XmATTACH_WIDGET,
				  XmNtopWidget,         todayBut,
				  XmNleftAttachment,    XmATTACH_FORM,
				  XmNrightAttachment,   XmATTACH_FORM,
				  NULL);

    okBut = XtVaCreateManagedWidget("dateOkBut", xmPushButtonWidgetClass, 
				    actionBox,
				    XmNuserData,          textW,
				    XmNtopAttachment,     XmATTACH_WIDGET,
				    XmNtopWidget,         sep,
				    XmNleftAttachment,    XmATTACH_FORM,
				    XmNrightAttachment,   XmATTACH_POSITION,
				    XmNrightPosition,     50,
				    XmNbottomAttachment,  XmATTACH_FORM,
				    NULL);
    XtAddCallback(okBut, XmNactivateCallback, dateOk, items);
    cancelBut = XtVaCreateManagedWidget("dateCancelBut", 
					xmPushButtonWidgetClass, actionBox, 
					XmNtopAttachment,     XmATTACH_WIDGET,
					XmNtopWidget,         sep,
					XmNleftAttachment,    XmATTACH_WIDGET,
					XmNleftWidget,        okBut,
					XmNbottomAttachment,  XmATTACH_FORM,
					XmNrightAttachment,   XmATTACH_FORM,
					NULL);
    XtAddCallback(cancelBut, XmNactivateCallback, dateCancel, items);
    
    months = XmCreatePulldownMenu(bar, "monthMenu",  NULL, 0);
    days10 = XmCreatePulldownMenu(bar, "days10Menu", NULL, 0);
    days1  = XmCreatePulldownMenu(bar, "days1Menu",  NULL, 0);
    years  = XmCreatePulldownMenu(bar, "yearsMenu",  NULL, 0);
    hour10 = XmCreatePulldownMenu(bar, "hour10Menu", NULL, 0);
    hour1  = XmCreatePulldownMenu(bar, "hour1Menu",  NULL, 0);
    min10  = XmCreatePulldownMenu(bar, "min10Menu",  NULL, 0);
    min1   = XmCreatePulldownMenu(bar, "min1Menu",   NULL, 0);

    XtSetArg(args[0], XmNsubMenuId, months);
    XtSetArg(args[1], XmNborderWidth, 0);
    XtSetArg(args[2], XmNshadowThickness, 0);
    XtSetArg(args[3], XmNmarginRight, 0);
    XtSetArg(args[4], XmNmarginWidth, 0);
    XtSetArg(args[5], XmNhighlightThickness,  0);
    monthsBut = XmCreateCascadeButton(bar, "  January", args, 6);
    items->monthBut = monthsBut;
    XtVaSetValues(monthsBut, XmNalignment, XmALIGNMENT_CENTER, NULL);
    XtManageChild(monthsBut);
    XtSetArg(args[0], XmNsubMenuId, days10);
    XtSetArg(args[6], XmNmarginLeft, 0);
    days10But = XmCreateCascadeButton(bar, " 0",        args, 7);
    items->day10But = days10But;
    XtManageChild(days10But);
    XtSetArg(args[0], XmNsubMenuId, days1);
    days1But  = XmCreateCascadeButton(bar, "1st, ",     args, 6);
    items->day1But = days1But;
    XtManageChild(days1But);
    XtSetArg(args[0], XmNsubMenuId, years);
    yearsBut  = XmCreateCascadeButton(bar, "1900 ",     args, 6);
    items->yearBut = yearsBut;
    XtManageChild(yearsBut);
    XtSetArg(args[0], XmNsubMenuId, hour10);
    hour10But = XmCreateCascadeButton(bar, " -",        args, 6);
    items->hour10But = hour10But;
    XtManageChild(hour10But);
    XtSetArg(args[0], XmNsubMenuId, hour1);
    hour1But  = XmCreateCascadeButton(bar, "-:",         args, 6);
    items->hour1But = hour1But;
    XtManageChild(hour1But);
    XtSetArg(args[0], XmNsubMenuId, min10);
    min10But  = XmCreateCascadeButton(bar, "-",        args, 6);
    items->min10But = min10But;
    XtManageChild(min10But);
    XtSetArg(args[0], XmNsubMenuId, min1);
    min1But   = XmCreateCascadeButton(bar, "- ",        args, 6);
    items->min1But = min1But;
    XtManageChild(min1But);
    

    for (i=0; i<12; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(months, monthNames[i], NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	XtAddCallback(menuBut[i], XmNactivateCallback, monthCB, monthNames[i]);
    }
    XtManageChildren(menuBut, 12);
    items->monthItem = menuBut[0];

    for (i=0; i<4; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(days10, "dayButton", NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	sprintf(buf, "%01d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[i], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[i], XmNactivateCallback, day10CB, (XtPointer)i);
    }
    XtManageChildren(menuBut, 4);
    items->day10Item = menuBut[0];

    for (i=0; i<10; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(days1, "dayButton", NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	sprintf(buf, "%d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[i], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[i], XmNactivateCallback, day1CB, (XtPointer)i);
    }
    XtManageChildren(menuBut, 10);
    items->day1Item = menuBut[0];

    for (i=year1; i<=year2; i++)
    {
	menuBut[0] = XmCreatePushButtonGadget(years, "yearButton", NULL, 0);
	XtVaSetValues(menuBut[0], XmNuserData, items, NULL);
	sprintf(buf, "%d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[0], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[0], XmNactivateCallback, yearCB, (XtPointer)i);
	XtManageChild(menuBut[0]);
    }
    items->yearItem = menuBut[0];

    for (i=0; i<3; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(hour10, "hourButton", NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	sprintf(buf, "%01d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[i], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[i], XmNactivateCallback, hour10CB, (XtPointer)i);
    }
    XtManageChildren(menuBut, 3);
    items->hour10Item = menuBut[0];

    for (i=0; i<10; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(hour1, "hourButton", NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	sprintf(buf, "%d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[i], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[i], XmNactivateCallback, hour1CB, (XtPointer)i);
    }
    XtManageChildren(menuBut, 10);
    items->hour1Item = menuBut[0];

    for (i=0; i<6; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(min10, "minButton", NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	sprintf(buf, "%01d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[i], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[i], XmNactivateCallback, min10CB, (XtPointer)i);
    }
    XtManageChildren(menuBut, 6);
    items->min10Item = menuBut[0];

    for (i=0; i<10; i++)
    {
	menuBut[i] = XmCreatePushButtonGadget(min1, "minButton", NULL, 0);
	XtVaSetValues(menuBut[i], XmNuserData, items, NULL);
	sprintf(buf, "%d", i);
	compStr = XmStringCreateSimple(buf);
	XtVaSetValues(menuBut[i], XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	XtAddCallback(menuBut[i], XmNactivateCallback, min1CB, (XtPointer)i);
    }
    XtManageChildren(menuBut, 10);
    items->min1Item = menuBut[0];

    setFormColumn(mainBox, 1);
    XtManageChild(mainBox); 
    dateNow(NULL, items, NULL);
    XtPopup(shell, XtGrabNone);
    setCursor(textW, None);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void monthCB(w, month, cbs)
  Widget w;
  char *month;
  XtPointer cbs;
{
    XmString compStr;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    compStr = XmStringCreateSimple(month);
    XtVaSetValues(items->monthBut, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void day10CB(w, dayNumPtr, cbs)
  Widget w;
  XtPointer dayNumPtr;
  XtPointer cbs;
{
    int dayNum = (int)dayNumPtr;
    XmString compStr;
    char buf[10];
    XtPointer valPtr;
    int check;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    XtVaGetValues(XtParent(items->day1Item), XmNuserData, &valPtr, NULL);
    check = (int)valPtr%10 + dayNum*10;
    /*
      if (check>31 || check<1)
      return;
      */
    XtVaSetValues(XtParent(items->day1Item), 
		  XmNuserData, (XtPointer)check, 
		  NULL);
    sprintf(buf, " %d", dayNum);
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->day10But, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
    day1CB(items->day1Item, (XtPointer)(check % 10), NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void day1CB(w, dayNumPtr, cbs)
  Widget w;
  XtPointer dayNumPtr;
  XtPointer cbs;
{
    int dayNum = (int)dayNumPtr;
    char *dayExt;
    XmString compStr;
    char buf[10];
    XtPointer valPtr;
    int check;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    XtVaGetValues(XtParent(w), XmNuserData, &valPtr, NULL);
    check = ((int)valPtr/10)*10 + dayNum;
    /*
      if (check>31 || check<1)
      return;
      */
    XtVaSetValues(XtParent(w), XmNuserData, (XtPointer)check, NULL);
    dayExt = "th";  /*default*/
    if (check/10 != 1)  /* 11th, 12th, 13th */
    {
	if (dayNum == 1)   dayExt = "st";
	if (dayNum == 2)   dayExt = "nd";
	if (dayNum == 3)   dayExt = "rd";
    }
    if (check>31 || check<1)
	dayExt = "??";
    sprintf(buf, "%01d%s, ", dayNum, dayExt);
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->day1But, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void yearCB(w, yearPtr, cbs)
  Widget w;
  XtPointer yearPtr;
  XtPointer cbs;
{
    int year = (int)yearPtr;
    XmString compStr;
    char buf[10];
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    sprintf(buf, "%d ", year);
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->yearBut, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void hour10CB(w, hourNumPtr, cbs)  /* negative val keeps the current time */
  Widget w;
  XtPointer hourNumPtr;
  XtPointer cbs;
{
    int hourNum = (int)hourNumPtr;
    XmString compStr;
    char buf[10];
    XtPointer valPtr;
    int check;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    XtVaGetValues(XtParent(items->hour1Item), XmNuserData,&valPtr, NULL);
    if (hourNum < 0)      /* negative value means keep the current time */
	hourNum = (int)valPtr / 10;
    check = (int)valPtr%10 + hourNum*10;
    /*
      if (check>23)
      return;
      */
    XtVaSetValues(XtParent(items->hour1Item), 
		  XmNuserData, (XtPointer)check, 
		  NULL);
    sprintf(buf, " %d", hourNum);
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->hour10But, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
    hour1CB(items->hour1Item, (XtPointer)(check % 10), NULL);
    /* the next call will change the "--" in the minutes part, if needed */
    if ((int)hourNumPtr >= 0)  /* no inf. loops allowed! */
	min10CB(items->min10Item, (XtPointer)(-1), NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void hour1CB(w, hourNumPtr, cbs)  /* negative val keeps the current time */
  Widget w;
  XtPointer hourNumPtr;
  XtPointer cbs;
{
    int hourNum = (int)hourNumPtr;
    XmString compStr;
    char buf[10];
    XtPointer valPtr;
    int check;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    XtVaGetValues(XtParent(w), XmNuserData, &valPtr, NULL);
    if (hourNum < 0)      /* negative value means keep the current time */
	hourNum = (int)valPtr % 10;
    check = ((int)valPtr/10)*10 + hourNum;
    /*
      if (check>23)
      return;
      */
    XtVaSetValues(XtParent(w), XmNuserData, (XtPointer)check, NULL);
    sprintf(buf, "%01d%c", hourNum, (check>23 ? '?' : ':'));
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->hour1But, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
    if (cbs != NULL)
	hour10CB(items->hour10Item, (XtPointer)(check / 10), NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void min10CB(w, minNumPtr, cbs)  /* negative val keeps the current time */
  Widget w;
  XtPointer minNumPtr;
  XtPointer cbs;
{
    int minNum = (int)minNumPtr;
    XmString compStr;
    char buf[10];
    Widget min10But;
    XtPointer valPtr;
    int check;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    XtVaGetValues(XtParent(items->min1Item), XmNuserData, &valPtr, NULL);
    if (minNum < 0)      /* negative value means keep the current time */
	minNum = (int)valPtr / 10;
    check = (int)valPtr%10 + minNum*10;
    /*
      if (check>23)
      return;
      */
    XtVaSetValues(XtParent(items->min1Item), 
		  XmNuserData, (XtPointer)check, 
		  NULL);
    sprintf(buf, "%d", minNum);
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->min10But, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
    min1CB(items->min1Item, (XtPointer)(check % 10), NULL);
    /* the next call will change the "--" in the hours part, if needed */
    if ((int)minNumPtr >= 0)  /* no inf. loops allowed! */
	hour10CB(items->hour10Item, (XtPointer)(-1), NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void min1CB(w, minNumPtr, cbs)  /* negative val keeps the current time */
  Widget w;
  XtPointer minNumPtr;
  XtPointer cbs;
{
    int minNum = (int)minNumPtr;
    XmString compStr;
    char buf[10];
    XtPointer valPtr;
    int check;
    menuItems *items;
    
    XtVaGetValues(w, XmNuserData, &items, NULL);
    XtVaGetValues(XtParent(w), XmNuserData, &valPtr, NULL);
    if (minNum < 0)      /* negative value means keep the current time */
	minNum = (int)valPtr % 10;
    check = ((int)valPtr/10)*10 + minNum;
    /*
      if (check>23)
      return;
      */
    XtVaSetValues(XtParent(w), XmNuserData, (XtPointer)check, NULL);
    sprintf(buf, "%01d", minNum);
    compStr = XmStringCreateSimple(buf);
    XtVaSetValues(items->min1But, XmNlabelString, compStr, NULL);
    XmStringFree(compStr);
    if (cbs != NULL)
	min10CB(items->min10Item, (XtPointer)(check / 10), NULL);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void dateNow(w, items, cbs)
  Widget w;
  menuItems *items;
  XtPointer cbs;
{
    time_t clock;
    struct tm *local;

    time(&clock);
    local = localtime(&clock);
    setDate(items, local->tm_mday, local->tm_mon, local->tm_year+1900);
    setTime(items, -1, -1);
    free(local);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void timeNow(w, items, cbs)
  Widget w;
  menuItems *items;
  XtPointer cbs;
{
    time_t clock;
    struct tm *local;

    dateNow(NULL, items, NULL);
    time(&clock);
    local = localtime(&clock);
    setTime(items, local->tm_hour, local->tm_min);
    free(local);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
setDate(items, day, month, year)
  menuItems *items;
  int day, month, year;
{
    XtVaSetValues(XtParent(items->day1Item), 
		  XmNuserData, (XtPointer)day, 
		  NULL);
    monthCB(items->monthItem, monthNames[month], NULL);
    day10CB(items->day10Item, (XtPointer)(day / 10), NULL);
    day1CB (items->day1Item,  (XtPointer)(day % 10), NULL);
    yearCB (items->yearItem,  (XtPointer)year, NULL);
}	





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
setTime(items, hour, min)   /* value of -1 for hour/min marks undefined time */
  menuItems *items;
  int hour, min;
{
    XmString compStr;
    
    XtVaSetValues(XtParent(items->hour1Item), 
		  XmNuserData, (XtPointer)(hour>=0 ? hour : 0), 
		  NULL);
    XtVaSetValues(XtParent(items->min1Item), 
		  XmNuserData, (XtPointer)(min>=0 ? min : 0), 
		  NULL);
    if (hour >= 0)
    {
	hour10CB(items->hour10Item, (XtPointer)(hour / 10), NULL);
	hour1CB (items->hour1Item,  (XtPointer)(hour % 10), NULL);
    }
    else
    {
	compStr = XmStringCreateSimple(" -");
	XtVaSetValues(items->hour10But, XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	compStr = XmStringCreateSimple("-:");
	XtVaSetValues(items->hour1But, XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
    }	
    if (min >= 0)
    {
	min10CB (items->min10Item,  (XtPointer)(min  / 10), NULL);
	min1CB  (items->min1Item,   (XtPointer)(min  % 10), NULL);
    }
    else
    {
	compStr = XmStringCreateSimple("-");
	XtVaSetValues(items->min10But, XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
	compStr = XmStringCreateSimple("- ");
	XtVaSetValues(items->min1But, XmNlabelString, compStr, NULL);
	XmStringFree(compStr);
    }	
}	





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* parses the <res> strings and puts the result year into <year>.
   allowable <res> values are either an absolute number representing
   a year, or a "+num" or "-num" which represent a relative notation.
   returns 0 if succeeded, 1 otherwise. */

parseYearResources(res1, year1, res2, year2)
  char *res1, *res2;
  int *year1, *year2;
{
    static int year1Store=0, year2Store=0;
    time_t clock;
    struct tm *local;
    int now, diff;
    Boolean err1=False, err2=False;
    
    if (year1Store && year2Store)    /* return the previously parsed values */
    {
	*year1 = year1Store;
	*year2 = year2Store;
	return;
    }
    time(&clock);
    local = localtime(&clock);
    now = local->tm_year + 1900;
    free(local);
    year1Store = *year1 = now-2;
    year2Store = *year2 = now+2;
    if (res1[0] == '+'  ||  res1[0] == '-')
    {
	if (sscanf(res1+1, "%d", year1) < 1)
	    err1 = True;
	if (res1[0] == '-')
	    *year1 = -*year1;
	*year1 += now;
    }
    else
	if (sscanf(res1, "%d", year1) < 1)
	{
	    *year1 = year1Store;
	    err1 = True;
	}
    if (res2[0] == '+'  ||  res2[0] == '-')
    {
	if (sscanf(res2+1, "%d", year2) < 1)
	    err2 = True;
	if (res2[0] == '-')
	    *year2 = -*year2;
	*year2 += now;
    }
    else
	if (sscanf(res2, "%d", year2) < 1)
	{
	    *year2 = year2Store;
	    err2 = True;
	}
    if (err1)
    {
	XtWarning("Illegal value for the year1 resource. Using default (-2)");
	*year1 = year1Store;
    }
    if (err2)
    {
	XtWarning("Illegal value for the year2 resource. Using default (+2)");
	*year2 = year2Store;
    }
    if ((diff = (*year2 - *year1)) < 0 || diff > MAX_YEAR_RANGE)
    {
	*year1 = year1Store;
	*year2 = year2Store;
	XtWarning("Illegal range for the years resources. Using default range (-2..+2)");
	err1 = err2 = True;
    }
    year1Store = *year1;
    year2Store = *year2;
    if (err1 || err2)
	return 1;
    return 0;
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void dateCancel(w, items, cbs)
  Widget w;
  menuItems *items;
  XtPointer cbs;
{
    XtDestroyWidget(items->shell);
    XtFree(items);
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void dateOk(w, items, cbs)
  Widget w;
  menuItems *items;
  XtPointer cbs;
{
    Widget textW;
    char buf[256];
    char timeBuf[10];
    XmString compStr;
    String month, day10, day1, year, hour10, hour1, min10, min1;
    int hourAsInt;
    
    XtVaGetValues(w, XmNuserData, &textW, NULL);
    XtVaGetValues(items->monthBut, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &month);
    XtVaGetValues(items->day10But, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &day10);
    XtVaGetValues(items->day1But, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &day1);
    XtVaGetValues(items->yearBut, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &year);
    XtVaGetValues(items->hour10But, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &hour10);
    XtVaGetValues(items->hour1But, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &hour1);
    XtVaGetValues(items->min10But, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &min10);
    XtVaGetValues(items->min1But, XmNlabelString, &compStr, NULL);
    XmStringGetLtoR(compStr, XmSTRING_DEFAULT_CHARSET, &min1);
    if (hour10[1] == '-')
	timeBuf[0] = '\0';
    else
    {
	hourAsInt = atoi(hour10)*10 + atoi(hour1);
	/* the following 3 lines correct a very strange behavior of
	   Postgres: first, in contradiction to the manual, the acceptable
	   hour range is 00-23 (and not 01-24). Then, each of this hours
	   result (in queries) in the next hour! eg. 00 is actually 01,...
	   and 23 is actually 00. The date dialog can fix this confusion
	   by passing Postgres the previous hour, getting as result the
	   hour you really want... While this is convenient if the date
	   dialog is always used, it just adds more confusion if both
	   the date dialog and the text entry field are used for date
	   and time entry. Also, I'm not so sure this behavior is found
	   on all systems, maybe we have some local problem? Maybe it's
	   the "daylight saving hour" which we currently have? So,
	   in order to get the modified behavior, uncomment the following
	   three lines.  */
/*
        hourAsInt = hourAsInt - 1;
	if (hourAsInt == -1)
	    hourAsInt = 23;
*/
	sprintf(timeBuf, "%02d:%01d%01d:00 ", hourAsInt, atoi(min10), 
		atoi(min1));
    }
    sprintf(buf, "\"%.3s %d%d %s%d\"", 
	    month, atoi(day10), atoi(day1), timeBuf, atoi(year));
    XmTextFieldSetString(textW, buf);
    XtFree(month);
    XtFree(day10);
    XtFree(day1);
    XtFree(year);
    XtFree(hour10);
    XtFree(hour1);
    XtFree(min10);
    XtFree(min1);
    dateCancel(NULL, items, NULL);      /* destroy the date popup */
}
