/***********************************
 *											  *
 * Module: Output	
 *											  *
 * Output text in a window. 
 *											  *
 ***********************************/

/*#FOLD: Includes */
/************
 *
 * Includes:
 *
 ************/

#include <exec/types.h>
#include <intuition/intuition.h>
#include "src/Editor.h"
/*#ENDFD*/
/*#FOLD: Defines */
/***********
 *
 * Defines:
 *
 ***********/

#define CR 13
#define LF 10
#define TAB 9
/*#ENDFD*/
/*#FOLD: External Functions */
/**********************
 *
 * External Functions:
 *
 **********************/

void SetAPen(),RectFill(),Text(),Move(),SetFont();
struct Zline *nextLine();
/*#ENDFD*/
/*#FOLD: External Variables */
/*********************
 *
 * External Variables:
 *
 *********************/ 

extern struct Editor *actualEditor;
extern struct TextFont *infoFont;
/*#ENDFD*/
/*#FOLD: Global Variables */
/*********************
 *
 * Global Variables:
 *
 *********************/ 

UWORD SplitDec = 0;
/*#ENDFD*/

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

/*#FOLD: initWindowSize */
/**********************************
 *
 * initWindowSize(ed)
 *
 * Initializes the width/height
 * statement of the actual windows.
 * Restores the zlineptr field
 *   
 *
 * ed ^ Editor structure.
 *
 **********************************/

void initWindowSize	  (ed)
register struct Editor *ed;
{
	register struct Window *w;
	register struct RastPort *rp;
	register UWORD n,newh;

	w	= ed->window;
	rp = ed->rp;

	ed->xoff = (UWORD)w->BorderLeft;
	ed->yoff = (UWORD)w->BorderTop;

	ed->cw	= (rp->TxWidth)? rp->TxWidth : 8;
	ed->ch	= (rp->TxHeight)? rp->TxHeight : 8;

	ed->wcw	= (w->Width - ed->xoff - w->BorderRight) / ed->cw;
	newh		= (w->Height- ed->yoff - w->BorderBottom)/ ed->ch;

	ed->xrl	= ed->xoff + ed->wcw*ed->cw;
	ed->xrr	= w->Width - w->BorderRight - 1;
	ed->yru	= w->Height - w->BorderBottom - 1;
	ed->bl	= rp->TxBaseline;

	{
		/* Position for Infoline: */
		register ULONG xinc,xsize;
	
		xinc = w->Width + ed->G_Info.LeftEdge + ed->gi_IText.LeftEdge - 1;
		xsize= infoFont->tf_XSize;

		ed->ip_xpos			= xinc + INFO_XPOS_INC * xsize;
		ed->ip_ypos			= xinc + INFO_YPOS_INC * xsize;
		ed->ip_numzlines	= xinc + INFO_NUMOFLINES_INC * xsize;
		ed->ip_minfold		= xinc + INFO_MINFOLD_INC * xsize;
		ed->ip_maxfold		= xinc + INFO_MAXFOLD_INC * xsize;
		ed->ip_flags		= xinc + INFO_FLAGS_INC * xsize;
		ed->ip_topedge		= w->Height + ed->G_Info.TopEdge
								+ ed->gi_IText.TopEdge
								+ (ULONG)infoFont->tf_Baseline - 1;
	}

	/* Now restore the zlineptr field: */
	if (newh != ed->wch)
	{
		register struct Zline *z,**zptr;
		UWORD znr,*pnr;

		if (newh < ed->wch)
		{
			/* Pointer to Null set: */
			zptr = ed->zlinesptr + newh + 1;
			for (n = newh; n < ed->wch; n++)
				*zptr++ = NULL;
		}
		else
		{
			zptr	= ed->zlinesptr + ed->wch;
			z		= *zptr++;
			pnr	= &(ed->zlinesnr[ed->wch]);
			znr	= *pnr++;
			for (n = ed->wch; n < newh; n++)
			{
				*zptr++	= (z = nextLine(z,&znr));
				*pnr++	= znr;
			}
		}

		ed->wch = newh;
	}

	/* Top/bottom border for scrolling: */
	ed->xscr = ed->xoff + ed->wcw*ed->cw - 1;
	ed->yscr = ed->yoff + ed->wch*ed->ch - 1;
}
/*#ENDFD*/
/*#FOLD: convertLineForPrint */
/******************************************
 *
 * convertLineForPrint(line,len,w,buf,lc)
 *
 * Convert line so that this can be
 * displayed simply.
 * Tabs converted into spaces
 *   
 *
 * line ^ Zline.
 * len = the length.
 * w = maximum wiidth.
 * buf ^buffer, in which the converted line
 *			 is stored.
 * lc ^ to Variable.
 *
 ******************************************/

