#include <exec/execbase.h>
#include <dos/dos.h>
#include <intuition/intuition.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// $VER: ClockChk.c V1.1 (C) by Christian Wasner  (12-Feb-97)
BYTE Version[]="$VER: ClockChk V1.1 (C) by Christian Wasner  (12-Feb-97)";

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct IntuitionBase *IntuitionBase;

BYTE Date1[LEN_DATSTRING],Time1[LEN_DATSTRING],
     Date2[LEN_DATSTRING],Time2[LEN_DATSTRING],
     Buf[256];

// Requester body texts
BYTE InvalidDayDiff[]="WARNING\n"
		                "Environment variable with number\n"
		                "of days between two sessions\n"
		                "is invalid",
     CantSetEnvVar[]= "WARNING\n"
                      "Cannot set environment variable",
     NoLastSession[]= "WARNING\n"
                      "Environment variable with date of\n"
                      "last session not found or invalid",
     DiffTooBig[]=    "WARNING:\n"
		                "Current date: %s %s\n"
		                "Last session: %s %s\n"
		                "Difference more than %ld days",
     SaveInFuture[]=  "WARNING:\n"
		                "Current date: %s %s\n"
		                "Last session: %s %s\n"
		                "Last session is in future",
     NoTimePrefs[]=   "WARNING\n"
                      "Cannot start time prefs\n"
                      "(%s)",
     DateChanged[]=   "WARNING: Date changed\n"
                      "Current date: %s %s\n"
                      "Change by: %ld days %ld hours %ld minutes",
     NoThisSession[]= "WARNING\n"
                      "Cannot save date of this session";

// Requester gadget texts
BYTE SetClk[]="Set clock",
     SetDef3[]="Set var to 3",
     DelVar[]="Delete var",
     SetToday[]="Set to today",
     Ignore[]="Ignore",
     Retry[]="Retry",
     Cancel[]="Cancel";

BYTE DayDiffVar[]="ENVARC:DAYDIFF",
     LastDateVar[]="LASTDATE";       // Not with ENVARC: !!

struct DateStamp DS1,DS2;

struct DateTime DateTime1={0,0,0,FORMAT_DOS,0,NULL,Date1,Time1},
                DateTime2={0,0,0,FORMAT_DOS,0,NULL,Date2,Time2};

LONG DayDiff;

VOID cleanup(BYTE err[]);
BOOL SetVariable(BYTE Var[],BYTE Val[]);
BOOL SetDate(struct DateTime *dt);
BOOL Requester(BYTE Body[],BYTE Pos[],BYTE Neg[]);

LONG __saveds main(VOID)
{
	LONG mindiff;
	BOOL OK;
	LONG i,j;

	SysBase=*(struct ExecBase **)4;

	DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",0);
	IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37);

// Open libraries

	if (!DOSBase || !IntuitionBase)
	{
		cleanup(DOSBase ? "Cannot open intuition.library V37.\n":NULL);
		return 20;
	}

	if (DOSBase->dl_lib.lib_Version<37)
	{
		cleanup("You need dos.library V37+ (Kickstart 2.04).\n");
		return 20;
	}

// Get current date
	DateStamp(&DateTime2.dat_Stamp);
	DateToStr(&DateTime2);

// Get and check environment variables

	GetVar(&DayDiffVar[7],Buf,256,LV_VAR|GVF_GLOBAL_ONLY);

	if (!Buf[0])
		DayDiff=3;
	else if ((DayDiff=atol(Buf))<1)
	{
		if (Requester(InvalidDayDiff,SetDef3,DelVar))
			while (!SetVariable(&DayDiffVar[7],"3")
				&& Requester(CantSetEnvVar,Retry,Ignore));
		else
		{
			DeleteFile(DayDiffVar);
			OK=(DeleteVar(&DayDiffVar[7],LV_VAR|GVF_GLOBAL_ONLY)==DOSTRUE);
		}

		DayDiff=3;
	}

	Buf[0]=0;
	GetVar("LASTDATE",Buf,256,LV_VAR|GVF_GLOBAL_ONLY);
	if (Buf[0])
	{
// Parse date and time of last seeesion
		for (i=0;Buf[i] && Buf[i]!=' ';i++)
			Date1[i]=Buf[i];
		if (Buf[i]==' ')
		{
			Date1[i++]=0;
			for (j=0;Buf[i+j] && Buf[i+j]!=' ';j++)
				Time1[j]=Buf[i+j];
			Time1[j]=0;
		}
		else
			Buf[0]=0;
	}

	if (!Buf[0])
	{
		strcpy(Date1,Date2);
		strcpy(Time1,Time2);
		StrToDate(&DateTime1);
		if (Requester(NoLastSession,SetToday,Ignore))
		{
			strcpy(Buf,DateTime1.dat_StrDate);
			strcat(Buf," ");
			strcat(Buf,DateTime1.dat_StrTime);
			while (!SetVariable(LastDateVar,Buf)
				&& Requester(CantSetEnvVar,Retry,Ignore));
		}

		DateTime1.dat_Stamp=DateTime2.dat_Stamp;
	}
	else
		StrToDate(&DateTime1);

	if ((DateTime2.dat_Stamp.ds_Days-DateTime1.dat_Stamp.ds_Days)*1440+
		DateTime2.dat_Stamp.ds_Minute-DateTime1.dat_Stamp.ds_Minute
		>1440*DayDiff)
		sprintf(Buf,DiffTooBig,
		            DateTime2.dat_StrDate,DateTime2.dat_StrTime,
		            DateTime1.dat_StrDate,DateTime1.dat_StrTime,
		            DayDiff);
	else if (CompareDates(&DateTime1.dat_Stamp,&DateTime2.dat_Stamp)<0)
		sprintf(Buf,SaveInFuture,
		            DateTime2.dat_StrDate,DateTime2.dat_StrTime,
		            DateTime1.dat_StrDate,DateTime1.dat_StrTime,
		            DayDiff);
	else
		Buf[0]=0;

	if (Buf[0] && Requester(Buf,SetClk,Ignore))
		SetDate(&DateTime2);

	do
	{
		strcpy(Buf,Date2);
		strcat(Buf," ");
		strcat(Buf,Time2);
		if (!(OK=SetVariable(LastDateVar,Buf)))
			OK=!Requester(NoThisSession,Retry,Ignore);
	}
	while (!OK);

	while (CheckSignal(SIGBREAKF_CTRL_C)!=SIGBREAKF_CTRL_C)
	{
		DateTime1.dat_Stamp=DateTime2.dat_Stamp;
		Delay(50);
		DateStamp(&DateTime2.dat_Stamp);
		mindiff=1440*(DateTime2.dat_Stamp.ds_Days-DateTime1.dat_Stamp.ds_Days)+
			DateTime2.dat_Stamp.ds_Minute-DateTime1.dat_Stamp.ds_Minute;

		if (mindiff!=1 && mindiff!=0)
		{
			DateToStr(&DateTime2);

			sprintf(Buf,DateChanged,DateTime2.dat_StrDate,DateTime2.dat_StrTime,
				mindiff/1440,(mindiff/60)%24,mindiff%60);
			if (Requester(Buf,SetClk,Ignore))
				SetDate(&DateTime2);
		}
	}

	cleanup(NULL);
}

