/* insdel.c - functions for inserting/deleting text
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mstring.h"
#include "getdate.h"
#include "terminal.h"
#include "editor.h"

void ed__op__position_x(void);


/* Delete line "l" from the array, freeing up associated memory.
 */
void ed__line_del(long l)
{
	int blanked;

	free(ed__array[l]);
	ed__array[l] = 0;

	for (; l < (ed__lines - 1); l++) {
		ed__array[l] = ed__array[l + 1];
		ed__array[l + 1] = 0;
	}

	ed__lines--;
	blanked = 0;
	if (ed__lines < 1) {
		blanked = 1;
		ed__lines = 1;
	}
	ed__array = realloc(ed__array, sizeof(char *) * (ed__lines));

	if (blanked)
		ed__array[0] = strdup("");

	if (!ed__array)
		ed__lines = 0;		    /* we're buggered now. */
}


/* Insert a new blank line just after "l".
 */
void ed__line_ins(long l)
{
	long i;

	ed__lines++;
	ed__array = realloc(ed__array, sizeof(char *) * (ed__lines));

	if (!ed__array) {
		ed__lines = 0;
		return;			    /* similarly buggered... */
	}

	for (i = ed__lines - 1; i > (l + 1); i--) {
		ed__array[i] = ed__array[i - 1];
		ed__array[i - 1] = 0;
	}

	ed__array[l + 1] = strdup("");
}


/* Delete one character to the left of the cursor, concatenating the current
 * and previous rows if currently at the start of the row.
 */
void ed__op_del_left(void)
{
	char buf[2];
	char *a;
	long o;
	int c, d;

	buf[0] = 0;
	buf[1] = 0;

	a = ed__array[ed__curline];
	if (!a)
		a = buf;

	ed__curchar--;

	if (ed__curchar < 0) {
		if (ed__curline < 1) {
			ed__curchar = 0;
			return;
		}
		a = ed__array[ed__curline - 1];
		if (!a)
			a = "";
		ed__curchar = strlen(a);
		ed__curcol = mstrlen(a);
		ed__op_up();
		ed__op_del_right();
		return;
	}

	if (ed__curchar > strlen(a))
		ed__curchar = strlen(a);

	if (strlen(a) > 0) {
		memmove(a + ed__curchar, a + ed__curchar + 1,
			strlen(a + ed__curchar + 1) + 1);
		c = a[ed__curchar];	    /* work out current column */
		a[ed__curchar] = 0;
		ed__curcol = mstrlen(a);
		a[ed__curchar] = c;
	} else {
		ed__curchar = 0;
		ed__curcol = 0;
	}

	o = ed__leftchar;
	ed__op__position_x();

	if (o != ed__leftchar) {	    /* redraw whole line */

		t_goto(0, ed__start_line + (ed__curline - ed__topline));
		ed_redraw_line(ed__curline);

	} else {			    /* remove 1 character */

		t_goto(ed__curchar - ed__leftchar,
		       ed__start_line + (ed__curline - ed__topline));
		t_abswrite("\033[1P");

		if (strlen(a + ed__leftchar) > (t_cols - 2)) {
			t_goto(t_cols - 2,
			       ed__start_line + (ed__curline -
						 ed__topline));
			d = a[ed__leftchar + t_cols - 2];
			if (miscntl(d))
				t_write("\035R]\035r");
			else {
				buf[0] = d;
				buf[1] = 0;
				t_write(buf);
			}
			if (strlen(a + ed__leftchar) > (t_cols - 1))
				t_write("\035R>\035r");
		}

	}

	t_goto(ed__curchar - ed__leftchar,
	       ed__start_line + (ed__curline - ed__topline));
}


/* Delete one character to the right of the cursor, concatenating the current
 * and next rows if currently at the end of the row.
 */