UWORD convertLineForPrint(line,len,w,buf,lc)
UBYTE							 *line;
register WORD						  len;
register UWORD								w;
register UBYTE								 *buf;
UBYTE												  *lc;
{
	register UBYTE *tab;
	register UWORD l = 1, skip = actualEditor->leftpos;
	UBYTE lastchar;
	UWORD realLen;

	/* determine if ends with CR or LF: */
	if (len)
	{
		tab = line + len - 1;
		if (*tab == CR)
		{
			len--;
			lastchar = ' ';
		}
		else if (*tab == LF)
		{
			len--;
			lastchar = ' ';
			if ((len) && (*--tab == CR))
				len--;
		}
		else
			lastchar = 183;
	}
	else
		lastchar = 183;

	if (actualEditor->tabs)
	{
		/* line convert: */
		tab = actualEditor->tabstring;
		while ((len--) && (l < w))
			if ((*buf = *line++) == TAB)
				do
				{
					tab++;
					if (skip)
						skip--;
					else
					{
						l++;
						*buf++ = ' ';
					}
				} while ((*tab) && (l < w));
			else
			{
				tab++;
				if (skip)
					skip--;
				else
				{
					l++;
					buf++;
				}
			}
	}
	else
	{
		/* line copied with no tabs: */
		while ((len--) && (l < w))
		{
			if (skip)
				skip--;
			else
			{
				l++;
				*buf++ = *line;
			}
			line++;
		}
	}

	/* determine if the line is not completely converted: */
	if (len >= 0)
		lastchar = 183;

	/* save lenght of line */
	realLen = l - 1;

	/* line filled from last character to end: */
	while (l++ <= w)
		*buf++ = lastchar;

	*lc = lastchar;
	return (realLen);
}
/*#ENDFD*/
/*#FOLD: printAt */
/************************************
 *
 * printAt(buf,len,x,y,fgpen)
 *
 *Prive character string buf a position
 * (x,y) in a window. The character-
 * string is changed!
 *
 * buf ^ character sring.
 * len = the length.
 * x = Pixel-X-Position.
 * y = Pixel-Y-Position.
 * fgpen = Foreground color (Folding)
 *
 ************************************/

void printAt	(buf,len,x,y,fgpen)
register UBYTE	*buf;
WORD					  len;
register UWORD				x,y;
ULONG								 fgpen;
{
	struct RastPort *rp = actualEditor->rp;
	register UWORD cw = actualEditor->cw;
	register UWORD x2;
	UWORD y2 = y + actualEditor->ch - 1;
	UBYTE *ptr;
	ULONG l;

	while (len > 0)
		if (*buf == ' ')
		{
			/* output spaces: */
			x2 = x - 1;

			while ((*buf == ' ') && len--)
			{
				buf++;
				x2 += cw;
			}

			SetAPen(rp,BGPEN);
			RectFill(rp,(ULONG)x,(ULONG)y,(ULONG)x2,(ULONG)y2);
			SetAPen(rp,fgpen);

			x = ++x2;
		}
		else
		{
			/* Also output text: */
			Move(rp,(ULONG)x,(ULONG)y + actualEditor->bl);
			ptr = buf;

			if (CONTROLCODE(*buf))
			{
				SetAPen(rp,CTRLPEN);

				while (CONTROLCODE(*buf) && len--)
					*buf++ |= 64;
				l = buf - ptr;
				Text(rp,ptr,l);

				SetAPen(rp,fgpen);
			}
			else
			{
				while (!CONTROLCODE(*buf) && (*buf != ' ') && len--)
					buf++;
				l = buf - ptr;
				Text(rp,ptr,l);
			}
			x += cw*l;
		}
}
/*#ENDFD*/
/*#FOLD: printLine */
/************************************
 *
 * printLine(line,y)
 *
 * Displays Zline at pixel position
 *y on the screen.
 *
 * line ^ Zline structure.
 * y = pixel positon.
 *
 ************************************/

