// Die Funktionen DrawTime() und v.a RedrawTime() sind sehr ineffizient
// und muessen unbedingt verbessert werden. Das Problem war, dass (als
// Folge von CpuBlit ?) RectFill() die jeweils neu gezeichneten Zahlen
// gleich wieder loeschte, obwohl der Aufruf vor Draw() erfolgte.


#include <graphics/gfx.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <clib/graphics_protos.h>
#include <clib/dos_protos.h>
#include <reqtools/reqtools.h>
#include <time.h>

#include "Main.h"
#include "Window.h"
#include "Draw.h"
#include "MenuDefs.h"

#define ALARM_X 65
#define ALARM_Y 19
#define TIMER_X 73
#define TIMER_Y 17

void TurnAlarmOff(struct AppPrefs *prefs);

// STATICS ------------------------------------------------------------------

int realtime;

BOOL Number[] =
{
	1, 1, 1, 0, 1, 1, 1,   // 0
	0, 0, 1, 0, 0, 1, 0,   // 1
	1, 0, 1, 1, 1, 0, 1,   // 2
	1, 0, 1, 1, 0, 1, 1,   // 3
	0, 1, 1, 1, 0, 1, 0,   // 4
	1, 1, 0, 1, 0, 1, 1,   // 5
	1, 1, 0, 1, 1, 1, 1,   // 6
	1, 0, 1, 0, 0, 1, 0,   // 7
	1, 1, 1, 1, 1, 1, 1,   // 8
	1, 1, 1, 1, 0, 1, 1,   // 9
};

SHORT BigNumber[] =
{
	1,  0,    7,  0,   6,  1,   2,  1,  //  -
	0,  1,    0,  7,   1,  6,   1,  2,  // |
	8,  1,    8,  7,   7,  6,   7,  2,  //   |
	2,  8,    6,  8,   6,  9,   2,  9,  //  -
	0,  9,    0, 15,   1, 14,   1, 10,  // |
	8,  9,    8, 15,   7, 14,   7, 10,  //   |
	2, 15,    6, 15,   7, 16,   1, 16   //  -
};

SHORT SmallNumber[] =
{
	1,  0,   4,  0,  //  -
	0,  1,   0,  4,  // |
	5,  1,   5,  4,  //   |
	1,  5,   4,  5,  //  -
	0,  6,   0,  9,  // |
	5,  6,   5,  9,  //   |
	1, 10,   4, 10,  //  -

};


SHORT Coords[] =
{
	6,  4,  /* Std. */
	19, 4,
	38, 4,  /* Min. */
	51, 4,
	64, 4,  /* Sec. */
	72, 4,
	32, 8,  /*  :   */
	32, 15,
	8, 25,  /* Day  */
	16, 25,
	27, 25, /* Mon. */
	35, 25,
	46, 25, /* Year */
	54, 25,
	62, 25,
	70, 25,
	24, 35, /* Dots */
	43, 35
};


