/************************************************
 *												*
 *     		Floating clock version 1.0			*
 *												*
 *					   BY						*
 *												*
 *				   Paul Court					*
 *					30/04/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 140
#define HEIGHT 50

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;


/* 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_MOUSEBUTTONS,	/* IDCMP flags. Just to check when the clock is clicked on*/
	SMART_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 CleanUp(void);

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

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

	/**********************************
	 * Set the position of the window *
	 **********************************/
	if(argc>1)
	{
		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 1.0b");
		printf("\nBy: Paul Court\n");
		printf("\nUsage: FCLOCK <LeftEdge> <TopEdge>\n\n");
		exit(0);
	}

/******************************
 * 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 );

	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. *
						 ********************/
						mics=TimerIO->tr_time.tv_micro;
						secs=TimerIO->tr_time.tv_secs;

						/*****************************
						 * Compute days, hours, etc. *
						 *****************************/
						mins=secs/60;
						hrs=mins/60;
						days=hrs/24;
						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;
						
						/*************************************
						 * Use the functins 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;
						}

						} /* End of check */

						/**************************
						 * 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 );
	}
CloseLibrary( (struct Library *)IntuitionBase );
}
/* THE END */
}

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. *
	 ****************************/
	if (gotSig & winSig)
	{
		intuimsg = (struct IntuiMessage*) GetMsg(win->UserPort);
		if( intuimsg != NULL)
		{
			if( intuimsg->Class == IDCMP_MOUSEBUTTONS )
			{
				ReplyMsg( (struct Message *) intuimsg);
				
				dcheck = 11;

				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()
{
	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 );
	}
	
	if( IntuitionBase != NULL )
		CloseLibrary( (struct Library *) IntuitionBase );
	going = FALSE;
}
