/************************************************
 *												*
 *     		Floating clock version 2.1			*
 *												*
 *					   BY						*
 *												*
 *				Paul Court (Quinn)				*
 *					16/06/98					*
 *												*
 ************************************************/

#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <devices/timer.h>
#include <intuition/intuition.h>
#include <dos/dos.h>

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

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>

#include "digits.h"

#define WIDTH 100
#define HEIGHT 36

struct IntuitionBase* IntuitionBase;	/* Pointer to intuition base */
struct Window* clock_win;				/* Pointer to my window structure. */
struct BitMap my_bitmap;
struct MsgPort* TimerMP;
struct Screen* wbscr;
struct timerequest* TimerIO;
extern struct Border hfiller_border;
extern struct Border vfiller_border;
extern struct Border dfiller_border;

/* Window definition! */
struct NewWindow new_clock_win=
{
	10,					/* Left Edge	x position of window. */
	420,				/* Top Edge		y position of window. */
	WIDTH,				/* Width. */
	HEIGHT,				/* Height. */
	0,					/* DetailPen 	colour register 0. */
	1,					/* BlockPen		colour register 1. */
	IDCMP_RAWKEY|
	IDCMP_REFRESHWINDOW|
	IDCMP_MOUSEBUTTONS,	/* IDCMP flags. Just to check when the clock is clicked on*/
	SIMPLE_REFRESH|		/* Flags       Intuition should refresh the window. */
	BORDERLESS,
	NULL,       	   	/* FirstGadget No Custom Gadgets. */
	NULL,          		/* CheckMark   Use Intuition's default CheckMark (v). */
	NULL,				/* Title       Title of the window. */
	NULL,       	   	/* Screen      Connected to the Workbench Screen. */
	NULL,          		/* BitMap      No Custom BitMap. */
	0,    	         	/* MinWidth    We do not need to care about these */
	0,      	       	/* MinHeight   since we have not supplied the window */
	0,          	   	/* MaxWidth    with a Sizing Gadget. */
	0,             		/* MaxHeight */
	WBENCHSCREEN   		/* Type        Connected to the Workbench Screen. */
};

void handleIDCMP(struct Window*);
void ReGrab(void);
void CleanUp(void);
void DrawTime(void);

/********************
 * Global Variables *
 ********************/
int a=1,b=1,c=1,d=1, dcheck=11;
int going = TRUE;
int left, top, loop;
ULONG timerSig, winSig, gotSig;
ULONG red=255, green=0, blue=0;

/*UBYTE mypen;
	extern struct Border hfiller_border;*/