void ed__op_del_right(void)
{
	char buf[2];
	char *a;
	char *b;
	long i, o;
	int d;

	buf[0] = 0;
	buf[1] = 0;

	a = ed__array[ed__curline];
	if (!a)
		a = buf;

	if (ed__curchar >= strlen(a)) {	    /* concatenate lines */

		if (ed__curline >= (ed__lines - 1))
			return;
		b = ed__array[ed__curline + 1];
		if (!b)
			b = "";
		ed__array[ed__curline] = realloc(ed__array[ed__curline],
						 strlen(a) + strlen(b) +
						 2);
		if (!ed__array[ed__curline])
			return;
		strcat(ed__array[ed__curline], b);
		ed__line_del(ed__curline + 1);

		t_goto(0, ed__start_line + (ed__curline - ed__topline));

		for (i = ed__curline;
		     i < (ed__topline + t_rows - 1 - ed__start_line);
		     i++) {
			ed_redraw_line(i);
		}

		t_goto(0, ed__start_line + (ed__curline - ed__topline));
		ed_redraw_line(ed__curline);

	} else {			    /* just delete a character */

		if (strlen(a) > 0) {
			memmove(a + ed__curchar, a + ed__curchar + 1,
				strlen(a + ed__curchar + 1) + 1);
		}

		o = ed__leftchar;
		ed__op__position_x();

		if (o != ed__leftchar) {    /* redraw whole line */

			t_goto(0,
			       ed__start_line + (ed__curline -
						 ed__topline));
			ed_redraw_line(ed__curline);

		} else {		    /* just delete character */

			t_goto(ed__curchar - ed__leftchar,
			       ed__start_line + (ed__curline -
						 ed__topline));
			t_abswrite("\033[1P");

			if (strlen(a + ed__leftchar) > (t_cols - 2)) {
				t_goto(t_cols - 2,
				       ed__start_line + (ed__curline -
							 ed__topline));
				d = a[ed__leftchar + t_cols - 2];
				if (miscntl(d))
					t_write("\035R]\035r");
				else {
					buf[0] = d;
					buf[1] = 0;
					t_write(buf);
				}
				if (strlen(a + ed__leftchar) >
				    (t_cols - 1))
					t_write("\035R>\035r");
			}

		}
	}


	t_goto(ed__curchar - ed__leftchar,
	       ed__start_line + (ed__curline - ed__topline));
}


/* Insert character "c" at the cursor. If "c" is 10 or 13 (i.e. RETURN) and
 * the current line contains only "." then 1 is returned and the line is
 * blanked; if it's RETURN and the line contains only ".quit" then 2 is
 * returned (the line is not blanked). Otherwise 0 is returned.
 *
 * If "c" is 9 (TAB) then the function calls itself with c=' ' enough times
 * to pad the cursor to the next column that's a multiple of 8.
 */
int ed__op_key(int c)
{
	char buf[16];
	char *a;
	char *b;
	long i, pcc, plc;
	int at_end, indented;
	int n, d, x;

	if (c == 7)
		c = 29;
	d = c;

	buf[0] = 0;
	buf[1] = 0;

	a = ed__array[ed__curline];
	if (!a)
		a = buf;

	switch (c) {
	case 9:			    /* TAB - insert spaces */
		d = ed__curchar;
		if (d > strlen(a))
			d = strlen(a);
		c = a[d];
		a[d] = 0;
		n = 8 - (mstrlen(a) % 8);
		a[d] = c;
		for (c = n; c > 0; c--)
			ed__op_key(' ');
		return (0);
		break;
	case 10:
	case 13:			    /* RETURN - check for ".", ".quit" */
		n = strspn(a, " ");
		a += n;			    /* skip leading spaces */
		b = strchr(a, ' ');
		while ((b) && (*b == ' '))
			b++;
		if ((!b) || (*b == 0)) {    /* skip trailing spaces */
			if (!strncasecmp(a, ".quit", 5))
				return (2); /* .quit */
			if (((b) && (!strncmp(a, ". ", 2))) || ((!b) && (!strcmp(a, ".")))) {	/* . */
				a = ed__array[ed__curline];
				a[0] = 0;
				return (1);
			}
		}
		break;
	case 7:
		c = 29;
		break;			    /* force use of ^] as trib char */
	case 8:
		break;			    /* allow ^H to be entered */
	default:
		if (miscntl(c)) {
			c = 29;
			break;
		}
		if ((c < 32) || (c == 127))
			return (0);	    /* abort if illegal char */
	}

	a = ed__array[ed__curline];
	if (!a)
		a = "";

	if (ed__curchar > strlen(a))
		ed__curchar = strlen(a);

	n = ed__curchar;
	while (a[n] == ' ')
		n++;			    /* ignore trailing spaces */

	at_end = (a[n] == 0) ? 1 : 0;	    /* we're typing at end of line */


	if ((c == 10) || (c == 13)) {	    /* insert new line */

		indented = 0;

		ed__line_ins(ed__curline);

		if ((ed_opt__indent) && (at_end)) {	/* autoindent new line */
			if (!strncmp(a, "Subject:", 8)) {
				n = 8;
			} else
				n = 0;
			while (a[n] == ' ')
				n++;	    /* read number of spaces */

			if (n > 0) {	    /* insert spaces on new line */
				x = n + 1;
				b = ed__array[ed__curline + 1];
				ed__array[ed__curline + 1] = realloc(b, x);
				if (!ed__array[ed__curline + 1])
					return (0);	/* failed */
				b = ed__array[ed__curline + 1];
				b[0] = 0;
				c = 0;
				for (; n > 0; n--)
					mstrinsert(b, " ", &c, x);
				indented = 1;
			}
		}

		b = a + ed__curchar;
		a = ed__array[ed__curline + 1];

		ed__array[ed__curline + 1] =
		    realloc(a, ((a) ? strlen(a) : 0) + strlen(b) + 2);
		if (!ed__array[ed__curline + 1])
			return (0);
		if (!a)
			ed__array[ed__curline + 1][0] = 0;

		strcat(ed__array[ed__curline + 1],
		       ed__array[ed__curline] + ed__curchar);

		a = ed__array[ed__curline];
		a[ed__curchar] = 0;

		t_goto(0, ed__start_line + (ed__curline - ed__topline));

		for (i = ed__curline;
		     i < (ed__topline + t_rows - 1 - ed__start_line);
		     i++) {
			ed_redraw_line(i);
		}

		ed__curchar = 0;
		ed__curcol = 0;
		ed__op_down();		    /* move on to new line */
		if (indented)
			ed__op_end();	    /* go to end of line if indented */
		return (0);
	}

	/* insert character at current position */

	if ((!ed_opt__insert) && (!at_end)) {	/* overwrite mode */
		a = ed__array[ed__curline];
		a[ed__curchar] = c;
		t_goto(ed__curchar - ed__leftchar,
		       ed__start_line + (ed__curline - ed__topline));
		if (miscntl(d))
			t_write("\035R]\035r");
		else {
			if (d == 8)
				t_write("\035RH\035r");
			else {
				buf[0] = d;
				buf[1] = 0;
				t_write(buf);
			}
		}
		ed__op_right();
		return (0);
	}

	pcc = ed__curchar;		    /* store old current char */

	ed__array[ed__curline] =
	    realloc(ed__array[ed__curline], strlen(a) + 2);
	if (!ed__array[ed__curline])
		return (0);

	buf[0] = c;
	buf[1] = 0;
	n = ed__curchar;
	a = ed__array[ed__curline];
	mstrinsert(a, buf, &n, strlen(a) + 2);
	ed__curchar++;
	if (ed__curchar > strlen(a))
		ed__curchar = strlen(a);

	c = a[ed__curchar];		    /* work out current column */
	a[ed__curchar] = 0;
	ed__curcol = mstrlen(a);
	a[ed__curchar] = c;

	plc = ed__leftchar;
	ed__op__position_x();

	if (ed_opt__wrap) {		    /* do word wrapping */
		if (ed__op_wrap(at_end))
			return (0);
	}

	a = ed__array[ed__curline];

	if (plc == ed__leftchar) {	    /* optimise redraw */
		t_goto(ed__curchar - 1 - ed__leftchar,
		       ed__start_line + (ed__curline - ed__topline));
		t_abswrite("\033[1@");
		if (miscntl(d))
			t_write("\035R]\035r");
		else {
			if (d == 8)
				t_write("\035RH\035r");
			else {
				buf[0] = d;
				buf[1] = 0;
				t_write(buf);
			}
		}
		if (strlen(a + ed__leftchar) > (t_cols - 1)) {
			t_goto(t_cols - 1,
			       ed__start_line + (ed__curline -
						 ed__topline));
			t_write("\035R>\035r");
			t_goto(ed__curchar - ed__leftchar,
			       ed__start_line + (ed__curline -
						 ed__topline));
		}
		return (0);
	}

	t_goto(0, ed__start_line + (ed__curline - ed__topline));
	ed_redraw_line(ed__curline);

	t_goto(ed__curchar - ed__leftchar,
	       ed__start_line + (ed__curline - ed__topline));

	return (0);
}


