#include <arpbase.h>
#include <arp_proto.h>
#include "Dragon.h"
#include "DragonGad.h"
#include "source:launch/launch.h"


struct FileRequester *FRequest;
struct Window *DragonWin, *InputWin;
struct Screen *Screen;
struct ArpBase *ArpBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;


void main (void)
{
	struct IntuiMessage *Message;
	struct Gadget *Gadget;
	LONG Class;
	WORD StartX, StartY;
	struct Dragon Drag, *NewDrag;

	SetUp ();

	CopyMem (DragonWin->RPort, &Drag.RastPort, sizeof (struct RastPort));
	Drag.DuplicateCount = 0;
	Drag.KindCount = 0;

	while (1)
	{
		WaitPort (InputWin->UserPort);

		while ( (Message = (struct IntuiMessage *)GetMsg (InputWin->UserPort)) != NULL)
		{
			Class = Message->Class;
			Gadget = (struct Gadget *)Message->IAddress;
			ReplyMsg (Message);

			if (Class == CLOSEWINDOW)
			{
				CleanUp ();
			}

			if (Class == GADGETUP)
			{
				switch (Gadget->GadgetID)
				{
					case DAYGAD:
					{
						Drag.Day = ReadNumber (DayGadSIBuff, NULL);
						ActivateGadget (&XGad, InputWin, 0);
						break;
					}

					case CELLGAD:
					{
						Drag.Cell = ReadNumber (CellGadSIBuff, NULL);
						ActivateGadget (&DayGad, InputWin, 0);
						break;
					}

					case XGAD:
					{
						StartX = ReadNumber (XGadSIBuff, NULL);
						ActivateGadget (&YGad, InputWin, 0);
						break;
					}

					case YGAD:
					{
						StartY = ReadNumber (YGadSIBuff, NULL);
						ActivateGadget (&CellGad, InputWin, 0);
						break;
					}

					case LOADGAD:
					{
						if (Load (&Drag) != 0)
						{
							Drag.DuplicateCount = 0;
							Drag.KindCount = 0;
						}
						ActivateGadget (&DayGad, InputWin, 0);
						break;
					}

					case GOGAD:
					{
						Drag.DragonX = StartX;
						Drag.DragonY = StartY;
						NewDrag = AllocMem (sizeof (struct Dragon), 0L);
						if (NewDrag)
						{
							CopyMem (&Drag, NewDrag, sizeof (struct Dragon));
							if (NULL == StartProcess ("Dragon generator", (CPTR)MakeDragon, NewDrag, -1))
							{
								DisplayBeep (Screen);
								FreeMem (NewDrag, sizeof (struct Dragon));
							}
						}
						ActivateGadget (&DayGad, InputWin, 0);
						break;
					}

					case STOPGAD:
					{
						KillProcesses ();
						WaitProcesses ();
						ActivateGadget (&DayGad, InputWin, 0);
						break;
					}

					case CLEARGAD:
					{
						SetAPen (&Drag.RastPort, 0);
						RectFill (&Drag.RastPort, 0, 0, 640, 399);
						SetAPen (&Drag.RastPort, 1);
						ActivateGadget (&DayGad, InputWin, 0);
						break;
					}
				}
			}
		}
	}
}


void MakeDragon (struct Dragon *Drag)
{
	Move (&Drag->RastPort, Drag->DragonX, Drag->DragonY);
	Dragon (Drag->Day, Drag->Cell, Drag);
	FreeMem (Drag, sizeof (struct Dragon));
}


void Dragon (WORD Day, WORD Cell, struct Dragon *Drag)
{
	WORD i;

	if (CheckKill ())
	{
		return;
	}

	if (Day <= 0)
	{
		Drag->DragonX += Drag->MoveX[Cell];
		Drag->DragonY += Drag->MoveY[Cell];
		Draw (&Drag->RastPort, Drag->DragonX, Drag->DragonY);
	}
	else
	{
		for (i = 0; i < Drag->DuplicateCount; i++)
		{
			Dragon (Day-1, Drag->Duplicate[Cell][i], Drag);
		}
	}
}


