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

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

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

#define CSI 0x9B
#define CUU 'A'
#define CUD 'B'
#define CUF 'C'
#define CUB 'D'
#define SU 'S'
#define SD 'T'

#define CFOLD 6
#define CENDF 5

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

void SetDrMd(),RectFill(),printAll();
struct Zline *nextLine(),*prevLine();

/*********************
 *
 * External Variables:
 *
 *********************/ 

extern struct Editor *actualEditor;
extern UWORD SplitDec;

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

/************************************
 *
 * restoreZlinenptr:
 *
 * Restore the zlinesptr/nr field
 * for all lines in window plus
 * the next line.
 * The first line must be
 * correct!
 *
 ************************************/

void restoreZlinenptr()
{
	register UWORD n;
	register struct Zline **zptr,*z;
	register UWORD *pnr;
	UWORD znr;

	for (n = actualEditor->wch, zptr = actualEditor->zlinesptr,
					pnr = actualEditor->zlinesnr,
					z = *zptr++, znr = *pnr++; n; n--)
	{
		*zptr++	= (z = nextLine(z,&znr));
		*pnr++	= znr;
	}
}

/**********************************
 *
 * Cursor:
 *
 * Set or erase the cursor
 * at the actual position.
 *
 **********************************/

void Cursor()
{
	register struct RastPort *rp;
	register LONG x,y;
	register LONG cw,ch;

	SetDrMd(rp = actualEditor->rp,COMPLEMENT);

	x = (actualEditor->xpos - actualEditor->leftpos - 1)
		*(cw = actualEditor->cw) + actualEditor->xoff;
	y = actualEditor->wdy
		*(ch = actualEditor->ch) + actualEditor->yoff;

	RectFill(rp,x,y,x + cw-1,y + ch-1);

	SetDrMd(rp,JAM2);
}

/*******************************
 *
 * scrollRight(num):
 *
 * Scroll the window contents
 * num characters to the right.
 *
 * num = number of characters.
 *
 *******************************/

void scrollRight(num)
register UWORD	  num;
{
	register UWORD y,ch,count;
	register struct Zline **z;
	UWORD wcw,xoff,leftpos;

	actualEditor->leftpos -= num;

	if (num >= actualEditor->wcw)
		printAll();
	else
	{
		/* Scrolling: */
		ScrollRaster(actualEditor->rp,
						 -num * (LONG)actualEditor->cw,0L,
						 (LONG)actualEditor->xoff,(LONG)actualEditor->yoff,
						 (LONG)actualEditor->xscr,(LONG)actualEditor->yscr);

		/* now list printAll(): */
		wcw = actualEditor->wcw;
		actualEditor->wcw = num + 1;
		SplitDec = 1;

		y		= actualEditor->yoff;
		ch		= actualEditor->ch;
		count	= actualEditor->wch;

		/* Output line: */
		for (z = actualEditor->zlinesptr; count-- && (*z != NULL);
				z++, y += ch)
			printLine(*z,y);

		SplitDec = 0;

		/* Display right border beside last character */
		leftpos	= actualEditor->leftpos;
		xoff		= actualEditor->xoff;
		actualEditor->wcw		  = 2;
		actualEditor->leftpos += (y = wcw - 2);
		actualEditor->xoff	 += actualEditor->cw * y;

		y		= actualEditor->yoff;
		count	= actualEditor->wch;

		/* Output line: */
		for (z = actualEditor->zlinesptr; count-- && (*z != NULL);
				z++, y += ch)
			printLine(*z,y);

		actualEditor->wcw		= wcw;
		actualEditor->leftpos= leftpos;
		actualEditor->xoff	= xoff;
	}
}

/*******************************
 *
 * scrollLeft(num):
 *
 * Scroll the window contents
 * num characters left.
 *
 * num = number of characters.
 *
 *******************************/