// Requester

BOOL Requester(BYTE Body[],BYTE Pos[],BYTE Neg[])
{
	struct IntuiText b[5]={{1,0,JAM1,0,0,NULL,NULL,NULL},
	                       {1,0,JAM1,0,0,NULL,NULL,NULL},
	                       {1,0,JAM1,0,0,NULL,NULL,NULL},
	                       {1,0,JAM1,0,0,NULL,NULL,NULL},
	                       {1,0,JAM1,0,0,NULL,NULL,NULL}},
                    p={1,0,JAM1,0,0,NULL,NULL,NULL},
                    n={1,0,JAM1,0,0,NULL,NULL,NULL};
	LONG i,t,x,h,l,l0;
	BYTE buf[200];
	struct Screen *wb;

	p.IText=(UBYTE *)Pos;
	n.IText=(UBYTE *)Neg;
	strncpy(buf,Body,200);
	buf[199]=0;

	if (wb=LockPubScreen("Workbench"))
	{
		h=(6*wb->Font->ta_YSize)/5;
		UnlockPubScreen(NULL,wb);
	}
	else
		h=9;

	l=IntuiTextLength(&n)+IntuiTextLength(&p)+3*h;

	for (i=t=x=0;;i++)
	{
		if (buf[i]=='\n' || !buf[i])
		{
			b[t].FrontPen=1;
			b[t].BackPen=1;
			b[t].DrawMode=JAM1;
			b[t].LeftEdge=0;
			b[t].TopEdge=h*t+h/2;
			b[t].ITextFont=NULL;
			b[t].IText=(UBYTE *)&buf[x];
			b[t].NextText=&b[t+1];
			if ((l0=IntuiTextLength(&b[t]))>l)
				l=l0;
			if (t==4)
				break;
			else
				t++;
			x=i+1;
			if (!buf[i])
				break;
			buf[i]=0;
		}
	b[t].NextText=NULL;
	}

	return AutoRequest(NULL,&b[0],&p,&n,0,0,l+5*h,(t+5)*h);
}

// Call time prefs and set up requester text on failure

BOOL SetDate(struct DateTime *dt)
{
	BOOL OK;
	BPTR nil;

	do
	{
		nil=Open("NIL:",MODE_NEWFILE);
		Buf[0]=0;
		if (GetVar("TIMEPREFS",Buf,256,LV_VAR|GVF_GLOBAL_ONLY)<1)
			strcpy(Buf,"SYS:Prefs/Time");

		if (OK=Execute(Buf,nil,nil))
		{
			DateStamp(&dt->dat_Stamp);
			DateToStr(dt);
		}

		if (nil)
			Close(nil);
	}
	while (!OK && (OK=Requester(NoTimePrefs,Retry,Ignore)));

	return OK;
}

// Set environment variable and asve to ENVARC:

BOOL SetVariable(BYTE Var[],BYTE Val[])
{
	BPTR file;
	BYTE fname[120];
	LONG l=strlen(Val);
	BOOL OK;

	strcpy(fname,"ENVARC:");
	strcpy(&fname[7],Var);
	if (file=Open(fname,MODE_NEWFILE))
	{
		if (Write(file,Val,l)==l)
			OK=(SetVar(Var,Val,strlen(Val),LV_VAR|GVF_GLOBAL_ONLY)==DOSTRUE);
		Close(file);
	}
	else
		OK=FALSE;

	return OK;
}


// Free resources. Note: Don't call with err!=NULL when dos.library is not open.

VOID cleanup(BYTE err[])
{
	if (err)
		Write(Output(),err,strlen(err));
	if (IntuitionBase)
		CloseLibrary((struct Library *)IntuitionBase);
	if (DOSBase)
		CloseLibrary((struct Library *)DOSBase);
}