main(int argc, char *argv[])
{
	LONG error;
	ULONG hrs,secs,mins;

	/**********************************
	 * Set the position of the window *
	 **********************************/
	if(argc>2)
	{
		new_clock_win.LeftEdge = atoi(argv[1]);
		new_clock_win.TopEdge = atoi(argv[2]);
		left = new_clock_win.LeftEdge;
		top = new_clock_win.TopEdge;
	}
	/*****************************
	 * Or print some usage info. *
	 *****************************/
	else
	{
		printf("\nFloating Clock Version 2.1");
		printf("\nBy: Paul Court\n");
		printf("\nUsage: FCLOCK <LeftEdge> <TopEdge> [R] [G] [B] (0-255)\n\n");
		exit(0);
	}

	if(argc>5)
	{
		red = atoi(argv[3]);
		green = atoi(argv[4]);
		blue = atoi(argv[5]);
	}

/******************************
 * Open the intuition library *
 ******************************/
IntuitionBase = (struct IntuitionBase *)
		OpenLibrary( "intuition.library", 0 );

if( IntuitionBase != NULL )
{
	/******************************************
	 * Get a pointer to the workbench screen. *
	 ******************************************/
	wbscr = LockPubScreen( NULL );
	UnlockPubScreen( NULL, wbscr );

	hfiller_border.FrontPen = ObtainBestPen(wbscr->ViewPort.ColorMap, red<<24, green<<24, blue<<24, NULL);
	vfiller_border.FrontPen = hfiller_border.FrontPen;
	dfiller_border.FrontPen = hfiller_border.FrontPen;

	InitBitMap( &my_bitmap, wbscr->BitMap.Depth, WIDTH, HEIGHT );
	
	for( loop=0; loop < wbscr->BitMap.Depth; loop++ )
	{
		my_bitmap.Planes[loop] = AllocRaster( WIDTH, HEIGHT );
		if( my_bitmap.Planes[loop] == NULL)
		{
			CleanUp(); /* Could not allocate all the memory required */
		}
		BltClear( my_bitmap.Planes[loop], RASSIZE( WIDTH, HEIGHT ), 0);
	}
	BltBitMap( wbscr->RastPort.BitMap, left, top, &my_bitmap, 0, 0, WIDTH, HEIGHT, 0xc0, 0xFF, NULL);

	/***************************************
	 * We will now try to open the window. *
	 ***************************************/
	clock_win = OpenWindow( &new_clock_win ); 
	if( clock_win != NULL )
	{
		/*****************************
		 * Set up the timers message *
		 * port and the timerIO      *
		 *****************************/
		if( TimerMP = CreatePort(0,0) )
		{
			if( TimerIO = (struct timerequest *)
				      CreateExtIO(TimerMP, sizeof(struct timerequest)) )
			{
				/******************************
				 * Opening the timer device   *
				 * might be useful since this *
				 * is a clock!!				  *
				 ******************************/
				if (!(error=OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)TimerIO, 0L)))
				{
					while(going)
					{
						/****************************************
						 * Send request to get the system time. *
						 ****************************************/
						TimerIO->tr_node.io_Command = TR_GETSYSTIME;
						DoIO( (struct IORequest *) TimerIO);
		
						/********************
						 * Get the results. *
						 ********************/
						secs=TimerIO->tr_time.tv_secs;

						/*****************************
						 * Compute days, hours, etc. *
						 *****************************/
						if(! secs == 0)
						{
							mins=secs/60;
							hrs=mins/60;
							secs=secs%60;
							mins=mins%60;
							hrs=hrs%24;
						}

						/******************************
						 * Set the individual digits. *
						 ******************************/
						a=hrs/10;
						b=hrs%10;
						c=mins/10;
						d=mins%10;
						

						/***********************************
						 * A simple check so the window    *
						 * is only Redrawn if the time has *
						 * changed.						   *
						 ***********************************/
						if(d != dcheck)
						{
							BltBitMapRastPort(&my_bitmap, 0, 0, clock_win->RPort, 0, 0, 140, 50, 0xc0);
							dcheck = d;
							DrawTime();
						}

						/**************************
						 * Send a time request to *
						 * wait a few seconds so  *
						 * that we don't hog the  *
						 * CPU... ;)			  *
						 **************************/	
						TimerIO->tr_node.io_Command = TR_ADDREQUEST;
						TimerIO->tr_time.tv_secs = 5;
						SendIO( (struct IORequest *)TimerIO);
						handleIDCMP(clock_win);
		    		}

				/**************
				 * Tidy up... *
				 **************/
					if( !(CheckIO( (struct IORequest *) TimerIO)) )
						AbortIO( (struct IORequest *) TimerIO );
				CloseDevice( (struct IORequest *) TimerIO);
				}
			DeleteExtIO( (struct IORequest *)TimerIO);
			}
		DeletePort(TimerMP);
		}
	CloseWindow(clock_win);
	}
	/*******************************
	 * Free the bitmap information *
	 *******************************/
	for( loop=0; loop < wbscr->BitMap.Depth; loop++ )
	{
		if( my_bitmap.Planes[loop] )
			FreeRaster( my_bitmap.Planes[loop], WIDTH, HEIGHT );
	}
	ReleasePen(wbscr->ViewPort.ColorMap,hfiller_border.FrontPen);
CloseLibrary( (struct Library *)IntuitionBase );
}
/* THE END */
}