/* Prompt the user for a date string and insert a relevant datestamp at the
 * cursor.
 */
void ed__op_datestamp(void)
{
	char buf[128];
	char buf2[128];
	time_t t;
	struct tm *tp;
	int old_insert;
	int old_indent;
	int old_wrap;
	int i;

	t_goto(0, t_rows - 1);
	t_clrtoeol();

	buf[0] = 0;

	t_goto(0, t_rows - 1);
	t_clrtoeol();

	do {
		i = t_input("Enter date, or blank for now : ", buf,
			    sizeof(buf) - 1);
	} while (i == 1);

	t_goto(0, t_rows - 1);
	t_clrtoeol();

	if (buf[0] == 0)
		strcpy(buf, "now");

	t = get_date(buf, 0);
	if (t == -1) {
		t = 0;
		strcpy(buf2, "Invalid Date");
	} else {
		tp = localtime(&t);
		if (!tp) {
			t = 0;
			strcpy(buf2, "Invalid Date");
		} else {
			buf2[0] = 0;
			strftime(buf2, sizeof(buf2) - 1,
				 "%a %b %d %H:%M:%S %Y %Z", tp);
		}
	}

	sprintf(buf, "Message: %08lX             (%s)\n", t, buf2);

	old_insert = ed_opt__insert;
	old_indent = ed_opt__indent;
	old_wrap = ed_opt__wrap;

	ed_opt__insert = 1;
	ed_opt__indent = 0;
	ed_opt__wrap = 0;

	if (ed__curchar > 0)
		ed__op_key('\n');
	for (i = 0; i < strlen(buf); i++)
		ed__op_key(buf[i]);

	ed_opt__insert = old_insert;
	ed_opt__indent = old_indent;
	ed_opt__wrap = old_wrap;
}

/* EOF */
