/*******************************\
* EDIT.C			*
* (C)1986, Patrick E. Hughes	*
\*******************************/

#include <exec/lists.h>
#include <exec/nodes.h>
#include <setjmp.h>
#include "system.h"
#include "defines.h"

#define MAXLINES 100
#define NT_EDITHEAD 15L
#define NT_EDITFREE 16L
#define NT_EDITUSED 17L
#define LINE_LENGTH 75
#define WRAP_MAX 15

extern struct System System;
extern int Whence_The_Logon;

extern jmp_buf Environment;

static char *Buffer, *Current;
static int Size, Char_Count, Line, MaxLines;

static struct List The_Header;

static struct Line_Node
	{
	struct Node L_Node;
	char L_Data[81];
	} The_Lines[100];

/***************\
* EDIT()	*
\***************/
int Edit(bp,size,maxline,type)
	char *bp;   
	short size,maxline,type;
{
struct Line_Node *lnp;
short i;
int stat, number;
char c;
char *begin;
char string[133];

Buffer=bp;
Current=bp;
Size=size-100;
Char_Count=0;
MaxLines=maxline;
Line=1;

if(type==0)
	{
	Init_Lines();
	Clear_Buffer();
	}
else
	{
	Init_Lines();
	Realign_Lines();
	List_Lines();
	}

PutStr("\r\nEnter a blank line to end input\r\n\r\n");

stat=Enter();
if(stat<0) { longjmp(Environment,stat); }

FOREVER
	{
PutStr("\r\nA>bort  C>ontinue  D>elete-line  E>dit-line F>ree-space\r\n");
PutStr("L>ist  R>etype-last-line  S>ave\r\n");
	PutStr("Edit Options? :");
	switch (c = ReadChar(120L))
		{
		case 'a': /* ABORT */
		case 'A': /* QUIT  */
		case 'q':
		case 'Q':
			if (Abort() == 0) { return(-1); }
			break;
		case 'C': /* CONTINUE */
		case 'c':
			PutStr("Continue writing\r\n");
			stat=Enter();
			if(stat<0) { return(stat); }
			break;
		case 'd': /* DELETE */
		case 'D':
			if(Line==1)
				{
				PutStr("Nothing entered yet to Delete\r\n");
				break;
				}
			PutStr("Delete a Line\r\n");
			sprintf(string,"[1..%d] ",Line-1);
			PutStr(string);
			number=NumberInput();
			if(number==0) { break; }
			if(!(number<Line))
				{
				PutStr("Too high a number\r\n");
				break;
				}
			Delete_Line(number);
			break;
		case 'e': /* EDIT */
		case 'E':
			if(Line==1)
				{
				PutStr("Nothing entered yet to Edit\r\n");
				break;
				}
			PutStr("Edit a Line\r\n");
			sprintf(string,"[1..%d] ",Line-1);
			PutStr(string);
			number=NumberInput();
			if(number==0) { break; }
			if(!(number<Line))
				{
				PutStr("Too high a number\r\n");
				break;
				}
			Edit_Line(number);
			break;
		case 'f': /* FREE SPACE */
		case 'F':
			PutStr("Free Space\r\n");
			Free_Space();
			break;
		case 'h': /* HELP IN A BIG WAY */
		case 'H':
			PutStr("Help\r\n");
			strcpy(string,System.Location);
			strcat(string,"Edit.Help");
			MenuSend(string);
			break;
		case 'l':
		case 'L':
			PutStr("List\r\n");
			List_Lines();
			break;
		case 'r': /* RETYPE */
		case 'R':
			if(Line==1)
				{
				PutStr("Nothing entered yet to edit\r\n");
				break;
				}
			PutStr("Retype last line\r\n");
			Retype_Line();
			break;
		case 'S':
		case 's':
			PutStr("Save\r\n");
			*Buffer='\0';
			for(lnp=The_Header.lh_Head;
			    lnp->L_Node.ln_Succ;
			    lnp=lnp->L_Node.ln_Succ)
				{
				strcat(Buffer,lnp->L_Data);
				strcat(Buffer,"\n");
				}
			return(Char_Count);
			break;
		case '?':
		case '/':
			PutStr("Help\r\n");
			Help();
			break;
		case TIMEOUT:
			longjmp(Environment,TIMEOUT);
			break;
		default :
			PutStr("\r\n");
			break;   
		}
	}
}

/***********************\
* FIND_FREE_LINE()	*
\***********************/
static int Find_Free_Line()
{
int x;

for(x=0;x<MAXLINES;++x)
	{
	if(The_Lines[x].L_Node.ln_Type==NT_EDITFREE) { return(x); }
	}

return(-1);
}