void DrawTime(struct Window *win, struct AppPrefs *prefs)
{
	int offx = win->BorderLeft;
	int offy = win->BorderTop;
	int width = DClockWidth;
	int height = DClockHeight;
	int i, j, k, digits = 0, hour;
	int vals[14];
	struct Time myTime;
	struct tm *TM = GetTime( &myTime, prefs );

	vals[0] = myTime.hour1; vals[1] = myTime.hour2;
	vals[2] = myTime.min1; vals[3] = myTime.min2;
	vals[4] = myTime.sec1; vals[5] = myTime.sec2;

	if (! prefs->twentyfour)
	{
		hour = vals[0] * 10 + vals[1];
		if (hour > 12)
			hour -= 12;
		else if (hour == 0)
			hour = 12;
		vals[0] = hour / 10;
		vals[1] = hour % 10;
	}

	if (prefs->date)
	{
		int year = TM->tm_year + 1900;
		int temp;

		vals[6]  = TM->tm_mday / 10;
		vals[7]  = TM->tm_mday % 10;
		vals[8]  = (TM->tm_mon + 1) / 10;
		vals[9]  = (TM->tm_mon + 1) % 10;
		vals[10] = year / 1000;
		vals[11] = (year - vals[10] * 1000) / 100;
		vals[12] = (year - vals[10] * 1000 - vals[11] * 100) / 10;
		vals[13] = (year - vals[10] * 1000 - vals[11] * 100) % 10;
		if (! prefs->ddmmyy)
		{
			temp = vals[6]; vals[6] = vals[8]; vals[8] = temp;
			temp = vals[7]; vals[7] = vals[9]; vals[9] = temp;
		}
	}


	ObtainSemaphore(&draw_semaphore);

	SetAPen(win->RPort, prefs->background);
	RectFill(win->RPort, offx + 1, offy + 1, offx + width - 2, offy + height - 2);

	SetAPen(win->RPort, prefs->foreground);

	if (! prefs->twentyfour)
	{
		if (! vals[0])
			digits = 1;
	}

	for (k = 3; k >= digits; k--)
	{
		j = vals[k] * 7;
		for (i = 0; i < 7; i++)
		{
			if (Number[j + i])
			{
				Move(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 0],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 1]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 2],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 3]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 4],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 5]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 6],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 7]);
			}
		}
	}
	if (prefs->seconds)
	{
		for (k = 5; k >= 4; k--)
		{
			j = vals[k] * 7;
			for (i = 0; i < 7; i++)
			{
				if (Number[j + i])
				{
					Move(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 0],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 1]);
					Draw(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 2],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 3]);
				}
			}
		}
	}
	Move(win->RPort, offx + Coords[12] + 0,
						  offy + Coords[13] + 0);
	Draw(win->RPort, offx + Coords[12] + 1,
						  offy + Coords[13] + 0);
	Draw(win->RPort, offx + Coords[12] + 1,
						  offy + Coords[13] + 1);
	Draw(win->RPort, offx + Coords[12] + 0,
						  offy + Coords[13] + 1);

	Move(win->RPort, offx + Coords[14] + 0,
						  offy + Coords[15] + 0);
	Draw(win->RPort, offx + Coords[14] + 1,
						  offy + Coords[15] + 0);
	Draw(win->RPort, offx + Coords[14] + 1,
						  offy + Coords[15] + 1);
	Draw(win->RPort, offx + Coords[14] + 0,
						  offy + Coords[15] + 1);


	if (prefs->date)
	{
		for (k = 15; k >= 8; k--)
		{
			j = vals[k - 2] * 7;
			for (i = 0; i < 7; i++)
			{
				if (Number[j + i])
				{
					Move(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 0],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 1]);
					Draw(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 2],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 3]);
				}
			}
		}
		WritePixel(win->RPort, Coords[32] + offx, Coords[33] + offy);
		WritePixel(win->RPort, Coords[34] + offx, Coords[35] + offy);
	}



	ReleaseSemaphore(&draw_semaphore);

	if (prefs->alarm)
		DrawAlarm(prefs->foreground);
	if (prefs->timer)
		DrawTimer(prefs->foreground);


}

struct tm *GetTime( struct Time *myTime, struct AppPrefs *prefs )
{
	time_t tp = time(0);
	tm *TM;
	TM = localtime(&tp);

	myTime->hour1 = TM->tm_hour / 10;
	myTime->hour2 = TM->tm_hour % 10;

	myTime->min1 = TM->tm_min / 10;
	myTime->min2 = TM->tm_min % 10;

	myTime->sec1 = TM->tm_sec / 10;
	myTime->sec2 = TM->tm_sec % 10;

	return TM;
}


