#include <libraries/zbbs.h>
#include "protos.h"
#include "globals.c"

BOOL LineEditor(STRPTR);
BOOL FullScreenEditor(STRPTR, STRPTR, STRPTR);
VOID RedrawFullScreen(STRPTR, STRPTR, struct Line *);
VOID MeltLines(STRPTR, STRPTR);
VOID RefreshFullScreen(struct Line *);

BOOL Editor(STRPTR filename, STRPTR to, STRPTR subject)
{
	switch(User.editor)
	{
		case 1:
			return(FullScreenEditor(filename, to, subject));
			break;

		default:
			return(LineEditor(filename));
			break;
	}
}

BOOL LineEditor(STRPTR filename)
{
	struct List LineList;
	struct Line *entry;
	LONG line;
	BOOL stop;

	Location("Zeilen Editor");

	NewList(&LineList);
	ClrScr();

	stop = FALSE;
	wait_buffer[0] = 'E';
	do
	{
		switch(toupper(wait_buffer[0]))
		{
			case 'L':
				line = 1;
				entry = GetHead(&LineList);
				while(entry)
				{
					color(CYAN);
					MyPrintf("%2ld>", line++);
					color(WHITE);
					MyPrintf("%ls\r\n", entry->text);

					entry = GetSucc(entry);
					if(CheckIO(ReadCON))
					{
						WaitIO(ReadCON);
						QueueConsole();
						entry = NULL;
						MyPrintf("<Abbruch>\r\n");
					}
					if(CheckIO(ReadSER))
					{
						WaitIO(ReadSER);
						QueueSerial();
						entry = NULL;
						MyPrintf("<Abbruch>\r\n");
					}
				}
				break;

			case 'S':
				if(entry = GetHead(&LineList))
				{
					BPTR FH;

					if(FH = Open(filename, MODE_NEWFILE))
					{
						while(entry)
						{
							FPrintf(FH, "%ls\r\n", entry->text);
							entry = GetSucc(entry);
						}
						Close(FH);

						RemList(&LineList);
						return(TRUE);
					}
					else	SendError("Editor", "couldn't save this file !");
				}
				else
				{
					color(RED);
					MyPrintf("Leere Nachricht nicht gespeichert.\r\n");
				}
				stop = TRUE;
				break;

			case 'E':
				line = 1;
				entry = GetHead(&LineList);
				while(entry)
				{
					line++;
					entry = GetSucc(entry);
				}

				MyPrintf("\r\n\r\nMit '.' in neuer Zeile abbrechen.\r\n");
				stop = FALSE;
				wait_buffer[0] = 0;
				do
				{
					color(CYAN);
					MyPrintf("\r\n%2ld>", line++);
					color(WHITE);
					In(76, 4);
					if(!connected && !login)	goto exit;
	
					if(!strcmp(wait_buffer, "."))	stop = TRUE;
					else
					{
						if(entry = GetLine())
						{
							strcpy(entry->text, wait_buffer);
							wait_buffer[0] = 0;
							if(strlen(entry->text) > 75)
							{
								STRPTR ptr;

								ptr = strrchr(entry->text, ' ');
								if(strrchr(entry->text, '-') > ptr)
									ptr = strrchr(entry->text, '-');
								if(ptr)
								{
									LONG i;

									strcpy(wait_buffer, ptr + 1);
									i = strlen(wait_buffer);
									while(i--);	Backspace();

									if(*ptr == '-')	ptr++;
									*ptr = 0;
								}
							}

							AddTail(&LineList, entry);
						}
						else	SendError("LineEditor", "couldn't allocate memory");
					}
				}	while(!stop && (connected || login) && entry);
				stop = FALSE;
				Return();
				break;

			case 'D':
				Ask("Zeile löschen : ", NULL, 5, TRUE);
				if(!connected && !login)	goto exit;

				if((entry = GetHead(&LineList)) && (line = atol(wait_buffer)))
				{
					line--;
					while(line-- && entry)	entry = GetSucc(entry);
					line++;

					if(entry && !line)
					{
						color(CYAN);
						MyPrintf("%2ld>", atol(wait_buffer));
						color(WHITE);
						MyPrintf("%ls\r\n", entry->text);

						Ask("Diese Zeile löschen [Y/n] : ", NULL, HOTKEY, TRUE);
						if(!connected && !login)	goto exit;
						if(toupper(wait_buffer[0]) != 'N')
						{
							Remove(entry);
							FreeVec(entry);

							color(YELLOW);
							MyPrintf("Die Zeile wurde gelöscht.\r\n");
						}
					}
					else
					{
						color(YELLOW);
						MyPrintf("Zeile nicht gefunden.\r\n");
					}
				}
				else
				{
					color(YELLOW);
					MyPrintf("Keine Zeilen zum löschen.\r\n");
				}
				break;

			case 'I':
				Ask("Nach welcher Zeile einfügen : ", NULL, 5, TRUE);
				if((line = atol(wait_buffer)) && (entry = GetHead(&LineList)))
				{
					line--;
					while(line-- && entry)	entry = GetSucc(entry);
					line++;

					if(entry)
					{
						struct Line *e;

						if(e = GetLine())
						{
							Insert(&LineList, e, entry);
							color(GREEN);
							MyPrintf("Die Zeile wurde eingefügt.\r\n");
						}
						else	SendError("LineEditor", "couldn't allocate memory");
					}
					else
					{
						color(YELLOW);
						MyPrintf("Es ist nicht möglich hier eine Zeile einzufügen.\r\n");
					}
				}
				else
				{
					if(wait_buffer[0] == '0')
					{
						if(entry = GetLine())
						{
							AddHead(&LineList, entry);
							color(GREEN);
							MyPrintf("Die Zeile wurde eingefügt.\r\n");
						}
						else	SendError("LineEditor", "couldn't allocate memory");
					}
				}
				break;

			case '?':
			case 0:
				ClrScr();
				ShowFile("%lsEditorMenu.txt", Config.text);
				if(!connected && !login)	goto exit;
				break;

			case 'C':
				ChatRequest();
				break;

			case 'M':
			case 'Z':
				if(GetHead(&LineList))
					Ask("Willst Du die Message nicht erst [S]aven [Y/n] ", NULL, HOTKEY, TRUE);
				if(toupper(wait_buffer[0]) == 'N' || !GetHead(&LineList))
				{
					Location("Editor Ende");
					stop = TRUE;
				}
				break;

			case 'G':
				if(GetHead(&LineList))
					Ask("Willst Du die Nachricht nicht erst [S]aven [Y/n] ", NULL, HOTKEY, TRUE);
				if(toupper(wait_buffer[0]) == 'N' || !GetHead(&LineList))
				{
					Goodbye();
				}
				if(!connected && !login)	goto exit;
				break;

			default:
				stop = FALSE;
				if((line = atol(wait_buffer)) && (entry = GetHead(&LineList)))
				{
					line--;
					while(line-- && entry)	entry = GetSucc(entry);
					line++;

					if(entry && !line)
					{
						color(CYAN);
						MyPrintf("%2ld>", atol(wait_buffer));
						color(WHITE);
						In(75, 4);
						if(!connected && !login)	goto exit;

						strcpy(entry->text, wait_buffer);
						color(GREEN);
						MyPrintf("Der Text wurde ersetzt.\r\n");
					}
					else
					{
						color(YELLOW);
						MyPrintf("Zeile nicht gefunden..\r\n");
					}
				}
				else
				{
					color(YELLOW);
					MyPrintf("Ungültige Eingabe. (? für Hilfe)\r\n");
				}
				break;
		}

		if(!stop && (connected || login))
		{
			if(User.help_level == 1)
			{
				color(WHITE);
				MyPrintf("(Commands: #, L, S, E, D, I, C, G , Z, M, ?)\r\n");
			}
			Ask("Editor : ", NULL, 5, TRUE);
		}
	}	while((connected || login) && !stop);

	exit:
	RemList(&LineList);
	return(FALSE);
}