/***********************\
* INIT_LINES()		*
\***********************/
static int Init_Lines()
{
int x;

The_Header.lh_Head=&The_Header.lh_Tail;
The_Header.lh_TailPred=&The_Header.lh_Head;
The_Header.lh_Type=NT_EDITHEAD;
The_Header.lh_Tail=NULL;

for(x=0;x<MAXLINES;++x)
	{
	The_Lines[x].L_Node.ln_Succ=NULL;
	The_Lines[x].L_Node.ln_Pred=NULL;
	The_Lines[x].L_Node.ln_Type=NT_EDITFREE;
	}
}

/***********************\
* LIST_LINES()		*
\***********************/
static int List_Lines()
{
struct Line_Node *lnp;
char string[133];
int count;

if(Line==1) { return(); }

for(count=1,lnp=The_Header.lh_Head;lnp->ln_Succ!=NULL;lnp=lnp->ln_Succ,++count)
	{
	sprintf(string,"%3d>%s\r\n",count,lnp->L_Data);
	PutStr(string);
	}

PutStr("\r\n");
}

/***********************\
* REALIGN_LINES()	*
\***********************/
static int Realign_Lines()
{
char *origin, c;
int freenode;

FOREVER
	{
	origin=Current;
	while( c=*Current && (freenode=Find_Free_Line())>=0 )
		{
		++Char_Count;
		if(Char_Count>=2299) { break; }
		if(c=='\n')
			{
			++Line;
			*Current='\0';
			strcpy(The_Lines[freenode].L_Data,origin);
			*Current++='\n';
			The_Lines[freenode].L_Node.ln_Type=NT_EDITUSED;
			}
		}
	}
}

/***************\
* RETYPE_LINE()	*
\***************/
static int Retype_Line()
{
struct Line_Node *nptr;
int x, oldlen, newlen, which;

which=Line-1;

if(Line==1)
	{
	PutStr("Nothing entered to retype\r\n\r\n");
	return();
	}

x=0;
nptr=The_Header.lh_Head;
while(++x!=which) { nptr=nptr->L_Node.ln_Succ; }

oldlen=strlen(nptr->L_Data);
newlen=LineInput(nptr->L_Data,nptr->L_Data,75,120L);
if(newlen<0) { return(newlen); }
Char_Count+= (newlen-oldlen);
}

/***********************\
* CLEAR_BUFFER		*
\***********************/
static int Clear_Buffer()
{
int x;
char *ptr;

for (ptr=Buffer,x=0;x<Size;++x) { *ptr='\0'; }
}

/***************\
* EDIT_LINE()	*
\***************/
static int Edit_Line(which)
	int which;
{
struct The_Lines *nptr;
int x, oldlen, newlen;

x=0;
nptr=The_Header.lh_Head;
while(++x!=which) { nptr=nptr->L_Node.ln_Succ; }

oldlen=strlen(nptr->L_Data);
newlen=LineInput(nptr->L_Data,nptr->L_Data,75,120L);
if(newlen<0) { return(newlen); }
Char_Count+= (newlen-oldlen);
}

/***************\
* FREE_SPACE()	*
\***************/
static int Free_Space()
{
char str[133];

sprintf(str,"[%d] bytes Free, out of [%d] Total\r\n",Size-Char_Count,Size);
PutStr(str);
PutStr("\r\n");
}

/***************\
* HELP()	*
\***************/
static int Help()
{
PutStr("\r\n");
PutStr("\ta,A - Abort and not save\r\n");
PutStr("\tc,C - Continue writing\r\n");
PutStr("\te,E - Edit a previous line\r\n");
PutStr("\tf,F - Free space left\r\n");
PutStr("\th,H - Detailed Help\r\n");
PutStr("\tl,L - List the text\r\n");
PutStr("\tr,R - Retype the last line immediately\r\n");
PutStr("\ts,S - Store current text\r\n");
PutStr("\t ?  - Help (this display)\r\n\r\n");
PutStr("\r\nWhile Entering Text:\r\n");
PutStr("\t^X - Erase Entire Line\r\n");
PutStr("\t^W - Erase Last Word\r\n");
}

/***************\
* DELETE_LINE()	*
\***************/
static int Delete_Line(which)
	int which;
{
struct The_Lines *nptr;
int x, oldlen, newlen;

x=0;
nptr=The_Header.lh_Head;
while(++x!=which) { nptr=nptr->L_Node.ln_Succ; }

Remove(nptr);
nptr->L_Node.ln_Type=NT_EDITFREE;
--Line;
Char_Count-=strlen(nptr->L_Data);
}