void RedrawTime(struct Window *win, struct AppPrefs *prefs)
{
	int offx = win->BorderLeft;
	int offy = win->BorderTop;
	int i, j, k, lower, hour;
	int vals[14];

	static int lastday;
	static int lastmonth;
	static int lastyear;
	static int last[6];

	struct Time myTime;
	struct tm *TM = GetTime( &myTime, prefs );
	BOOL dodate = FALSE;

	if (prefs->date)
	{
		if ((lastday != TM->tm_mday) || (lastmonth != TM->tm_mon) || (lastyear != TM->tm_year))
		{
			int year = TM->tm_year + 1900;
			int temp;

			vals[6]  = TM->tm_mday / 10;
			vals[7]  = TM->tm_mday % 10;
			vals[8]  = (TM->tm_mon + 1) / 10;
			vals[9]  = (TM->tm_mon + 1) % 10;
			vals[10] = year / 1000;
			vals[11] = (year - vals[10] * 1000) / 100;
			vals[12] = (year - vals[10] * 1000 - vals[11] * 100) / 10;
			vals[13] = (year - vals[10] * 1000 - vals[11] * 100) % 10;
			if (! prefs->ddmmyy)
			{
				temp = vals[6]; vals[6] = vals[8]; vals[8] = temp;
				temp = vals[7]; vals[7] = vals[9]; vals[9] = temp;
			}
			lastday = TM->tm_mday;
			lastmonth = TM->tm_mon;
			lastyear = TM->tm_year;
			dodate = TRUE;
		}
	}

	vals[0] = myTime.hour1; vals[1] = myTime.hour2;
	vals[2] = myTime.min1; vals[3] = myTime.min2;
	vals[4] = myTime.sec1; vals[5] = myTime.sec2;

	if (! prefs->twentyfour)
	{
		hour = vals[0] * 10 + vals[1];
		if (hour > 12)
			hour -= 12;
		else if (hour == 0)
			hour = 12;
		vals[0] = hour / 10;
		vals[1] = hour % 10;
	}

	if (prefs->alarm)
		CheckAlarm(prefs, &myTime);
	if (prefs->timer)
		if (CheckTimer(prefs, &myTime))
			TurnTimerOff(prefs);

	lower = 5;
	for (i = 4; i >=0 ; i--)
	{
		if (last[i] != vals[i])
			lower = i;
		last[i] = vals[i];
	}


	ObtainSemaphore(&draw_semaphore);

	for (k = 3; k >= lower; k--)
	{
		j = vals[k] * 7;
		for (i = 0; i < 7; i++)
		{
			SetAPen(win->RPort, prefs->background);
			if (! Number[j + i])
			{
				Move(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 0],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 1]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 2],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 3]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 4],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 5]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 6],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 7]);
			}
			if ((! k) && (! prefs->twentyfour) && (! vals[0]))
				SetAPen(win->RPort, prefs->background);
			else
				SetAPen(win->RPort, prefs->foreground);
			if (Number[j + i])
			{
				Move(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 0],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 1]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 2],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 3]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 4],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 5]);
				Draw(win->RPort, offx + Coords[k * 2 + 0] + BigNumber[i * 8 + 6],
									  offy + Coords[k * 2 + 1] + BigNumber[i * 8 + 7]);
			}
		}
	}
	if (prefs->seconds)
	{
		if (lower < 4)
			lower = 4;
		for (k = 5; k >= lower; k--)
		{
			j = vals[k] * 7;
			for (i = 0; i < 7; i++)
			{
				SetAPen(win->RPort, prefs->background);
				if (! Number[j + i])
				{
					Move(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 0],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 1]);
					Draw(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 2],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 3]);
				}
				SetAPen(win->RPort, prefs->foreground);
				if (Number[j + i])
				{
					Move(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 0],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 1]);
					Draw(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 2],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 3]);
				}
			}
		}
	}

	if (dodate)
	{
		for (k = 15; k >= 8; k--)
		{
			j = vals[k - 2] * 7;
			for (i = 0; i < 7; i++)
			{
				SetAPen(win->RPort, prefs->background);
				if (! Number[j + i])
				{
					Move(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 0],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 1]);
					Draw(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 2],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 3]);
				}
				SetAPen(win->RPort, prefs->foreground);
				if (Number[j + i])
				{
					Move(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 0],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 1]);
					Draw(win->RPort, offx + Coords[k * 2 + 0] + SmallNumber[i * 4 + 2],
										  offy + Coords[k * 2 + 1] + SmallNumber[i * 4 + 3]);
				}
			}
		}
	}


	ReleaseSemaphore(&draw_semaphore);
}


void CheckAlarm(struct AppPrefs *prefs, struct Time *myTime)
{
	realtime = 10000 * (myTime->hour1 * 10 + myTime->hour2) +
				  100 * (myTime->min1  * 10 + myTime->min2) + (myTime->sec1 * 10 + myTime->sec2);

	if (realtime == prefs->alarmval)
		Signal(infotask, alarmsig);
}


void TurnAlarmOff(struct AppPrefs *prefs)
{
	struct MenuItem *it;

	it = (struct MenuItem *)ItemAddress(DClockMenus, (ULONG)FULLMENUNUM(MENU_DCLOCK, MENU_ALARMON, 0));

	ClearMenuStrip(DClockWnd);
	it->Flags = it->Flags & (~CHECKED);
	SetMenuStrip(DClockWnd, DClockMenus);

	prefs->alarm = FALSE;
	EraseAlarm(prefs->background);
}