void DrawTime()
{
	/*************************************
	 * Use the functions from digits.h to *
	 * draw our digital time display     *
	 *************************************/
	switch (a)
	{
		case 1 : number_one(AX, clock_win); break;
		case 2 : number_two(AX, clock_win); break;
		case 3 : number_three(AX, clock_win); break;
		case 4 : number_four(AX, clock_win); break;
		case 5 : number_five(AX, clock_win); break;
		case 6 : number_six(AX, clock_win); break;
		case 7 : number_seven(AX, clock_win); break;
		case 8 : number_eight(AX, clock_win); break;
		case 9 : number_nine(AX, clock_win); break;
		case 0 : number_zero(AX, clock_win); break;
	}
	switch (b)
	{
		case 1 : number_one(BX, clock_win); break;
		case 2 : number_two(BX, clock_win); break;
		case 3 : number_three(BX, clock_win); break;
		case 4 : number_four(BX, clock_win); break;
		case 5 : number_five(BX, clock_win); break;
		case 6 : number_six(BX, clock_win); break;
		case 7 : number_seven(BX, clock_win); break;
		case 8 : number_eight(BX, clock_win); break;
		case 9 : number_nine(BX, clock_win); break;
		case 0 : number_zero(BX, clock_win); break;
	}
	dots(clock_win);
	switch (c)
	{
		case 1 : number_one(CX, clock_win); break;
		case 2 : number_two(CX, clock_win); break;
		case 3 : number_three(CX, clock_win); break;
		case 4 : number_four(CX, clock_win); break;
		case 5 : number_five(CX, clock_win); break;
		case 6 : number_six(CX, clock_win); break;
		case 7 : number_seven(CX, clock_win); break;
		case 8 : number_eight(CX, clock_win); break;
		case 9 : number_nine(CX, clock_win); break;
		case 0 : number_zero(CX, clock_win); break;
	}
	switch (d)
	{
		case 1 : number_one(DX, clock_win); break;
		case 2 : number_two(DX, clock_win); break;
		case 3 : number_three(DX, clock_win); break;
		case 4 : number_four(DX, clock_win); break;
		case 5 : number_five(DX, clock_win); break;
		case 6 : number_six(DX, clock_win); break;
		case 7 : number_seven(DX, clock_win); break;
		case 8 : number_eight(DX, clock_win); break;
		case 9 : number_nine(DX, clock_win); break;
		case 0 : number_zero(DX, clock_win); break;
	}
}

void handleIDCMP(struct Window* win)
{
	struct IntuiMessage* intuimsg;

	/**********************************
	 * Set up the signals to wait for *
	 **********************************/
	winSig = 1 << win->UserPort->mp_SigBit;
	timerSig = 1 << TimerMP->mp_SigBit;

	/*************************
	 * Wait for some signals *
	 *************************/
	gotSig = Wait(winSig | timerSig | SIGBREAKF_CTRL_C);

	/*****************************************
	 * End program if it was CTRL-C pressed. *
	 *****************************************/
	if (gotSig & SIGBREAKF_CTRL_C)
	{
		going = FALSE;
		SetSignal(0, SIGBREAKF_CTRL_C);
	}

	/****************************
	 * Or regrab the background *
	 * if it was a mouse click  *
	 * or an intuition redraw   *
	 * signal.					*
	 ****************************/
	if (gotSig & winSig)
	{
		intuimsg = (struct IntuiMessage*) GetMsg(win->UserPort);
		if( intuimsg != NULL)
		{
			if( intuimsg->Class == IDCMP_MOUSEBUTTONS )
			{
				ReplyMsg( (struct Message *) intuimsg);
				ReGrab();
				DrawTime();
			}
			
			if( intuimsg->Class == IDCMP_REFRESHWINDOW )
			{
				WindowToFront( clock_win );
				ReplyMsg( (struct Message *) intuimsg);
				ReGrab();
				DrawTime();
			}
		}
	}

	
}

void ReGrab()
{
	/************************
	 * Close the window and *
	 * regrab the backdrop  *
	 * before reopening the *
	 * window.				*
	 ************************/
	if( clock_win != NULL )
		CloseWindow( clock_win );

	BltBitMap( wbscr->RastPort.BitMap, left, top, &my_bitmap, 0, 0, WIDTH, HEIGHT, 0xc0, 0xFF, NULL);

	clock_win = OpenWindow( &new_clock_win ); 
	if( clock_win != NULL )
	{
		BltBitMapRastPort(&my_bitmap, 0, 0, clock_win->RPort, 0, 0, 140, 50, 0xc0);
	}
	else CleanUp();
}

void CleanUp()
{
	/**************************
	 * Check the status of,   *
	 * and close if neccasary *
	 * any resources used.	  *
	 **************************/
	int loop;

	if( !(CheckIO( (struct IORequest *) TimerIO)) )
		AbortIO( (struct IORequest *) TimerIO );

	if ( TimerIO != NULL )
		CloseDevice( (struct IORequest *) TimerIO);

	if( TimerIO != NULL )
		DeleteExtIO( (struct IORequest *) TimerIO );
	
	if( TimerMP != NULL )
		DeletePort( TimerMP );
	
	if( clock_win != NULL )
		CloseWindow( clock_win );
	
	for( loop=0; loop < wbscr->BitMap.Depth; loop++ )
	{
		if( my_bitmap.Planes[loop] )
			FreeRaster( my_bitmap.Planes[loop], WIDTH, HEIGHT );
	}
	ReleasePen(wbscr->ViewPort.ColorMap,hfiller_border.FrontPen);
	if( IntuitionBase != NULL )
		CloseLibrary( (struct Library *) IntuitionBase );
	going = FALSE;
}