/***************\
* ABORT()	*
\***************/
static int Abort()
{
int c;

PutStr("Are you sure you wish to Abort message (y,n)?\r\n");

FOREVER{
	if(((c = ReadChar(120L)) == 'y') || (c == 'Y')){
		PutStr("Yes\r\n");
		return(0);
	}
	if((c == 'n') || (c == 'N') || (c == '\n')){
		PutStr("NO!\r\n");
		return(1);
	}
	if(c==TIMEOUT) { longjmp(Environment,TIMEOUT); }
}  
}

/***************\
* ENTER()	*
\***************/
static int Enter()
{
struct Line_Node *lnp;
int freenode;
int x, char_count, column, line, wrapcount;
static char string[81], wrapbuf[81], inputbuf[81];
int newchar, oldchar;
char *wrap;

column=0;
wrapbuf[0]='\0';
inputbuf[0]='\0';
string[0]='\0';
newchar='\0';
oldchar='\0';

do
	{
	lnp=&The_Lines[Find_Free_Line()];
	sprintf(string,"%3d>",Line);
	PutStr(string);
	column=0;

	if( (x=strlen(wrapbuf)) >0 )
		{
		if( (x+Char_Count) > Size ) { break; }
		strcpy(inputbuf,wrapbuf);
		Char_Count+=x;
		column+=x;
		PutStr(wrapbuf);
		wrapbuf[0]='\0';
		}

	while ((Char_Count < Size) && (column<LINE_LENGTH))
		{
		newchar=ReadChar(120L);
		if(newchar<0) { longjmp(Environment,SLEEP_LOGOFF); }
		newchar&=0x7f;

		if(newchar=='\r')	/* RETURN */
			{
			if(Whence_The_Logon>=REMOTE_LOGON)
				{
				if((CheckCarrier())==FALSE)
					{
					longjmp(Environment,CARRIER_LOGOFF);
					}
				}
			if(column==0)
				{
				PutStr("\r\n");
				break;
				}
			inputbuf[column]='\0';
			PutStr("\r\n");
			++Char_Count;
			++Line;
			break;
			}

		if( ((newchar=='\b')||(newchar=='\177')) && (column>0))
					/* BACKSPACE or DEL */
			{
			PutStr("\b \b");
			--column;
			--Char_Count;
			inputbuf[column]='\0';
			continue;
			}

		if(newchar=='\030')	/* CTRL-X LINE DELETE */
			{
			while(column)
				{
				PutStr("\b \b");	
				--column;
				--Char_Count;
				inputbuf[column]='\0';
				}
			continue;
			}

		if(newchar=='\027' && column>0)	/* CTRL-W WORD DELETE */
			{
			--Current;
			while( (column) && inputbuf[column]==' ')
				{
				inputbuf[column--]='\000';
				PutStr("\b \b");
				}
			while( (column) && inputbuf[column]!=' ')
				{
				inputbuf[column--]='\000';
				PutStr("\b \b");
				}
			}

		if(newchar<0) { longjmp(Environment,SLEEP_LOGOFF); }

		if( (newchar<' ') || (newchar=='\177') ) { continue; }

		SendChar(newchar);
		inputbuf[column]=(char)newchar;

		++Current;
		++column;
		++Char_Count;
		}

	if(column==LINE_LENGTH)
		{
		for(wrapcount=0,wrap=&inputbuf[column];
			(*wrap!=' ') && (wrapcount<WRAP_MAX);
			--wrap,++wrapcount) { ; }

		if(*wrap==' ')
			{
			++wrap;
			strcpy(wrapbuf,wrap);
			for(x=0;x<wrapcount;++x)
				{
				PutStr("\b \b");
				--column;
				--Char_Count;
				}
			inputbuf[column]='\0';
			PutStr("\r\n");
			}
		else
			{
			wrapbuf[0]='\0';
			inputbuf[column]='\0';
			PutStr("\r\n");
			}
		++Line;
		}
	else { wrapbuf[0]='\0'; }

	} while (  (Line<=MaxLines)
		&& (Char_Count<Size)
		&& (column!=0)
		&& (strcpy(lnp->L_Data,inputbuf))
		&& (lnp->L_Node.ln_Type=NT_EDITUSED)
		&& (AddTail(&The_Header,lnp)) );

if (Char_Count > Size)
	{
	PutStr("Message has reached maximum size\r\n");
	--Char_Count;
	}

if(!(Line<=MaxLines))
	{
	PutStr("That was the last available line\r\n");
	}

return(Char_Count);
}