WORD ReadNumber (BYTE *Buffer, WORD *PosPtr)
{
	WORD Number, Sign, Position;

	Sign = 1;
	Position = 0;
	Number = 0;

	while (*Buffer == ' ' || *Buffer == 10)
	{
		Position++;
		Buffer++;
	}

	if (*Buffer == '-')
	{
		Sign = -1;
		Position++;
		Buffer++;
	}

	while (*Buffer >= '0' && *Buffer <= '9')
	{
		Number *= 10;
		Number += *Buffer - '0';
		Buffer++;
		Position++;
	}

	if (PosPtr != NULL)
	{
		*PosPtr += Position;
	}

	return (Sign == 1 ? Number : -Number);
}


WORD Load (struct Dragon *Drag)
{
	LONG Len;
	WORD i,j;
	WORD Position;
	BYTE *Buffer, Name[256];
	BPTR File;

	if (FileRequest (FRequest))
	{
		strcpy (Name, FRequest->fr_Dir);
		TackOn (Name, FRequest->fr_File);

		if ( (File = Open (Name, MODE_OLDFILE)) == NULL)
			return 1;

		Len = Seek (File, 0, OFFSET_END);
		Len = Seek (File, 0, OFFSET_BEGINNING);

		if ( (Buffer = DosAllocMem (Len)) == NULL)
		{
			Close (File);
			return 1;
		}

		Read (File, Buffer, Len);
		Close (File);

		Position = 0;

		Drag->KindCount = ReadNumber (Buffer+Position, &Position);
		Drag->DuplicateCount = ReadNumber (Buffer+Position, &Position);

		if (Drag->KindCount <= 0 || Drag->DuplicateCount <= 0)
			return 1;

		for (i = 0; i < Drag->KindCount; i++)
		{
			Drag->MoveX[i] = ReadNumber (Buffer+Position, &Position);
		}

		for (i = 0; i < Drag->KindCount; i++)
		{
			Drag->MoveY[i] = ReadNumber (Buffer+Position, &Position);
		}

		for (i = 0; i < Drag->KindCount; i++)
		{
			for (j = 0; j < Drag->DuplicateCount; j++)
			{
				Drag->Duplicate[i][j] = ReadNumber (Buffer+Position, &Position);
				if (Drag->Duplicate[i][j] < 0)
				{
					return 1;
				}
			}
		}

		DosFreeMem (Buffer);
	}

	return 0;
}


void SetUp (void)
{
	if ( (ArpBase = (void *)OpenLibrary ("arp.library", 0)) == NULL)
	{
		CleanUp ();
	}

	if ( (GfxBase = (void *)OpenLibrary ("graphics.library", 0)) == NULL)
	{
		CleanUp ();
	}

	if ( (IntuitionBase = (void *)OpenLibrary ("intuition.library", 0)) == NULL)
	{
		CleanUp ();
	}

	if ( (Screen = OpenScreen(&DragonNewScreen)) == NULL )
	{
		CleanUp();
	}

	SetRGB4 (&Screen->ViewPort, 0, 0, 0, 0);
	SetRGB4 (&Screen->ViewPort, 1, 4, 6, 14);

	DragonNewWin.Screen = InputNewWin.Screen = Screen;

	if ( (DragonWin = OpenWindow (&DragonNewWin)) == NULL )
	{
		CleanUp ();
	}

	if ( (InputWin = OpenWindow (&InputNewWin)) == NULL )
	{
		CleanUp ();
	}

	FRequest = ArpAllocFreq ();
	if (FRequest)
	{
		FRequest->fr_Window = InputWin;
		FRequest->fr_Hail = "Choose Dragon...";
	}
	else
	{
		CleanUp ();
	}
}


void CleanUp (void)
{
	KillProcesses ();
	WaitProcesses ();

	if (InputWin)
		CloseWindow (InputWin);

	if (DragonWin)
		CloseWindow (DragonWin);

	if (Screen)
		CloseScreen (Screen);

	if (IntuitionBase)
		CloseLibrary (IntuitionBase);

	if (GfxBase)
		CloseLibrary (GfxBase);

	if (ArpBase)
		CloseLibrary (ArpBase);

	exit (0);
}