void printLine			 (line,y)
register struct Zline *line;
register UWORD					  y;
{
	static UBYTE buf[MAXWIDTH];

	if (line)
	{
		register struct Zline *z;
		register UBYTE *p1,*p2;
		register UWORD w;
		register ULONG pen;
		UBYTE lc;

		/* Test, if line even edited: */
		if (line->flags & ZLF_USED)
		{
			/* Buffer copies to  buf,since  printAt changed this! */
			if (MAXWIDTH > actualEditor->leftpos)
			{
				w = MAXWIDTH - actualEditor->leftpos;
				p2 = actualEditor->buffer + actualEditor->leftpos;

				p1 = buf;
				while (w)
				{
					*p1 = *p2;
					p1++;
					p2++;
					w--;
				}
			}
			else
				p1 = buf;

			/* fill rest from lastchar : */
			p2 = buf + (w = actualEditor->wcw);
			lc = actualEditor->buflastchar;
			while (p1 < p2)
			{
				*p1 = lc;
				p1++;
			}
		}
		else
			convertLineForPrint(line+1,line->len,
								  	w = actualEditor->wcw,buf,&lc);

		/* If start/end marker of fold => FOLDPEN */
		if (line->flags & ZLF_FSE)
		{
			if ((z = line->succ)->succ)
			{
				if ((z->flags & ZLF_FOLD) <= actualEditor->maxfold)
				{
					SetAPen(actualEditor->rp,FOLDPEN);
					pen = FOLDPEN;
				}
				else
					pen = FGPEN;
			}
			else
			{
				SetAPen(actualEditor->rp,FOLDPEN);
				pen = FOLDPEN;
			}

			printAt(buf,w - SplitDec,actualEditor->xoff,y,pen);

			/* Old write color first again: */
			if (pen != FGPEN)
				SetAPen(actualEditor->rp,FGPEN);
		}
		else
			printAt(buf,w - SplitDec,actualEditor->xoff,y,FGPEN);
	}
	else
	{
		/* if no  line => erase in window: */
		struct RastPort *rp = actualEditor->rp;

		SetAPen(rp,BGPEN);
		RectFill(rp,(ULONG)actualEditor->xoff,
						(ULONG)y,
						(ULONG)actualEditor->xscr,
						(ULONG)y + actualEditor->ch - 1);
		SetAPen(rp,FGPEN);
	}
}
/*#ENDFD*/
/*#FOLD: printAll */
/**********************************
 *
 * printAll
 *
 * print new screen.
 *
 **********************************/

void printAll()
{
	register UWORD y,ch,count;
	register struct Zline **z;
	register struct RastPort *rp;

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

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

	/* erase right and bottom border: */
	SetAPen(rp,BGPEN);
	if (actualEditor->yru >= y)
		RectFill(rp,(ULONG)actualEditor->xoff,(ULONG)y,
						(ULONG)actualEditor->xrr,(ULONG)actualEditor->yru);
	if ((actualEditor->xrr >= actualEditor->xrl)
		&& (y > actualEditor->yoff))
		RectFill(rp,(ULONG)actualEditor->xrl,(ULONG)actualEditor->yoff,
						(ULONG)actualEditor->xrr,(ULONG)y-1);
	SetAPen(rp,FGPEN);
}
/*#ENDFD*/
/*#FOLD: cn_utoa */
/******************************
 *
 * cn_utoa(buf,val,len):
 *
 * Convert UWORD in ASCII.
 *
 * buf ^ buffer for ASCII.
 * val = Value
 * len = Maximum Lenght.
 *
 ******************************/

void cn_utoa();

#asm

	cseg
	public _cn_utoa

_cn_utoa:

	; 4(sp) ^ Buffer,
	; 8(sp) = Value,
	;10(sp) = maximum Lenght.

	lea		4(sp),a0
	move.l	(a0)+,a1
	moveq		#0,d0
	move.w	(a0)+,d0			; = Value
	move.w	(a0),d1			; = maximum Lenght
	lea		0(a1,d1.w),a0	; ^ End of Buffers
	bra.s		.in

.lp:
	divu		#10,d0
	swap		d0
	add.b		#'0',d0			; d0.w = VAlue MOD 10
	move.b	d0,-(a0)
	clr.w		d0
	swap		d0			; Zero-Flag is 1, when d0.l = 0
.in:
	dbeq		d1,.lp			; solange bis Wert = 0 oder String voll
	beq.s		.ib			; Value = 0 => Rest is full of blanks
	bra.s		.r			; String full!

.bl:
	move.b	#' ',-(a0)
.ib:
	dbra		d1,.bl
.r:
	rts

#endasm
/*#ENDFD*/
/*#FOLD: printXpos */
/*****************************
 *
 * printXpos:
 *
 * Give Xpos of cursor.
 *
 *****************************/

