/************
 *
 * Includes:
 *
 ************/

#include <exec/types.h>
#include <intuition/intuition.h>
#include "src/Editor.h"

/***********
 *
 * Defines:
 *
 ***********/

#define REV 33L
#define MAXINPUTLEN 128L

/**********************
 *
 * External Functions:
 *
 **********************/

void Test();

struct Library *OpenLibrary();
struct Window *OpenWindow();
void CloseLibrary(),NewList(),AddTail(),CloseWindow(),free();
void DeletePort(),ModifyIDCMP(),ReplyMsg(),freeMemoryblock();
void initWindowSize(),SetDrMd(),SetAPen(),SetBPen(),printAll();
void handleKeys(),Cursor();
void BeginRefresh(),EndRefresh();
struct Editor *malloc(),*RemHead();
struct MsgPort *CreatePort();
struct IntuiMessage *GetMsg();
ULONG Wait(),OpenDevice();
SHORT RawKeyConvert();

/*********************
 *
 * Global Variables:
 *
 *********************/ 

struct Library *IntuitionBase = NULL, *GfxBase = NULL, *DosBase = NULL;
struct Device *ConsoleDevice = NULL;

struct EList editorList;
struct Editor *actualEditor;

struct NewWindow newEdWindow =
{
	100,40,440,156,
	AUTOFRONTPEN,AUTOBACKPEN,
	REFRESHWINDOW | MOUSEBUTTONS | RAWKEY | CLOSEWINDOW | NEWSIZE,
	WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SIZEBBOTTOM
	| SIMPLE_REFRESH | ACTIVATE,
	NULL,NULL,
	(UBYTE *)"Editor",
	NULL,NULL,
	100,50,640,200,
	WBENCHSCREEN
};

struct MsgPort *edUserPort = NULL;

struct IOStdReq ioStdReq;

UBYTE inputBuffer[MAXINPUTLEN];
UWORD inputLen = 0;

struct InputEvent inputEvent =
{
	0,
	IECLASS_RAWKEY,0,
	0,0
};

/***************
 *					*
 * Functions: *
 *					*
 ***************/

/*********************************************
 *
 * nextLine(line,pnr)
 *
 * Returns pointer to next line,
 * and executes folding
 * Zero, if no next line.
 *
 * line ^ Zline-Structure.
 * pnr ^ to Zline number.
 *
 *********************************************/

struct Zline *nextLine(line,pnr)
register struct Zline *line;
register UWORD					 *pnr;
{
	register struct Zline *z;
	register UWORD minfold = actualEditor->minfold;
	register UWORD maxfold = actualEditor->maxfold;

	if (z = line)
		if (z->succ)
			do
			{
				if ((z = z->succ)->succ)
					if ((z->flags & ZLF_FOLD) < minfold)
					{
						/* Following lines lie outside of fold */
						z = NULL;
						break;
					}
					else
						*pnr += 1;
				else
				{
					/* no following line */
					z = NULL;
					break;
				}
			}
			while ((z->flags & ZLF_FOLD) > maxfold);
		else
			z = NULL;

	return (z);
}

/*******************************************
 *
 * prevLine(line,pnr)
 *
 * Returns pointer to previous line
 * and executes folding
 * Zero, if no previous line.
 *
 * line ^ Zline-Structure.
 * pnr ^ to  line number.
 *
 *******************************************/

struct Zline *prevLine(line,pnr)
register struct Zline *line;
register UWORD					 *pnr;
{
	register struct Zline *z;
	register UWORD minfold = actualEditor->minfold;
	register UWORD maxfold = actualEditor->maxfold;

	if (z = line)
		if (z->pred)
			do
			{
				if ((z = z->pred)->pred)
					if ((z->flags & ZLF_FOLD) < minfold)
					{
						/* previous line lies outside fold */
						z = NULL;
						break;
					}
					else
						*pnr += 1;
				else
				{
					/* no previous line */
					z = NULL;
					break;
				}
			}
			while ((z->flags & ZLF_FOLD) > maxfold);
		else
			z = NULL;

	return (z);
}

/***********************************
 *
 * OpenEditor()
 *
 * Open Editor window and
 * initalize Editor structure
 *
 * Returns pointer to Editor structur
 * or is zero in case of an error.
 *
 ***********************************/

struct Editor *OpenEditor()
{
	register struct Editor *ed = NULL;
	register struct Window *wd;
	register struct RastPort *rp;
	register ULONG flags;
	register UBYTE *ptr;
	register struct Zline **zptr;
	register UWORD n,*pnr;

	/* IDCMPFlags saved, sets it to zero in structure!
		=> use your own UserPort! */
	flags = newEdWindow.IDCMPFlags;
	newEdWindow.IDCMPFlags = NULL;