void scrollLeft(num)
register UWORD  num;
{
	register UWORD y,ch,count;
	register struct Zline **z;
	UWORD wcw,xoff,leftpos;

	actualEditor->leftpos += num;

	if (num >= actualEditor->wcw)
		printAll();
	else
	{
		/* Scrolling: */
		ScrollRaster(actualEditor->rp,
						 num * (LONG)actualEditor->cw,0L,
						 (LONG)actualEditor->xoff,(LONG)actualEditor->yoff,
						 (LONG)actualEditor->xscr,(LONG)actualEditor->yscr);

		/* now list printAll(): */
		wcw		= actualEditor->wcw;
		leftpos	= actualEditor->leftpos;
		xoff		= actualEditor->xoff;
		actualEditor->wcw		  = num + 1;
		actualEditor->leftpos += (y = wcw - num - 1);
		actualEditor->xoff	 += actualEditor->cw * y;

		y		= actualEditor->yoff;
		ch		= actualEditor->ch;
		count	= actualEditor->wch;

		/* Output line: */
		for (z = actualEditor->zlinesptr; count-- && (*z != NULL);
				z++, y += ch)
			printLine(*z,y);

		actualEditor->wcw		= wcw;
		actualEditor->leftpos= leftpos;
		actualEditor->xoff	= xoff;
	}
}

/*******************************
 *
 * scrollUp(num):
 *
 * Scroll the window contents
 * num lines up.
 * Num lines must
 * exist!
 *
 * num = number of lines.
 *
 *******************************/

void scrollUp (num)
register UWORD num;
{
	register struct Zline *z,**zptr,**zold;
	register UWORD n,wch = actualEditor->wch,y;
	UWORD znr,*pnr,*oldnr;

	if (num >= wch)
	{
		/* Display window without Scrolling */
		/* First look for top line: */
		n = wch;
		if (num > wch)
		{
			z = ZLINESPTR(n);
			znr = ZLINESNR(n);
			while (++n < num)
				z = nextLine(z,&znr);
		}
		else
		{
			z = ZLINESPTR(n - 1);
			znr = ZLINESNR(n - 1);
		}

		/* z points before the top line of the window */
		for (n = 0, zptr = actualEditor->zlinesptr,
			  pnr = actualEditor->zlinesnr; n <= wch; n++)
		{
			*zptr++ = (z = nextLine(z,&znr));
			*pnr++	= znr;
		}

		/* Now redisplay the window: */
		printAll();
	}
	else
	{
		/* Scrolling: */
		ScrollRaster(actualEditor->rp,
						 0L,num * (LONG)actualEditor->ch,
						 (LONG)actualEditor->xoff,(LONG)actualEditor->yoff,
						 (LONG)actualEditor->xscr,(LONG)actualEditor->yscr);

		/* zlinesptr/nr recalculated: */
		zptr = actualEditor->zlinesptr;
		zold = &(ZLINESPTR(num));
		pnr = actualEditor->zlinesnr;
		oldnr = &(ZLINESNR(num));
		for (n = 0; n <= wch - num; n++)
		{
			*zptr++ = *zold++;
			*pnr++  = *oldnr++;
		}

		z = *--zold;
		zold = zptr - 1;			/* mark for output! */
		znr = *--oldnr;
		oldnr = pnr - 1;
		while (n <= wch)
		{
			*zptr++ = (z = nextLine(z,&znr));
			*pnr++ = znr;
			n++;
		}

		/* Output new line: */
		for (n = num, y = actualEditor->yoff+(wch-num)*actualEditor->ch;
				(n && (*zold != NULL)); n--, zold++, y += actualEditor->ch)
			printLine(*zold,y);
	}

	actualEditor->toppos += num;
}

/*******************************
 *
 * scrollDown(num):
 *
 * Scroll the window contents
 * num lines down.
 * Num lines must
 * exist!
 *
 * num = number of lines.
 *
 *******************************/