BOOL FullScreenEditor(STRPTR filename, STRPTR to, STRPTR subject)
{
	struct List LineList;
	struct Line *entry, *e;
	STRPTR ptr;
	BPTR FH;
	unsigned char c;
	LONG x, y, line, lines, i;

	Location("Fullscreen Editor");

	x		= 1;
	y		= 5;
	line	=
	lines = 1;

	e = entry = NULL;
	ClrScr();

	NewList(&LineList);
	GetLineList(filename, &LineList);

	entry = GetHead(&LineList);
	while(entry)
	{
		line++;
		lines++;
		y++;

		entry = GetSucc(entry);
	}

	if(!(entry = GetLine()))
	{
		SendError("FullScreenEditor", "couldn't allocate memory");
		RemList(&LineList);
		return(FALSE);
	}
	AddTail(&LineList, entry);

	RedrawFullScreen(to, subject, entry);

	do
	{
		In(1, 1);

		c = wait_buffer[0];
		switch(c)
		{
			case BACK_SPACE:
				if(x == 1 && line == 1)	Beep();
				else
				{
					if(x == 1 && (e = GetPred(entry)))
					{
						if(y == 5)
						{
							gotoxy(1, User.lines);
							Csi(DELETE_LINE);
							gotoxy(1, 5);
							Csi(INSERT_LINE);
							MyPrintf(e->text);
							y++;
						}

						x = strlen(e->text) + 1;
						y--;
						line--;

						MeltLines(e->text, entry->text);
						gotoxy(1, y + 1);

						if(!entry->text[0])
						{
							if(entry)
							{
								Remove(entry);
								FreeVec(entry);
							}

							Csi(DELETE_LINE);
							lines--;

							gotoxy(1, User.lines);
							Csi(INSERT_LINE);
							if(lines > User.lines - 4)
							{
								entry = e;
								i = User.lines - y;
								while(i-- && entry)	entry = GetSucc(entry);
								if(entry)	MyPrintf(entry->text);
							}
						}
						else
						{
							MyPrintf(entry->text);
							Csi(DEL_RO_LINE);
						}
						gotoxy(1, y);
						MyPrintf(e->text);
						Csi(DEL_RO_LINE);

						gotoxy(x, y);
						entry = e;
					}
					else
					{
						Char(BACK_SPACE);
						Csi(DELETE_CHAR);
						x--;
						strcpy(&entry->text[x - 1], &entry->text[x]);
					}
				}
				break;

			case DEL:
				if(entry->text[x - 1])
				{
					Csi(DELETE_CHAR);
					strcpy(&entry->text[x - 1], &entry->text[x]);
				}
				else
				{
					if(e = GetSucc(entry))
					{
						MeltLines(entry->text, e->text);
						if(e->text[0])
						{
							gotoxy(1, y + 1);
							MyPrintf(e->text);
							Csi(DEL_RO_LINE);
							gotoxy(1, y);
							MyPrintf(entry->text);
							gotoxy(x, y);
						}
						else
						{
							Remove(e);
							FreeVec(e);

							gotoxy(1, y + 1);
							Csi(DELETE_LINE);
							lines--;

							gotoxy(1, User.lines);
							Csi(INSERT_LINE);
							if(lines > User.lines - 4)
							{
								e = entry;
								i = User.lines - y;
								while(i-- && e)	e = GetSucc(e);
								if(e)	MyPrintf(e->text);
							}

							gotoxy(1, y);
							MyPrintf(entry->text);
							gotoxy(x, y);
						}
					}
					else	Beep();
				}
				break;

			case ESC:
				In(1, 1);
				c = wait_buffer[0];
				if(c == ESC)
				{
					RemList(&LineList);
					ClrScr();
					return(FALSE);
				}
				if(c != '[')	continue;

			case CSI:
				In(1, 1);
				c = wait_buffer[0];
				switch(c)
				{
					case 'A': /* up */
						if(e = GetPred(entry))
						{
							line--;
							entry = e;

							if(y == 5)
							{
								gotoxy(1, User.lines);
								Csi(DELETE_LINE);

								gotoxy(1, 5);
								Csi(INSERT_LINE);

								MyPrintf(entry->text);
								gotoxy(x, y);
							}
							else
							{
								Csi(c);
								y--;
							}

							if(x > strlen(entry->text))
							{
								x = strlen(entry->text) + 1;
								gotoxy(x, y);
							}
						}
						else	Beep();
						break;

					case 'B': /* down */
						if(e = GetSucc(entry))
						{
							line++;
							entry = e;

							if(y < User.lines)
							{
								Csi(c);
								y++;
							}
							else
							{
								gotoxy(1, 5);
								Csi(DELETE_LINE);

								gotoxy(1, User.lines);
								Csi(INSERT_LINE);

								MyPrintf(entry->text);
								gotoxy(x, y);
							}

							if(x > strlen(entry->text))
							{
								x = strlen(entry->text) + 1;
								gotoxy(x, y);
							}
						}
						else	Beep();
						break;

					case 'C': /* right */
						if(x - 1 < strlen(entry->text))
						{
							Csi(c);
							x++;
						}
						else	Beep();
						break;

					case 'D': /* left */
						if(x > 1)
						{
							Csi(c);
							x--;
						}
						else	Beep();
						break;

					case 'T': /* shift up */
						if(GetPred(entry))
						{
							if(y == 5)	i = User.lines - 5;
							else			i = y - 5;

							while(i-- && entry)
							{
								entry = GetPred(entry);
								line--;
							}
							if(!entry || line < 1)
							{
								entry = GetHead(&LineList);
								line = 1;
							}
							if(y == 5)	RefreshFullScreen(entry);
							else	y = 5;

							if(x > strlen(entry->text))	x = strlen(entry->text) + 1;
							gotoxy(x, y);
						}
						else	Beep();
						break;

					case 'S': /* shift down */
						if(GetSucc(entry))
						{
							if(y == User.lines)	i = User.lines - 5;
							else						i = User.lines - y;

							while(i-- && entry)
							{
								entry = GetSucc(entry);
								line++;
							}
							if(!entry || line > lines)
							{
								entry = GetTail(&LineList);
								line = lines;
							}
							if(y == User.lines)
							{
								e = entry;
								i = User.lines - 5;
								while(i-- && e)	e = GetPred(e);
								if(!e)	e = GetHead(&LineList);
								RefreshFullScreen(e);
							}
							else	y = User.lines;

							if(y - 4 > lines)	y = lines + 4;

							if(x > strlen(entry->text))	x = strlen(entry->text) + 1;
							gotoxy(x, y);
						}
						else	Beep();
						break;

					case ' ':
						In(1, 1);
						c = wait_buffer[0];
						switch(c)
						{
							case 'A': /* shift left */
								x = 1;
								gotoxy(x, y);
								break;
							case '@': /* shift right */
								x = strlen(entry->text) + 1;
								gotoxy(x, y);
								break;
						}
						break;
				}
				break;

			case CTRL_K:
				if(e = GetSucc(entry))
				{
					Remove(entry);
					FreeVec(entry);
					entry = e;
					lines--;

					Csi(DELETE_LINE);
					gotoxy(1, User.lines);
					Csi(INSERT_LINE);
					if(lines > User.lines - 4)
					{
						e = entry;
						i = User.lines - y;
						while(i-- && e)	e = GetSucc(e);
						if(e)	MyPrintf(e->text);
					}

					if(x > strlen(entry->text))	x = strlen(entry->text) + 1;
					gotoxy(x, y);
				}
				else
				{
					if(strlen(entry->text))
					{
						gotoxy(1, y);
						Csi(DEL_RO_LINE);
						entry->text[0] = 0;
					}
					else	Beep();
				}
				break;

			case CTRL_Q: /* quoten incl. 3 zeilen quote-header */
				if(GetHead(&LineList))
				{
					char file[256];

					entry = GetPred(entry);
					SPrintf(file, "%lsQuote", Config.temp);
					if(FH = Open(file, MODE_OLDFILE))
					{
						i = 3;
						while(i--)
						{
							FGets(FH, file, 78);
							if(ptr = strchr(file, '\r'))	*ptr = 0;
							else
							{
								if(ptr = strchr(file, '\n'))	*ptr = 0;
								else
								file[79] = 0;
							}
							if(e = GetLine())
							{
								Insert(&LineList, e, entry);
								SPrintf(e->text, "%.79ls", file);
								entry = e;
								line++;
								lines++;
								y++;
							}
						}

						while(FGets(FH, file, 77))
						{
							if(e = GetLine())
							{
								Insert(&LineList, e, entry);
								if(ptr = strchr(file, '\r'))	*ptr = 0;
								else
								{
									if(ptr = strchr(file, '\n'))	*ptr = 0;
									else
									file[78] = 0;
								}
								SPrintf(e->text, "> %.77ls", file);
								entry = e;
								line++;
								lines++;
								y++;
							}
						}
						Close(FH);

						if(y > lines)	y = lines + 4;
						if(y > User.lines)	y = User.lines;
						if(GetSucc(entry))	entry = GetSucc(entry);

						i = y - 5;
						e = entry;
						while(i-- && e)	e = GetPred(e);
						RefreshFullScreen(e);
						gotoxy(x, y);
					}
				}
				break;

			case CTRL_L: /* redraw screen */
				i = y - 5;
				e = entry;
				while(i-- && e)	e = GetPred(e);
				RedrawFullScreen(to, subject, e);
				gotoxy(x, y);
				break;

			case 0:
				if(e = GetLine())
				{
					if(y == User.lines)
					{
						gotoxy(1, 5);
						Csi(DELETE_LINE);

						gotoxy(1, User.lines);
						Csi(INSERT_LINE);

						y--;
					}
					else
					{
						gotoxy(1, User.lines);
						Csi(DELETE_LINE);
						gotoxy(1, y + 1);
						Csi(INSERT_LINE);
					}

					Insert(&LineList, e, entry);

					if(entry->text[x - 1])
					{
						strcpy(e->text, &entry->text[x - 1]);
						entry->text[x - 1] = 0;

						gotoxy(x, y);
						Csi(DEL_RO_LINE);

						gotoxy(1, y + 1);
						MyPrintf(e->text);
						gotoxy(1, y + 1);
					}

					entry = e;
					x = 1;
					y++;
					line++;
					lines++;
				}
				else Beep();
				break;

			case CTRL_Z: /* save */
				if(entry = GetHead(&LineList))
				{
					if(FH = Open(filename, MODE_NEWFILE))
					{
						while(entry)
						{
							FPrintf(FH, "%ls\r\n", entry->text);
							entry = GetSucc(entry);
						}
						Close(FH);
						RemList(&LineList);
						gotoxy(1, User.lines);
						return(TRUE);
					}
					else	Beep();
				}
				break;

			default:
				if(iscntrl(c))	Beep();
				else
				{
					if(strlen(entry->text) < 79)
					{
						if(!entry->text[x - 1])
						{
							entry->text[x - 1] = c;
							entry->text[x] = 0;
							Char(c);
						}
						else
						{
							char buffer[81];

							Csi(INSERT_CHAR);
							Char(c);
							strcpy(buffer, &entry->text[x - 1]);
							entry->text[x - 1] = c;
							strcpy(&entry->text[x], buffer);
						}
						x++;
					}
					else
					{
						if(!entry->text[x -1 ])
						{
							STRPTR ptr;
	
							if(y == User.lines)
							{
								gotoxy(1, 5);
								Csi(DELETE_LINE);

								gotoxy(1, User.lines);
								Csi(INSERT_LINE);

								y--;
							}
	
							if(e = GetLine())
							{
								Insert(&LineList, e, entry);
								ptr = strrchr(entry->text, ' ');
								if(strrchr(entry->text, '-') > ptr)
									ptr = strrchr(entry->text, '-');
								if(ptr)
								{
									strcpy(e->text, ptr + 1);
									if(*ptr == '-')	ptr++;
									x = ptr - entry->text + 1;
									gotoxy(x, y);
									Csi(DEL_RO_LINE);
									*ptr = 0;
								}
								entry = e;
								y++;
								line++;
								lines++;

								gotoxy(1, User.lines);
								Csi(DELETE_LINE);
								gotoxy(1, y);
								Csi(INSERT_LINE);

								MyPrintf(entry->text);
								x = strlen(entry->text) + 1;
								Char(c);
								entry->text[x - 1] = c;
								entry->text[x] = 0;
								x++;
							}
						}
					}
				}
		}
	}	while(connected || login);

	RemList(&LineList);

	return(FALSE);
}

