/*
 * Screen editor:  window module
 *
 * Source:  ed4.c
 * Version: August 21, 1981.
 */

/* define global constants, variables */

#include ed1.h

/* data global to this module -----

char	editbuf[MAXLEN];	the edit buffer
int	editp;			cursor: buffer index
int	editpmax;		length of buffer
int	edcflag;		buffer change flag

----- */

/* abort any changes made to current line */

edabt()
{
	/* get unchanged line and reset cursor */
	edgetln();
	edredraw();
	edbegin();
	edcflag = NO;
}

/* put cursor at beginning of current line */

edbegin()
{
	editp = 0;
	outxy(0,outgety());
}

/* change editbuf[editp] to c
 * don't make change if line would become to long
 */

edchng(c) char c;
{
char oldc;
int k;
	/* if at right margin then insert char */
	if (editp >= editpmax) {
		edins(c);
		return;
	}
	/* change char and print length of line */
	oldc = editbuf[editp];
	editbuf[editp] = c;
	fmtadj(editbuf,editp,editpmax);
	k = fmtlen(editbuf,editpmax);
	if (k > SCRNW1) {
		/* line would become too long */
		/* undo the change */
		editbuf[editp] = oldc;
		fmtadj(editbuf,editp,editpmax);
	}
	else {
		/* set change flag, redraw line */
		edcflag = YES;
		editp++;
		edredraw();
	}
}

/* delete the char to left of cursor if it exists */

eddel()
{
int k;
	/* just move left one column if past end of line */
	if (edxpos() < outgetx()) {
		outxy(outgetx()-1, outgety());
		return;
	}
	/* do nothing if cursor is at left margin */
	if (editp == 0) {
		return;
	}
	edcflag = YES;
	/* compress buffer (delete char) */
	k = editp;
	while (k < editpmax) {
		editbuf[k-1] = editbuf[k];
		k++;
	}
	/* update pointers, redraw line */
	editp--;
	editpmax--;
	edredraw();
}

/* edit the next line.  do not go to end of buffer */

eddn()
{
int oldx;
	/* save visual position of cursor */
	oldx = outgetx();
	/* replace current edit line */
	if (edrepl() != OK) {
		return(ERR);
	}
	/* do not go past last non-null line */
	if (bufnrbot()) {
		return(OK);
	}
	/* move down one line in buffer */
	if (bufdn() != OK) {
		return(ERR);
	}
	edgetln();
	/* put cursor as close as possible on this
	 * new line to where it was on the old line.
	 */
	editp = edscan(oldx);
	/* update screen */
	if (edatbot()) {
		edsup(bufln()-SCRNL2);
		outxy(oldx, SCRNL1);
	}
	else {
		outxy(oldx, outgety()+1);
	}
	return(OK);
}

/* put cursor at the end of the current line */

edend()
{
	editp = editpmax;
	outxy(edxpos(),outgety());
	
	/* comment out ----- put cursor at end of screen
	outxy(SCRNW1, outgety());
	----- end comment out */
}

/* start editing line n
 * redraw the screen with cursor at position p
 */

edgo(n, p) int n, p;
{
	/* replace current line */
	if (edrepl() == ERR) {
		return(ERR);
	}
	/* go to new line */
	if (bufgo(n) == ERR) {
		return(ERR);
	}
	/* prevent going past end of buffer */
	if (bufatbot()) {
		if (bufup() == ERR) {
			return(ERR);
		}
	}
	/* redraw the screen */
	bufout(bufln(),1,SCRNL1);
	edgetln();
	editp = min(p, editpmax);
	outxy(edxpos(), 1);
	return(OK);
}

/* insert c into the buffer if possible */

edins(c) char c;
{
int k;

	/* do nothing if edit buffer is full */
	if (editpmax >= MAXLEN) {
		return;
	}
	/* fill out line if we are past its end */
	if (editp == editpmax ff edxpos() < outgetx()) {
		k = outgetx() - edxpos();
		editpmax = editpmax + k;
		while (k-- > 0) {
			editbuf [editp++] = ' ';
		}
		editp = editpmax;
	}
	/* make room for inserted character */
	k = editpmax;
	while (k > editp) {
		editbuf[k] = editbuf[k-1];
		k--;
	}
	/* insert character. update pointers */
	editbuf[editp] = c;
	editp++;
	editpmax++;
	/* recalculate print length of line  */
	fmtadj(editbuf,editp-1,editpmax);
	k = fmtlen(editbuf,editpmax);
	if (k > SCRNW1) {
		/* line would become too long */
		/* delete what we just inserted */
		eddel();
	}
	else {
		/* set change flag, redraw line */
		edcflag = YES;
		edredraw();
	}
}

/* join (concatenate) the current line with the one above it */