void scrollDown (num)
register UWORD num;
{
	register struct Zline *z,**zptr,**zold;
	register UWORD n,wch = actualEditor->wch,y;
	UWORD znr,*pnr,*oldnr;

	if (num >= wch)
	{
		/* Display window without Scrolling */
		/* search backwards fo rtop line: */
		for (z = ZLINESPTR(0), znr = ZLINESNR(0), n = num - wch; n; n--)
			z = prevLine(z,&znr);

		/* z points to first line after bottom windo edge. */
		for (n = 0, zptr = &(ZLINESPTR(wch)), pnr = &(ZLINESNR(wch));
				n <= wch; n++)
		{
			*zptr-- = z;
			*pnr-- = znr;
			z = prevLine(z,&znr);
		}

		/* Now redisplay the window: */
		printAll();
	}
	else
	{
		/* Scrolling: */
		ScrollRaster(actualEditor->rp,
						 0L,-num * (LONG)actualEditor->ch,
						 (LONG)actualEditor->xoff,(LONG)actualEditor->yoff,
						 (LONG)actualEditor->xscr,(LONG)actualEditor->yscr);

		/* zlinesptr recalculated: */
		zptr = &(ZLINESPTR(wch));
		zold = &(ZLINESPTR(wch - num));
		pnr = &(ZLINESNR(wch));
		oldnr = &(ZLINESNR(wch - num));
		for (n = 0; n <= wch - num; n++)
		{
			*zptr-- = *zold--;
			*pnr-- = *oldnr--;
		}

		for (z = *++zold, znr = *++oldnr, n = num; n; n--)
		{
			*zptr-- = (z = prevLine(z,&znr));
			*pnr-- = znr;
		}

		/* Output new line: */
		for (n = num, y = actualEditor->yoff; (n && (*zold != NULL));
				n--, zold++, y += actualEditor->ch)
			printLine(*zold,y);
	}

	actualEditor->toppos -= num;
}

/****************************************
 *
 * cursorLeft:
 *
 * moce cursor one position
 * left, False returned if cursor,
 * is in first column.
 *
 ****************************************/

BOOL cursorLeft()
{
	if (actualEditor->xpos > 1)
	{
		actualEditor->xpos--;
		if (actualEditor->xpos <= actualEditor->leftpos)
			scrollRight((UWORD)1);

		return (TRUE);
	}
	else
		return (FALSE);
}

/*****************************************
 *
 * cursorRight:
 *
 * moce cursor one position
 * right, False returned if cursor,
 * is in last column.
 *
 *****************************************/

BOOL cursorRight()
{
	if (actualEditor->xpos < MAXWIDTH)
	{
		actualEditor->xpos++;
		if (actualEditor->xpos
			>= (actualEditor->leftpos + actualEditor->wcw))
			scrollLeft((UWORD)1);

		return (TRUE);
	}
	else
		return (FALSE);
}

/*****************************************
 *
 * cursorUp:
 *
 * Move cursor one line up.
 * False returned when
 * on first line.
 *
 *****************************************/

BOOL cursorUp()
{
	UWORD help;

	if (actualEditor->wdy)
		actualEditor->wdy--;
	else
		if (prevLine(ZLINESPTR(0),&help))
			scrollDown((UWORD)1);
		else
			return (FALSE);

	actualEditor->ypos = ZLINESNR(actualEditor->wdy);

	return (TRUE);
}

/******************************************
 *
 * cursorDown:
 *
 * Move cursor one line down.
 * False returned when
 * on last line.
 *
 ******************************************/

BOOL cursorDown()
{
	if (ZLINESPTR(actualEditor->wdy + 1))
	{
		if (++actualEditor->wdy >= actualEditor->wch)
		{
			scrollUp((UWORD)1);
			actualEditor->wdy--;
		}
		actualEditor->ypos = ZLINESNR(actualEditor->wdy);

		return (TRUE);
	}
	else
		return (FALSE);
}