	/* Memory for editor structure: */
	if (ed = malloc(sizeof(struct Editor)))
		/* Window open: */
		if (wd = OpenWindow(&newEdWindow))
		{
			ed->window = wd;
			ed->rp = (rp = wd->RPort);

			/* Write mode set: */
			SetDrMd(rp,JAM2);
			SetAPen(rp,FGPEN);
			SetBPen(rp,BGPEN);

			/* UserPort established: */
			wd->UserPort = edUserPort;
			ModifyIDCMP(wd,flags);

			/* Parameter initialization: */
			NewList(&(ed->block));
			NewList(&(ed->zlines));
			ed->num_lines = 0;
			ed->actual = NULL;
			ed->toppos = 0;
			ed->leftpos = 0;
			ed->xpos = 1;
			ed->ypos = 1;
			ed->wdy	= 0;
			ed->changed = 0;
			ed->insert = 1;
			ed->minfold = 0;
			ed->maxfold = 0;

			/* zlinesptr/nr-Array initialization: */
			for (n = 0, zptr = ed->zlinesptr, pnr = ed->zlinesnr;
					n < MAXHEIGHT; n++, zptr++, pnr++)
			{
				*zptr = NULL;
				*pnr	= 1;
			}

			/* Tab initialization: */
			ptr = ed->tabstring;
			*ptr++ = 1;
			for (n = 1; n < MAXWIDTH; n++)
				if (n % 3)
					*ptr++ = 1;
				else
					*ptr++ = 0;

			ed->wch = 0;
			initWindowSize(ed);
		}
		else
		{
			free(ed);
			ed = NULL;
		}

	newEdWindow.IDCMPFlags = flags;
	return (ed);
}

/***************************
 *
 * CloseEditor(ed)
 *
 * Close editor window.
 *
 * ed ^ Editor structure.
 *
 ***************************/

void CloseEditor(ed)
struct Editor	 *ed;
{
	register struct Memoryblock *blk;

	/* Free first memory block: */
	while (blk = (struct Memoryblock *)RemHead(&(ed->block)))
		freeMemoryblock(blk);

	/* Then Close window: */
	ed->window->UserPort = NULL;
	CloseWindow(ed->window);
	free(ed);
}

/*****************
 *
 * Main program:
 *
 *****************/

main()
{
	register struct Editor *ed;
	BOOL running = TRUE;
	register struct IntuiMessage *imsg;
	ULONG signal,class,mouseX,mouseY;
	UWORD code,qualifier;
	APTR iaddress;

	/* Libraries open: */
	if ( !(IntuitionBase = OpenLibrary("intuition.library",REV)))
		goto Ende;
	if ( !(GfxBase = OpenLibrary("graphics.library",REV)))
		goto Ende;
	if ( !(DosBase = OpenLibrary("dos.library",REV)))
		goto Ende;
	if ( !(OpenDevice("console.device",-1L,&ioStdReq,0L)))
		ConsoleDevice = ioStdReq.io_Device;
	else
		goto Ende;

	/* UserPort open */
	if (! (edUserPort = CreatePort(NULL,0L))) goto Ende;

	/* Editor list initialization: */
	NewList(&editorList);

	/* Open first editor window: */
	if (ed = OpenEditor())
	{
		AddTail(&editorList,ed);
		actualEditor = ed;
	}
	else
		goto Ende;

	Test();

	do
	{
		/* Set cursor : */
		Cursor();

		signal = Wait(1L << edUserPort->mp_SigBit);

		/* erase cursor again: */
		Cursor();

		while (imsg = GetMsg(edUserPort))
		{
			class			= imsg->Class;
			code			= imsg->Code;
			qualifier	= imsg->Qualifier;
			iaddress		= imsg->IAddress;
			mouseX		= imsg->MouseX;
			mouseY		= imsg->MouseY;

			ReplyMsg(imsg);

			/* Event processing: */
			switch (class)
			{
				case RAWKEY:
					if (! (code & IECODE_UP_PREFIX))
					{
						inputEvent.ie_Code		= code;
						inputEvent.ie_Qualifier = qualifier;
						if ((inputLen = RawKeyConvert(
									&inputEvent,inputBuffer,MAXINPUTLEN,NULL)
									) >= 0)
							handleKeys(inputBuffer,inputLen);
					}
					break;

				case MOUSEBUTTONS:
					{
						register WORD x,y;

						if (mouseX <= actualEditor->xoff)
							x = 0;
						else
							x = (mouseX - actualEditor->xoff)
								/ actualEditor->cw;
						if (++x >= actualEditor->wcw)
							x = actualEditor->wcw - 1;
						x += actualEditor->leftpos;
						if (x > MAXWIDTH)
							x = MAXWIDTH;

						if (mouseY <= actualEditor->yoff)
							y = 0;
						else
							y = (mouseY - actualEditor->yoff)
								/ actualEditor->ch;

						if ((y < actualEditor->wch)
							&& (actualEditor->zlinesptr[y]))
						{
							actualEditor->xpos = x;
							actualEditor->wdy  = y;
							actualEditor->ypos = actualEditor->zlinesnr[y];
						}
					}

				case NEWSIZE:
					initWindowSize(actualEditor);

					/* check if cursor still in window! */
					if (actualEditor->xpos > actualEditor->leftpos
														+actualEditor->wcw)
						actualEditor->xpos = actualEditor->leftpos
													 + actualEditor->wcw;

					if (actualEditor->wdy >= actualEditor->wch)
						actualEditor->ypos = actualEditor->zlinesnr
							[(actualEditor->wdy  = actualEditor->wch - 1)];

					break;

				case REFRESHWINDOW:
					BeginRefresh(actualEditor->window);
					printAll();
					EndRefresh(actualEditor->window,TRUE);
					break;

				case CLOSEWINDOW:
					running = FALSE;
					break;

				default:
					printf("Not a processable event: %lx\n",class);

			} /* of case */
		} /* of while (GetMsg()) */
	} while (running);

Ende:
	/* Close all editor windows: */
	while (ed = RemHead(&editorList))
		CloseEditor(ed);

	/* Close UserPort: */
	if (edUserPort) DeletePort(edUserPort);

	/* Close Libraries: */
	if (DosBase) CloseLibrary(DosBase);
	if (GfxBase) CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
}
