#include <ascii.h>
#include "fido.h"
#include "fidomem.h"
#include "proto.h"

char *skip_space();

/* Enter a block of text. Does word wrap, etc. Returns the highest line
written in. */

edit(ln,end_line,width,text)
int ln,end_line,width;
char *text;
{
int lastline;			/* last line number, for detecting when to display */
char c,lastc;			/* character & last character */
char rptchar;			/* # times to repeat last character 'c' */
int col;			/* logical column in current line */
FLAG x;
char word[SS * 2],*p;		/* word[] must be at least 2X max line len */
int pc;				/* index into word[] */

	col= 0;
	lastline= -1;
	if (width > SS) width= SS;
	width-= sizeof("999: ");	/* compensate for max. prompt length, */
	c= lastc= -1;			/* anything but CR */
	rptchar= 0;
	ins_line(ln,end_line,text);	/* in case we're inserting */

	while (ln < end_line) {
		if (ln != lastline) {
			line= 0;			/* override "More?" */
			mcrlf();
			p= &text[ln * SS];
			mprintf(0,"%2u: ",ln + 1);
			column= 0;			/* reset so tabs line up */
			while (*p) mconout(*p++ & 0x7f);
			lastline= ln;			/* only once each */
		}

		pc= 0;
		word[pc]= NUL;
		while (wordlen(word,col) + wordlen(&text[ln * SS],0) < width) {
			lastc= c;			/* remember last character */
			if (rptchar != 0) {		/* if repeated character */
				--rptchar;		/* count one, */

			} else c= mconin();		/* get one word */

			if (c == CR) break;		/* stop if CR, */
			if (c == DEL) c= BS;		/* DEL -> BS */
			if (c == CAN) c= ETX;		/* ^X -> ^C */

			if (c == TAB) {			/* if we get a tab, */
				rptchar= 8 - ((col + pc) % 8);
				c= ' ';			/* set the character, */
				continue;		/* then go do it */

			} else if (c == ETX) {		/* if delete line */
				rptchar= col + pc;	/* for the entire line, */
				c= BS;			/* set as back space, */
				continue;		/* go do it */

			} else if (c == ETB) {		/* Control-W */

/* Delete word backspaces until it finds a white-space followed by a
non-white space character. See the note on backspace, below. */

				x= 0;			/* 1 == seen white space */
				while (1) {
					if (pc > 0) {
						c= word[pc - 1];
						if (delim(c)) x= 1;
						else if (x) break;

						--pc; erase(1); mconout(BS);
						word[pc]= NUL;

					} else if (col > 0) {
						c= text[ln * SS + col - 1];
						if (delim(c)) x= 1;
						else if (x) break;

						--col; erase(1); mconout(BS);
						text[ln * SS + col]= NUL;

					} else break;	/* line is empty */
				}
				c= NUL;

/* If a character delete, backspace on the screen. First delete characters 
from the word we are building, if that is empty, then from the line we
are building. */

			} else if (c == BS) {
				if (pc > 0) {
					--pc; erase(1); mconout(BS);
					word[pc]= NUL;

				} else if (col > 0) {
					--col; erase(1); mconout(BS);
					text[ln * SS + col]= NUL;
				}
				continue;

/* Printable character */

			} else if (c >= ' ') {
				mconout(c);		/* stash the character */
				word[pc++]= c;		/* store until */
				word[pc]= NUL;		/* end of word or */
			}
			if (pc >= sizeof(word) - 1) break; /* max length */
			if (c == TAB) break;		/* word terminators */
			if (c == ' ') break;
			if (c == ',') break;
			if (c == ';') break;
		}

		if (wordlen(word,col) + wordlen(&text[ln * SS],0) < width) {
			strcat(&text[ln * SS],word);	/* add it if it fits, */
			col= wordlen(&text[ln * SS],0);	/* correct column */

/* When we go to the next line, insert a blank line; if we're entering
new text this is a waste of time, but if we're inserting it moves existing
text down one line. */

		} else {				/* doesnt fit */
			erase(wordlen(word,col));	/* clear last word from screen, */
			if (wordlen(&text[ln * SS],0) == 0)
				strcat(&text[ln * SS]," "); /* prevent 0 length lines */
			strcat(&text[ln * SS],"\215\n"); /* add softCR */
			++ln;				/* go to next line, */
			if (ln < end_line) ins_line(ln,end_line,text); /* insert blank line */
			strcpy(&text[ln * SS],word);	/* put word on next line */
		}
		if (c == CR) {				/* if hard return */
			strcat(&text[ln * SS],"\r\n");	/* add CR LF, */
			++ln;				/* next line */
			if (col == 0) break;		/* blank line last time */
			if (ln < end_line) ins_line(ln,end_line,text);
		}
		col= wordlen(&text[ln * SS],0);		/* correct column */
	}

/* Now find the first unused line, and return that as the next line. */

	while (text[ln * SS]) {				/* find next blank line */
		if (ln >= end_line) break;		/* dont go past the end */
		++ln;
	}
	return(ln);
}

/* Delete a line from the text array. */

del_line(n,ln,text)
int n,ln;
char *text;
{

	for ( ; n < ln; n++) 
		strcpy(&text[n * SS],&text[(n + 1) * SS]);
	text[n * SS]= NUL;
	return(--ln);
}
/* Insert a blank line. Assumes that there is at least one unused 
line at the end. */

ins_line(n,ln,text)
int n,ln;
char *text;
{
int i;

	for (i= ln; i >= n; i--) 
		strcpy(&text[(i + 1) * SS],&text[i * SS]);
	text[n * SS]= NUL;
	return(ln);
}

/* Substitute one string for another. If the line becomes too long, it
gets truncated to fit. However, the line length is the physical array length, 
80 chars, so when listed, it will adjust properly if less than that. Returns
true if the substitution was made. */

substr(s,o,n,l)
char *s;	/* string to edit */
char *o;	/* old thing to find */
char *n;	/* new thing to replace it with, */
int l;		/* max length of any string, */
{
char work[SS * 2];
int p;		/* output string position */
int m;		/* old things position in string to edit */

	--l;				/* room for a null */

	m= strfnd(s,o);			/* old things position in the text */
	if (m == -1) return(0);		/* not found */

	p= 0;				/* output string position */
	for ( ; p < m; p++) 		/* copy text up to the */
		work[p]= s[p];		/* old thing to replace, */

	for ( ; p < l; p++) {		/* copy in replacement string, */
		work[p]= *n++;
		if (! work[p]) break;	/* end of replacement or max length */
	}

	while (*o++) ++m;		/* skip to after old thing (strlen o) */

	for ( ; p < l; p++) {		/* copy the text remaining */
		work[p]= s[m++];	/* after the old thing, */
		if (! work[p]) break;	/* end of string or max length */
	}
	work[p]= NUL;			/* in case length limit hit */

	strcpy(s,work);			/* copy complete string back */
	return(1);
}

/* Erase a word. Backspace, then type spaces. */

erase(n)
int n;
{
int i;

	for (i= 0; i < n; i++) mconout(BS);
	for (i= 0; i < n; i++) mconout(' ');
}
/* Skip leading blanks. */

char *skip_space(s)
char *s;
{
	while (*s && (*s == ' ')) ++s;
	return(s);
}