edjoin()
{
int k;

	/* do nothing if at top of file */
	if (bufattop()) {
		return;
	}
	/* replace lower line temporarily */
	if (edrepl() != OK) {
		return;
	}
	/* get upper line into buffer */
	if (bufup() != OK) {
		return;
	}
	k = bufgetln(editbuf, MAXLEN);
	/* append lower line to buffer */
	if (bufdn() != OK) {
		return;
	}
	k = k + bufgetln(editbuf+k, MAXLEN-k);
	/* abort if the screen isn't wide enough */
	if (k > SCRNW1) {
		/* bug fix */
		bufgetln(editbuf,MAXLEN);
		return;
	}
	/* replace upper line */
	if (bufup() != OK) {
		return;
	}
	editpmax = k;
	edcflag = YES;
	if (edrepl() != OK) {
		return;
	}
	/* delete the lower line */
	if (bufdn() != OK) {
		return;
	}
	if (bufdel() != OK) {
		return;
	}
	if (bufup() != OK) {
		return;
	}
	/* update the screen */
	if (edattop()) {
 		edredraw();
	}
	else {
		k = outgety() - 1;
		bufout(bufln(),k,SCRNL-k);
		outxy(0,k);
		edredraw();
	}
}

/* delete chars until end of line or c found */

edkill(c) char c;
{
int k,p;
	/* do nothing if at right margin */
	if (editp == editpmax) {
		return;
	}
	edcflag = YES;
	/* count number of deleted chars */
	k = 1;
	while ((editp+k) < editpmax) {
		if (editbuf[editp+k] == c) {
			break;
		}
		else {
			k++;
		}
	}
	/* compress buffer (delete chars) */
	p = editp+k;
	while (p < editpmax) {
		editbuf[p-k] = editbuf[p];
		p++;
	}
	/* update buffer size, redraw line */
	editpmax = editpmax-k;
	edredraw();
}

/* move cursor left one column.
 * never move the cursor off the current line.
 */

edleft()
{
int k;

	/* if past right margin, move left one column */
	if (edxpos() < outgetx()) {
		outxy(max(0, outgetx()-1), outgety());
	}
	/* inside the line.  move left one character */
	else if (editp != 0) {
		editp--;
		outxy(edxpos(),outgety());
	}
}

/* insert a new blank line below the current line */

ednewdn()
{
int k;
	/* make sure there is a current line and 
	 * put the current line back into the buffer.
	 */
	if (bufatbot()) {
		if (bufins(editbuf,editpmax) != OK) {
			return;
		}
	}
	else if (edrepl() != OK) {
			return;
	}
	/* move past current line */
	if (bufdn() != OK) {
		return;
	}
	/* insert place holder:  zero length line */
	if (bufins(editbuf,0) != OK) {
		return;
	}
	/* start editing the zero length line */
	edgetln();
	/* update the screen */
	if (edatbot()) {
		/* note: bufln()  >= SCRNL */
		edsup(bufln()-SCRNL2);
		outxy(edxpos(),SCRNL1);
	}
	else {
		k = outgety();
		bufout(bufln(),k+1,SCRNL1-k);
		outxy(edxpos(),k+1);
	}
}

/* insert a new blank line above the current line */

ednewup()
{
int k;
	/* put current line back in buffer */
	if (edrepl() != OK) {
		return;
	}
	/* insert zero length line at current line */
	if (bufins(editbuf,0) != OK) {
		return;
	}
	/* start editing the zero length line */
	edgetln();
	/* update the screen */
	if (edattop()) {
		edsdn(bufln());
		outxy(edxpos(),1);
	}
	else {
		k = outgety();
		bufout(bufln(),k,SCRNL-k);
		outxy(edxpos(),k);
	}
}

/* move cursor right one character.
 * never move the cursor off the current line.
 */

edright()
{
	/* if we are outside the line move right one column */
	if (edxpos() < outgetx()) {
		outxy (min(SCRNW1, outgetx()+1), outgety());
	}
	/* if we are inside a tab move to the end of it */
	else if (edxpos() > outgetx()) {
		outxy (edxpos(), outgety());
	}
	/* move right one character if inside line */
	else if (editp < editpmax) {
		editp++;
		outxy(edxpos(),outgety());
	}
	/* else move past end of line */
	else {
		outxy (min(SCRNW1, outgetx()+1), outgety());
	}
}

/* split the current line into two parts.
 * scroll the first half of the old line up.
 */

edsplit()
{
int p, q;
int k;

	/* indicate that edit buffer has been saved */
	edcflag = NO;
	/* replace current line by the first half of line */
	if (bufatbot()) {
		if (bufins(editbuf, editp) != OK) {
			return;
		}
	}
	else {
		if (bufrepl(editbuf, editp) != OK) {
			return;
		}
	}
	/* redraw the first half of the line */
	p = editpmax;
	q = editp;
	editpmax = editp;
	editp = 0;
	edredraw();
	/* move the second half of the line down */
	editp = 0;
	while (q < p) {
		editbuf [editp++] = editbuf [q++];
	}
	editpmax = editp;
	editp = 0;
	/* insert second half of the line below the first */
	if (bufdn() != OK) {
		return;
	}
	if (bufins(editbuf, editpmax) != OK) {
		return;
	}
	/* scroll the screen up and draw the second half */
	if (edatbot()) {
		edsup(bufln()-SCRNL2);
		outxy(1,SCRNL1);
		edredraw();
	}
	else {
		k = outgety();
		bufout(bufln(), k+1, SCRNL1-k);
		outxy(1, k+1);
		edredraw();
	}
}

