
/*	AmyInfo v1.1 by Digital Design, Inc.

	Author: Juha Tuominen

	Released: 26-Jun-91		*/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <libraries/dos.h>
#include <devices/timer.h>
#include <intuition/intuitionbase.h>
#include <graphics/rastport.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <graphics/text.h>
#include <proto/all.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define FONTSIZE 8

void CXBRK(void) { exit(1); }

BOOL	timeropen=FALSE;
BOOL	keepgoing=TRUE;
BOOL	time_requested=FALSE;
char	*months[]={"","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
char	date[16]="               ";
char	tempdays[8]="       ";
char	timetemp[8]="       ";
int		upsecs=0,upmins=0,uphours=0,updays=0;
ULONG	maxchip, maxfast, freechip=0, freefast=0;
long	chipscale=0, fastscale=0;

extern	struct ExecBase	*SysBase;
struct	IntuitionBase *IntuitionBase=NULL;
struct	Window *window=NULL;
struct	GfxBase *GfxBase=NULL;
struct	MsgPort *timerport=NULL;
struct	timerequest *timermsg=NULL;
struct	IntuiText abouttext[];
struct	IntuiText proceed;
struct	NewWindow mywindow = 
{
	100,
	100,
	310,
	76,
	0,1,
	CLOSEWINDOW | MOUSEBUTTONS,
	SMART_REFRESH | WINDOWDRAG | WINDOWCLOSE | WINDOWDEPTH | RMBTRAP,
	NULL,
	NULL,
	"AmyInfo",
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	WBENCHSCREEN

};

struct TextAttr aifont[1] =
{
	{(UBYTE *)"topaz.font",8,FS_NORMAL ,FPF_ROMFONT},
};

struct IntuiText abouttext[4] =
{
	{2,1,JAM1,8, 4,(struct TextAttr *)&aifont[0],(UBYTE *)"AmyInfo v1.1",(struct IntuiText *)&abouttext[1]},
	{2,1,JAM1,8,14,(struct TextAttr *)&aifont[0],(UBYTE *)"by Juha Tuominen",(struct IntuiText *)&abouttext[2]},
	{2,1,JAM1,8,22,(struct TextAttr *)&aifont[0],(UBYTE *)"Copyright © 1991",(struct IntuiText *)&abouttext[3]},
	{2,1,JAM1,8,30,(struct TextAttr *)&aifont[0],(UBYTE *)"Digital Design, Inc.",(struct IntuiText *)NULL},
};

struct IntuiText proceed =
{
	2,1,JAM1,5,3,(struct TextAttr *)&aifont[0],(UBYTE *)"Continue",(struct IntuiText *)NULL
};



void cleanexit(int error);
void openthings(void);
void addtimerequest(long secs, long micros);
void currenttime(void);
void changefont(void);
void initgraphics(void);
void printfinetext(char *text,int x,int y,int color);
ULONG maxmemsize(long memtype);

void cleanexit(int error)
{
	if(timeropen)
	{
		if(time_requested)
		{
			AbortIO((struct IORequest *)timermsg);
			WaitIO((struct IORequest *)timermsg);
		}
		CloseDevice((struct IORequest *)timermsg);
	}
	if(timermsg) DeleteExtIO((struct IORequest *)timermsg);
	if(timerport) DeletePort(timerport);
	if(window) CloseWindow(window);
	if(GfxBase) CloseLibrary(GfxBase);
	if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	exit(error);
}


void openthings(void)
{
	if (!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",33L)))
	{
		printf("\aError opening GfxBase\n");
		cleanexit(30);
	}
	if (!(IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",33L)))
	{
		printf("\aError opening IntuitionBase\n");
		cleanexit(30);
	}
	if(!(timerport=CreatePort(0,0)))
	{
		printf("\aError creating timerport\n");
		cleanexit(22);
	}
	if(!(timermsg=(struct timerequest *) CreateExtIO(timerport, sizeof(struct timerequest))))
	{
		printf("\aError creating timerequest\n");
		cleanexit(22);
	}
	if(OpenDevice("timer.device", UNIT_VBLANK, ((struct IORequest *) timermsg), 0))
	{
		printf("\aError opening timer.device\n");
		cleanexit(22);
	}
	timeropen=TRUE;
	if(!(window=OpenWindow(&mywindow)))
	{
		printf("\aError opening window\n");
		cleanexit(27);
	}

	maxchip=maxmemsize(MEMF_CHIP);
	maxfast=maxmemsize(MEMF_FAST);

	/*	Because we run this part only once we just have to assume that user 
		does not add memory cartiges while this program is running :) */

	chipscale=maxchip/142;
	fastscale=maxfast/142;
}


void addtimerequest(long secs, long micros)
{
	time_requested=TRUE;
	timermsg->tr_node.io_Command=TR_ADDREQUEST;
	timermsg->tr_time.tv_secs=secs;
	timermsg->tr_time.tv_micro=micros;
	SendIO((struct IORequest *)timermsg);
}


void currenttime(void)
{
	long	n;
	int		m,d,y,hours,mins,secs;
	char	temp[16];
	long	v[3];
	struct	DateStamp ds;

	DateStamp((struct DateStamp *)v);
	n=v[0]-2251;
	y=(4*n+3)/1461;
	n-=1461*(long)y/4;
	y+=84;
	m=(5*n+2)/153;
	d=n-(153*m+2)/5+1;
	m+=3;
	if (m>12)
	{
		y++;
		m-=12;
	}

/*	Date stamp conversation routine from Robert A. Peck's book 
	'Programming Guide to the Amiga. Routine by Tom Rokicki. */

	sprintf(temp,"%02d-%3s-%02d",d,months[m],y);
	if(strcmp(temp,date))
	{
		printfinetext(temp,70,38,2);
		strcpy(date,temp);
	}

	DateStamp(&ds);
	hours=ds.ds_Minute/60;
	mins=ds.ds_Minute%60;
	secs=ds.ds_Tick/50;	

	sprintf(temp,"%02d:%02d:%02d",hours,mins,secs);
	if(strcmp(timetemp,temp))
	{
		strcpy(timetemp,temp);
		printfinetext(temp,70,25,2);
		if(++upsecs>59)
		{
			upsecs=0;
			if(++upmins>59)
			{
				upmins=0;
				if(++uphours>23)
				{
					uphours=0;
					updays++;
				}
			}
		}		

		sprintf(temp,"%02d:%02d:%02d",uphours,upmins,upsecs);
		printfinetext(temp,230,25,2);
	}

	sprintf(temp,"%04d",updays); /* I think 9999 days is enough for most of people :) */
	if(strcmp(temp,tempdays))
	{
		printfinetext(temp,230,38,2);
		strcpy(tempdays,temp);
	}
}

void changefont(void)
{
	struct	TextAttr	textattr;
	struct	TextFont	*textfont;

	textattr.ta_Name="topaz.font";
	textattr.ta_YSize=FONTSIZE;
	textattr.ta_Style=FS_NORMAL;
	textattr.ta_Flags=FPF_DESIGNED | FPF_ROMFONT;

	if(textfont=OpenFont(&textattr))
		SetFont(window->RPort,textfont);
	else
	{
		printf("Cannot open topaz 8!\n");
		cleanexit(10);
	}
}

void initgraphics(void)
{
	printfinetext("Time:",10,25,3);
	printfinetext("Date:",10,38,3);
	printfinetext("UpTime:",160,25,3);
	printfinetext("Days:",160,38,3);
	printfinetext("Chip:         K",10,51,3);
	printfinetext("Fast:          K",160,51,3);

	SetDrMd(window->RPort,JAM1);
	SetAPen(window->RPort,1);
	Move(window->RPort,7,69);
	Draw(window->RPort,7,59);
	Draw(window->RPort,148,59);
	Move(window->RPort,152,69);
	Draw(window->RPort,152,59);
	Draw(window->RPort,303,59);
	SetAPen(window->RPort,2);
	Draw(window->RPort,303,69);
	Draw(window->RPort,153,69);
	Move(window->RPort,148,60);
	Draw(window->RPort,148,69);
	Draw(window->RPort,8,69);
}


ULONG maxmemsize(long memtype)
{
	ULONG blocksize=0;
	struct MemHeader *MemHeader;
	struct ExecBase *ExecBase = SysBase;

	Forbid();
		for(MemHeader=(struct MemHeader *)ExecBase->MemList.lh_Head;MemHeader->mh_Node.ln_Succ;MemHeader=(struct MemHeader *)MemHeader->mh_Node.ln_Succ)
		{
			if(MemHeader->mh_Attributes&memtype)
				blocksize+=((ULONG)MemHeader->mh_Upper-(ULONG)MemHeader->mh_Lower);
		}
	Permit();

	return(blocksize);

	/* MaxMemSize() by Louis A. Mamakos. */
}

void updatememorybar(void)
{
	ULONG currentchip, currentfast;
	long tempx;
	char temp[16];

	currentchip=AvailMem(MEMF_CHIP);
	currentfast=AvailMem(MEMF_FAST);


	if(currentchip!=freechip)
	{
		sprintf(temp,"%05d",currentchip/1024);
		printfinetext(temp,70,51,2);

		tempx=currentchip/chipscale;
		SetDrMd(window->RPort,JAM1);
		if(freechip>currentchip)
		{
			SetAPen(window->RPort,0);
			RectFill(window->RPort,tempx+10,61,freechip/chipscale+11,67);
		}
		SetAPen(window->RPort,3);
		RectFill(window->RPort,10,62,tempx+10,66);
		Move(window->RPort,tempx+11,61);
		SetAPen(window->RPort,1);
		Draw(window->RPort,tempx+11,67);
		Draw(window->RPort,9,67);
		SetAPen(window->RPort,2);
		Draw(window->RPort,9,61);
		Draw(window->RPort,tempx+11,61);
		freechip=currentchip;				
	}

	if(currentfast!=freefast)
	{
		sprintf(temp,"%05d",currentfast/1024);
		printfinetext(temp,230,51,2);

		tempx=currentfast/fastscale;
		SetDrMd(window->RPort,JAM1);
		if(freefast>currentfast)
		{
			SetAPen(window->RPort,0);
			RectFill(window->RPort,tempx+155,61,freefast/fastscale+156,67);
		}
		SetAPen(window->RPort,3);
		RectFill(window->RPort,155,62,tempx+155,66);
		Move(window->RPort,tempx+156,61);
		SetAPen(window->RPort,1);
		Draw(window->RPort,tempx+156,67);
		Draw(window->RPort,154,67);
		SetAPen(window->RPort,2);
		Draw(window->RPort,154,61);
		Draw(window->RPort,tempx+156,61);
		freefast=currentfast;				
	}
}

void printfinetext(char *text,int x, int y, int color)
{
	int	tempy,
		tempx,
		len,
		x1,
		y1;
	struct RastPort *rastport=window->RPort;

	SetDrMd(rastport,JAM2);
	SetAPen(rastport,0);
	SetBPen(rastport,0);
	Move(rastport,x,y+2-FONTSIZE);
	len=strlen(text);
	tempy=y+2-FONTSIZE;
	tempx=x+len*8;
	x1=x+1;
	y1=y+1;

	WaitTOF();

	/* 	Uh, well .. I can't discover any better way to avoid the flickering.
		Don't place AmyInfo too high on your WB-screen :)
		It does not make any flickering on my big A, but I've got A2620..
		The following part will take ~5-> lines to be executed */

	Draw(rastport,tempx,tempy);
	SetAPen(rastport,1);
	Move(rastport,x1,y1);
	Text(rastport,text,len);
	SetDrMd(rastport,JAM1);
	SetAPen(rastport,color);
	Move(rastport,x,y);
	Text(rastport,text,len);
}

void main(int argc, char *argv[])
{
	ULONG	timersignal, 
			idcmpsignal, 
			signals, 
			class;
	UWORD	code, 
			qualifier;
	struct	IntuiMessage *msg=NULL;

	if(argc==2 && (!strncmp(argv[1],"?",1) || !strncmp(argv[1],"-?",2)))
	{
		printf("\nUsage: AmyInfo <LEFT> <TOP>\n");
		printf("AmyInfo v1.1  Copyright © 1991 Juha Tuominen / Digital Design, Inc.\n\n");
	}
	else
	{
		if(argc==3)
		{
			mywindow.LeftEdge=atoi(argv[1]);
			mywindow.TopEdge=atoi(argv[2]);
		}
		
		openthings();
		changefont();
		initgraphics();

		timersignal = 1L << timerport->mp_SigBit;
		idcmpsignal = 1L << window->UserPort->mp_SigBit;
		addtimerequest(0,1);

		while(keepgoing)
		{
			signals = Wait(timersignal | idcmpsignal);
			if(signals & timersignal)
			{
				GetMsg(timerport);
				addtimerequest(1,0);
				currenttime();
				updatememorybar();
			}
			if(signals & idcmpsignal)
			{
				while(msg=(struct IntuiMessage *)GetMsg(window->UserPort))
				{

					class=msg->Class;
					code=msg->Code;
					qualifier=msg->Qualifier;
					ReplyMsg((struct Message *) msg);

					switch(class)
					{
						case CLOSEWINDOW:
							keepgoing=FALSE;
							break;
						case MOUSEBUTTONS:
							if(code==MENUDOWN)
								AutoRequest(NULL,&abouttext[0],NULL,&proceed,NULL,NULL,272,128);
			
					}
				}
			}
		}
	}
	cleanexit(0);
}