void DrawAlarm(int color)
{
	int offx = DClockWnd->BorderLeft;
	int offy = DClockWnd->BorderTop;
	struct RastPort *rport = DClockWnd->RPort;

	ObtainSemaphore(&draw_semaphore);

	SetAPen(rport, color);
	WritePixel(rport, ALARM_X + offx, ALARM_Y + offy);
	Move(rport, ALARM_X + offx + 2, ALARM_Y + offy - 1);
	Draw(rport, ALARM_X + offx + 2, ALARM_Y + offy + 1);

	Move(rport, ALARM_X + offx + 4, ALARM_Y + offy - 2);
	Draw(rport, ALARM_X + offx + 4, ALARM_Y + offy + 2);

	ReleaseSemaphore(&draw_semaphore);
}

void EraseAlarm(int color)
{
	int offx = DClockWnd->BorderLeft;
	int offy = DClockWnd->BorderTop;
	struct RastPort *rport = DClockWnd->RPort;

	ObtainSemaphore(&draw_semaphore);

	SetAPen(rport, color);
	RectFill(rport, ALARM_X + offx , ALARM_Y + offy - 2, ALARM_X + offx + 4, ALARM_Y + offy + 2);

	ReleaseSemaphore(&draw_semaphore);
}

void DrawTimer(int color)
{
	int offx = DClockWnd->BorderLeft;
	int offy = DClockWnd->BorderTop;
	struct RastPort *rport = DClockWnd->RPort;

	ObtainSemaphore(&draw_semaphore);

	SetAPen(rport, color);
	Move(rport, TIMER_X + offx, TIMER_Y + offy);
	Draw(rport, TIMER_X + offx + 4, TIMER_Y + offy);
	Move(rport, TIMER_X + offx + 2, TIMER_Y + offy);
	Draw(rport, TIMER_X + offx + 2, TIMER_Y + offy + 4);

	ReleaseSemaphore(&draw_semaphore);
}

void EraseTimer(int color)
{
	int offx = DClockWnd->BorderLeft;
	int offy = DClockWnd->BorderTop;
	struct RastPort *rport = DClockWnd->RPort;

	ObtainSemaphore(&draw_semaphore);

	SetAPen(rport, color);
	RectFill(rport, TIMER_X + offx, TIMER_Y + offy, TIMER_X + offx + 4, TIMER_Y + offy + 5);

	ReleaseSemaphore(&draw_semaphore);
}

BOOL CheckTimer(struct AppPrefs *prefs, struct Time *myTime)
{
	int arglist[3];

	if ((--prefs->timerval) == 0)
	{
		Signal(infotask, timersig);
		return TRUE;
	}
	else
		return FALSE;
}

void TurnTimerOff(struct AppPrefs *prefs)
{
	struct MenuItem *it;
	ULONG menu_num = FULLMENUNUM(MENU_DCLOCK, MENU_TIMERON, 0);

	it = (struct MenuItem *)ItemAddress(DClockMenus, menu_num);

	ClearMenuStrip(DClockWnd);
	it->Flags = it->Flags & (~CHECKED);
	SetMenuStrip(DClockWnd, DClockMenus);
	OffMenu(DClockWnd, menu_num);
	prefs->timer = FALSE;
	EraseTimer(prefs->background);
}


void ShowAlarm(struct AppPrefs *prefs)
{
	int arglist[1];
	char buf[16];
	time_t t = time(0);

	if (prefs->twentyfour)
		strftime(buf, 16, "%X", localtime(&t));
	else
		strftime(buf, 16, "%I:%M:%S %p", localtime(&t));

	arglist[0] = (int)buf;
	DisplayBeep(Scr);
	if (rtEZRequestA("It is %s\n\n"
						  "Whatever you've got to do -\n"
						  "now is the time for doing it",
						  "Turn alarm off|Leave on", NULL, arglist, ezRequestTags))
		TurnAlarmOff(prefs);
}


void ShowTimer(struct AppPrefs *prefs)
{
	int arglist[1];
	char buf[16];
	time_t t = time(0);

	if (prefs->twentyfour)
		strftime(buf, 16, "%X", localtime(&t));
	else
		strftime(buf, 16, "%I:%M:%S %p", localtime(&t));

	arglist[0] = (int)buf;

	DisplayBeep(Scr);
	rtEZRequestA("It is %s\n\n"
					 "The timer has finished",
					 "Thanks", NULL, arglist, ezRequestTags);
}