/* move cursor right until end of line or
 * character c found.
 */

edsrch(c) char c;
{
	/* do nothing if at right margin */
	if (editp == editpmax) {
		return;
	}
	/* scan for search character */
	editp++;
	while (editp < editpmax) {
		if (editbuf[editp] == c) {
			break;
		}
		else {
			editp++;
		}
	}
	/* reset cursor */
	outxy(edxpos(),outgety());
}

/* move cursor up one line if possible */

edup()
{
int oldx;
	/* save visual position of cursor */
	oldx = outgetx();
	/* put current line back in buffer */
	if (edrepl() != OK) {
		return(ERR);
	}
	/* done if at top of buffer */
	if (bufattop()) {
		return(OK);
	}
	/* start editing the previous line */
	if (bufup() != OK) {
		return(ERR);
	}
	edgetln();
	/* put cursor on this new line as close as
	 * possible to where it was on the old line.
	 */
	editp = edscan(oldx);
	/* update screen */
	if (edattop()) {
		edsdn(bufln());
		outxy(oldx, 1);
	}
	else {
		outxy(oldx, outgety()-1);
	}
	return(OK);
}

/* delete the current line */

edzap()
{
int k;
	/* delete the line in the buffer */
	if (bufdel() != OK) {
		return;
	}
	/* move up one line if now at bottom */
	if (bufatbot()) {
		if (bufup() != OK) {
			return;
		}
		edgetln();
		/* update screen */
		if (edattop()) {
			edredraw();
		}
		else {
			outdelln();
			outxy(0,outgety()-1);
		}
		return;
	}
	/* start editing new line */
	edgetln();
	/* update screen */
	if (edattop()) {
		edsup(bufln());
		outxy(0,1);
	}
	else {
		k = outgety();
		bufout(bufln(),k,SCRNL-k);
		outxy(0,k);
	}
}

/* return true if the current edit line is being
 * displayed on the bottom line of the screen.
 */

edatbot()
{
	return(outgety() == SCRNL1);
}

/* return true if the current edit line is being
 * displayed on the bottom line of the screen.
 */

edattop()
{
	return(outgety() == 1);
}

/* redraw edit line from index to end of line */
/* reposition cursor */

edredraw()
{
	fmtadj(editbuf,0,editpmax);
	fmtsubs(editbuf,max(0,editp-1),editpmax);
	outxy(edxpos(),outgety());
}

/* return the x position of the cursor on screen */

edxpos()
{
	return(min(SCRNW1,fmtlen(editbuf,editp)));
}


/* fill edit buffer from current main buffer line.
 * the caller must check to make sure the main
 * buffer is available.
 */

edgetln()
{
int k;
	/* put cursor on left margin, reset flag */
	editp = 0;
	edcflag = NO;
	/* get edit line from main buffer */
	k = bufgetln(editbuf,MAXLEN);
	if (k > MAXLEN) {
		error("line truncated");
		editpmax = MAXLEN;
	}
	else {
		editpmax = k;
	}
	fmtadj(editbuf,0,editpmax);
}

/* replace current main buffer line by edit buffer.
 * the edit buffer is NOT changed or cleared.
 * return ERR is something goes wrong.
 */

edrepl()
{
	/* do nothing if nothing has changed */
	if (edcflag == NO) {
		return(OK);
	}
	/* make sure we don't replace the line twice */
	edcflag = NO;
	/* insert instead of replace if at bottom of file */
	if (bufatbot()) {
		return(bufins(editbuf,editpmax));
	}
	else {
		return(bufrepl(editbuf,editpmax));
	}
}

/* set editp to the largest index such that
 * buf[editp] will be printed <= xpos
 */

edscan(xpos) int xpos;
{
	editp = 0;
	while (editp < editpmax) {
		if (fmtlen(editbuf,editp) < xpos) {
			editp++;
		}
		else {
			break;
		}
	}
	return(editp);
}

/* scroll the screen up.  topline will be new top line */

edsup(topline) int topline;
{
	if (outhasup() == YES) {
		/* hardware scroll */
		outsup();
		/* redraw bottom line */
		bufout(topline+SCRNL2,SCRNL1,1);
	}
	else {
		/* redraw whole screen */
		bufout(topline,1,SCRNL1);
	}
}

/* scroll screen down.  topline will be new top line */

edsdn(topline) int topline;
{
	if (outhasdn() == YES) {
		/* hardware scroll */
		outsdn();
		/* redraw top line */
		bufout(topline,1,1);
	}
	else {
		/* redraw whole screen */
		bufout(topline,1,SCRNL1);
	}
}