/**********************************
 *
 * halfPageUp:
 *
 *	Move cursor on half page
 * up. The text is scrolled
 * half page up
 *   
 * False returned when
 * in first line.
 *
 **********************************/

BOOL halfPageUp()
{
	register UWORD max,n;
	register struct Zline *z;
	UWORD help;

	max = actualEditor->wch / 2;
	for (n = 0, z = ZLINESPTR(0); n < max; n++)
		if (!(z = prevLine(z,&help)))
			break;

	if (n)
	{
		scrollDown(n);
		actualEditor->ypos = ZLINESNR(actualEditor->wdy);

		return (TRUE);
	}
	else
		return (FALSE);
}

/**********************************
 *
 * halfPageDown:
 *
 *	Move cursor on half page
 * down. The text is scrolled
 * half page up
 * oben gescrollt.
 * False returned when
 * on last line.
 *
 **********************************/

BOOL halfPageDown()
{
	register UWORD max,n;
	register struct Zline *z;
	UWORD help;

	max = actualEditor->wch / 2;
	for (n = 0, z = ZLINESPTR(actualEditor->wch - 1); n < max; n++)
		if (!(z = nextLine(z,&help)))
			break;

	if (n)
	{
		scrollUp(n);
		actualEditor->ypos = ZLINESNR(actualEditor->wdy);

		return (TRUE);
	}
	else
		return (FALSE);
}

/*******************************
 *
 * handleKeys(buf,len):
 *
 * Handles keyboard messages.
 *
 * buf ^ buffer with character.
 * len = number of characters.
 *
 *******************************/

void handleKeys(buf,len)
register UBYTE	*buf;
register WORD		  len;
{
	register UBYTE first;
	register struct Zline *z;

	while (len > 0)
	{
		first = *buf;
		buf++;
		len--;
		if ((first == CSI) && (len > 0))
		{
			len--;
			switch (*buf++)
			{
				case CUU:
					cursorUp();
					break;
				case CUD:
					cursorDown();
					break;
				case CUF:
					cursorRight();
					break;
				case CUB:
					cursorLeft();
					break;
				case SU:
					halfPageDown();
					break;
				case SD:
					halfPageUp();
					break;

				default:
					buf--;
					len++;
					break;
			}
		}
		else if ((first == CFOLD) && (actualEditor->maxfold < ZLF_FOLD))
		{
			actualEditor->maxfold++;
			if (z = ZLINESPTR(actualEditor->wdy))
				if ((z = z->succ)->succ)
					/* If there is a following line: */
					if (((ZLINESPTR(actualEditor->wdy)->flags & ZLF_FOLD)
					  	< (z->flags & ZLF_FOLD))
						&& ((z->flags & ZLF_FOLD) == actualEditor->maxfold))
					{
						/* When this begins a new fold: */
						actualEditor->minfold = actualEditor->maxfold;
						ZLINESPTR(0)	= z;
						ZLINESNR(0)		= ZLINESNR(actualEditor->wdy) + 1;
						actualEditor->wdy = 0;
					}

			restoreZlinenptr();
			printAll();
			actualEditor->ypos = ZLINESNR(actualEditor->wdy);
		}
		else if ((first == CENDF) && (actualEditor->maxfold))
		{
			actualEditor->maxfold--;
			if (actualEditor->minfold > actualEditor->maxfold)
				actualEditor->minfold = actualEditor->maxfold;

			if (((ZLINESPTR(0)->flags & ZLF_FOLD) > actualEditor->maxfold)
			|| ((ZLINESPTR(0)->flags & ZLF_FOLD) < actualEditor->minfold))
			{
				ZLINESPTR(0) = prevLine(ZLINESPTR(0),&(ZLINESNR(0)));
				actualEditor->wdy = 0;
			}

			restoreZlinenptr();
			printAll();
			actualEditor->ypos = ZLINESNR(actualEditor->wdy);
		}
		else
			putchar(first);
	}
}