VOID RedrawFullScreen(STRPTR to, STRPTR subject, struct Line *entry)
{
	LONG i;

	ClrScr();

	color(CYAN);
	MyPrintf("An   : ");
	color(GREEN);
	MyPrintf("%-47.47ls ", to);

	color(CYAN);
	MyPrintf("Datum: ");
	color(GREEN);
	MyPrintf("%ls %ls\r\n", date, time);

	color(CYAN);
	MyPrintf("Von  : ");
	color(GREEN);
	MyPrintf("%-35.35ls ", User.alias);

	color(VIOLET);
	MyPrintf("CTRL-Z : Speichern  CTRL-Q : Quoten\r\n");

	color(CYAN);
	MyPrintf("Betr.: ");
	color(GREEN);
	MyPrintf("%-35.35ls ", subject);

	color(VIOLET);
	MyPrintf("ESC-ESC: Abbrechen  CTRL-L : Refresh\r\n");

	color(YELLOW);
	MyPrintf("-------------------------------------------------------------------------------");

	color(WHITE);
	i = User.lines - 4;
	while(entry && i--)
	{
		MyPrintf("\r\n%ls", entry->text);
		entry = GetSucc(entry);
	}
}

VOID RefreshFullScreen(struct Line *entry)
{
	LONG i;

	MyPrintf("\33[5;1H\33[0J\33[4;1H");

	color(WHITE);
	i = User.lines - 4;
	while(entry && i--)
	{
		MyPrintf("\r\n%ls", entry->text);
		entry = GetSucc(entry);
	}
}

VOID MeltLines(STRPTR line1, STRPTR line2)
{
	STRPTR ptr;
	char buffer[162], c;

	if(strlen(line1) + strlen(line2) > 79)
	{
		strcpy(buffer, line1);
		strcpy(&buffer[strlen(buffer)], line2);

		c = buffer[80];
		buffer[80] = 0;

		if(!(ptr = strrchr(buffer, ' ')))	ptr = strrchr(buffer, '-');
		buffer[80] = c;
		if(!ptr || strlen(ptr + 1) > 79)
		{
			Beep();
			return;
		}

		strcpy(line2, ptr + 1);
		if(*ptr == '-')	ptr++;
		*ptr = 0;
		strcpy(line1, buffer);
	}
	else
	{
		strcpy(&line1[strlen(line1)], line2);
		line2[0] = 0;
	}
}