void printXpos()
{
	register struct TextFont *oldFont;
	register struct Editor *ae = actualEditor;

	cn_utoa(ae->gi_Text + INFO_XPOS_INC,ae->xpos,(UWORD)INFO_XPOS_LEN);

	oldFont = ae->rp->Font;
	SetFont(ae->rp,infoFont);
	Move(ae->rp,ae->ip_xpos,ae->ip_topedge);
	Text(ae->rp,ae->gi_Text + INFO_XPOS_INC,(ULONG)INFO_XPOS_LEN);
	SetFont(ae->rp,oldFont);
}
/*#ENDFD*/
/*#FOLD: printYpos */
/*****************************
 *
 * printYpos:
 *
 * Give Ypos of cursor.
 *
 *****************************/

void printYpos()
{
	register struct TextFont *oldFont;
	register struct Editor *ae = actualEditor;

	cn_utoa(ae->gi_Text + INFO_YPOS_INC,ae->ypos,(UWORD)INFO_YPOS_LEN);

	oldFont = ae->rp->Font;
	SetFont(ae->rp,infoFont);
	Move(ae->rp,ae->ip_ypos,ae->ip_topedge);
	Text(ae->rp,ae->gi_Text + INFO_YPOS_INC,(ULONG)INFO_YPOS_LEN);
	SetFont(ae->rp,oldFont);
}
/*#ENDFD*/
/*#FOLD: printNumLines */
/*****************************
 *
 * printNumLines:
 *
 * Give number of lines
 * of text
 *
 *****************************/

void printNumLines()
{
	register struct TextFont *oldFont;
	register struct Editor *ae = actualEditor;

	cn_utoa(ae->gi_Text + INFO_NUMOFLINES_INC,ae->num_lines,
			  (UWORD)INFO_NUMOFLINES_LEN);

	oldFont = ae->rp->Font;
	SetFont(ae->rp,infoFont);
	Move(ae->rp,ae->ip_numzlines,ae->ip_topedge);
	Text(ae->rp,ae->gi_Text + INFO_NUMOFLINES_INC,
		  (ULONG)INFO_NUMOFLINES_LEN);
	SetFont(ae->rp,oldFont);
}
/*#ENDFD*/
/*#FOLD: printFold */
/********************************
 *
 * printFold:
 *
 * Gives  minfold and maxfold display.
 * 
 ********************************/

void printFold()
{
	register struct TextFont *oldFont;
	register struct Editor *ae = actualEditor;

	cn_utoa(ae->gi_Text + INFO_MINFOLD_INC,ae->minfold,
			  (UWORD)INFO_MINFOLD_LEN);
	cn_utoa(ae->gi_Text + INFO_MAXFOLD_INC,ae->maxfold,
			  (UWORD)INFO_MAXFOLD_LEN);

	oldFont = ae->rp->Font;
	SetFont(ae->rp,infoFont);
	Move(ae->rp,ae->ip_minfold,ae->ip_topedge);
	Text(ae->rp,ae->gi_Text + INFO_MINFOLD_INC,(ULONG)INFO_MINFOLD_LEN);
	Move(ae->rp,ae->ip_maxfold,ae->ip_topedge);
	Text(ae->rp,ae->gi_Text + INFO_MAXFOLD_INC,(ULONG)INFO_MAXFOLD_LEN);
	SetFont(ae->rp,oldFont);
}
/*#ENDFD*/
/*#FOLD: printFlags */
/*****************************
 *
 * printFlags:
 *
 * At Ypos of cursor.
 *
 *****************************/

void printFlags()
{
	register struct TextFont *oldFont;
	register struct Editor *ae = actualEditor;
	register UBYTE *fs = ae->gi_Text + INFO_FLAGS_INC;

	if (ae->insert)
		*fs++ = 'I';
	else
		*fs++ = 'O';
	if (ae->changed)
		*fs++ = 'C';
	else
		*fs++ = 'c';
	if (ae->autoindent)
		*fs++ = 'A';
	else
		*fs++ = 'a';
	if (ae->tabs)
		*fs++ = 'T';
	else
		*fs++ = 't';
	if (ae->skipblanks)
		*fs = 'B';
	else
		*fs = 'b';

	oldFont = ae->rp->Font;
	SetFont(ae->rp,infoFont);
	Move(ae->rp,ae->ip_flags,ae->ip_topedge);
	Text(ae->rp,ae->gi_Text + INFO_FLAGS_INC,(ULONG)INFO_FLAGS_LEN);
	SetFont(ae->rp,oldFont);
}
/*#ENDFD*/
/*#FOLD: printInfo */
/****************************
 *
 * printInfo:
 *
 * Gives new  Infoline.
 *
 ****************************/

void printInfo()
{
	printXpos();
	printYpos();
	printNumLines();
	printFold();
	printFlags();
}
/*#ENDFD*/
