#include <intuition/intuitionbase.h>
#include <exec/nodes.h>
#include <exec/tasks.h>
#include <libraries/dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <exec/libraries.h>
#include <dos/dos.h>

struct Task *task,*met;
char *taskname = "CPU_TASK";

struct timerequest *tr;
struct MsgPort *tport;
struct Message *msg;
struct Window *CustWindow;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *IconBase;
struct Library *CxBase;

#define rp CustWindow->RPort

struct NewWindow BlankWindow=
{
	0,0,130,50,1,0,
	CLOSEWINDOW | NEWSIZE,
	WINDOWSIZING | ACTIVATE | GIMMEZEROZERO | SMART_REFRESH | WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH,
	0,0,
	"CPULoad",
	0,0,70,20,0,0,
	PUBLICSCREEN
};

unsigned int maximum,aktuell,cnt,quit=0;

/*	System structure name	*/

#define UTILITY_NAME "CPU_PROC"

/*	allocate the timer	*/

struct timerequest *create_timer(ULONG unit)
{
	LONG error;
	struct MsgPort *timerport;
	struct timerequest *timermsg;

	if ((timerport=(struct MsgPort *)CreatePort(0,0))==NULL) exit(1);
	if ((timermsg=(struct timerequest *)CreateExtIO(timerport,sizeof(struct timerequest)))==NULL) exit(1);
	if ((error=OpenDevice(TIMERNAME,unit,(struct IORequest *)timermsg,0))!=0) exit(1);
	return(timermsg);
}
	
/*	Läuft als Task	*/

druck()
{
	struct IntuiMessage *message;	/*	Windowclose	*/
	struct IntuiMessage *GetMsg();
	struct timeval updateval;	/*	1/10 Sekunde	*/
	char name[256];			/*	PubScreen	*/
	int n;
	unsigned int sum;		/*	Summand der freien Zyklen	*/
	unsigned int height,width,right,bottom;
	unsigned int int_pix_per_load;		/*	Skalierung	*/
	int whitepen,blackpen;
	struct Screen *PubScreen;
	short pen,minpen,maxpen;
	unsigned short RGB;
	int class;

	geta4();

/*	init timer	*/

	tr=create_timer(UNIT_MICROHZ);

	updateval.tv_secs=0;
	updateval.tv_micro=100000;	/*	1/10 secs	*/

	IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0);
	GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0);

	GetDefaultPubScreen(name);
	PubScreen=(struct Screen *)LockPubScreen(name);
	UnlockPubScreen(0L,PubScreen);

	BlankWindow.MaxHeight=PubScreen->Height;
	BlankWindow.MaxWidth=PubScreen->Width;

	CustWindow=(struct Window *)OpenWindow(&BlankWindow);

/*	Farbgebung aus der ColorMap bestimmen (SunClock-Methode)	*/

	whitepen=1;
	blackpen=0;
	maxpen=0x000;
	minpen=0xfff;

	for (n=0; n<1<<PubScreen->BitMap.Depth; n++)
	{
		RGB=GetRGB4(PubScreen->ViewPort.ColorMap,n);

		pen=(RGB & 0x00f) + ((RGB & 0x0f0) >> 4) + ((RGB & 0xf00) >> 8);
		if (pen < minpen)
		{
			minpen = pen;
			blackpen = n;
		}
		if (pen > maxpen)
		{
			maxpen = pen;
			whitepen = n;
		}
	}

	height=CustWindow->GZZHeight;
	width=CustWindow->GZZWidth;
	right=width-1;
	bottom=height-1;

	SetAPen(rp,whitepen);
	RectFill(rp,0,0,right,bottom);

/*	FOREVER	*/

	while (1)
	{
		sum=0;

		for (n=0; n<10; n++)
		{
			cnt=0;
			tr->tr_node.io_Command=TR_ADDREQUEST;
			tr->tr_time=updateval;
			DoIO((struct IORequest *)tr);
			aktuell=cnt;
			sum+=aktuell;
		}

		sum/=10;	/*	Average	*/

/*	Verschiebe Bild nach links	*/

		height=CustWindow->GZZHeight;
		width=CustWindow->GZZWidth;
		right=width-1;
		bottom=height-1;

		int_pix_per_load=(height<<16)/maximum;

		ScrollRaster(rp,1,0,0,0,width,height);

/*	Jede Sekunde Ausdruck	*/

		SetAPen(rp,blackpen);
		Move(rp,right,bottom);

		Draw(rp,right,(sum*int_pix_per_load)>>16);
		if (rp->cp_y)
		{
			SetAPen(rp,whitepen);
			Draw(rp,right,0);
		}

		while (message=GetMsg(CustWindow->UserPort))
		{
			class=message->Class;
			ReplyMsg(message);

			if (class==CLOSEWINDOW)
			{
				Signal(met,SIGBREAKF_CTRL_D);
			}
			else if (class==NEWSIZE)
			{
				SetAPen(rp,whitepen);
				RectFill(rp,0,0,right,bottom);
			}	
		}
	}
}

/* Run this as a process. It aborts when it detects a CTRL_D signal */

main(int argc, char **argv)
{
	extern struct Task *FindTask(char *);
	WORD oldpri;
	char *oldname;
	int i;
	UBYTE **ttypes;

/*	switch off CTRL_C handling	*/

	if (met=FindTask(UTILITY_NAME)) exit(1);

	if (IconBase=(struct Library *)OpenLibrary("icon.library",37L))
	{
		if (CxBase=(struct Library *)OpenLibrary("icon.library",37L))
		{
			if ((ttypes=ArgArrayInit(argc,argv)))
			{
				BlankWindow.LeftEdge=ArgInt(ttypes,"XPOS",0);
				BlankWindow.TopEdge=ArgInt(ttypes,"YPOS",0);
				BlankWindow.Width=ArgInt(ttypes,"XSIZE",130);
				BlankWindow.Height=ArgInt(ttypes,"YSIZE",50);
				CloseLibrary(CxBase);
			}
		}
		CloseLibrary(IconBase);
	}

	met=FindTask(NULL);			/*	Finde mich selber	*/
	oldpri=met->tc_Node.ln_Pri;		/*	Save old priority	*/
	oldname=met->tc_Node.ln_Name;		/*	Save old name	*/

	met->tc_Node.ln_Name=UTILITY_NAME;
	met->tc_Node.ln_Pri=126;	/*	Raise priority for calibration	*/

	maximum=1000000;

	task=CreateTask(taskname,127,druck,4096);

	aktuell=0;
	while(!aktuell) cnt++;
	maximum=aktuell;

	met->tc_Node.ln_Pri=-127;

	while ((met->tc_SigRecvd & SIGBREAKF_CTRL_D)==0) cnt++;

	met->tc_Node.ln_Pri=oldpri;	/*	Change priority back	*/
	met->tc_Node.ln_Name=oldname;	/*	Change name back	*/

	Forbid();
	DeleteTask(task);
	Permit();

	CloseWindow(CustWindow);
	CloseLibrary(IntuitionBase);
	CloseLibrary(GfxBase);

	exit(1);
}
