/* wrap.c - functions to handle word wrapping
 */

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

void ed__line_ins(long);
void ed_redraw_line(long);


/* Word wrap from the current line downwards until a blank line, or one with
 * different indentation, is reached. If "single" is nonzero then only the
 * current line is wrapped, with overflow words being placed on new lines
 * inserted after the current line.
 *
 * Returns zero unless some action was taken.
 */
int ed__op_wrap(int single)
{
	int indent;
	int changed;
	int highest_changed;
	int blank;
	int first;
	int make_new;
	int go_down;
	char *a;
	char *b;
	long l, x;
	int n, o, i, s;

	indent = 0;			    /* expected indentation */
	changed = 0;			    /* 1 if any changes made */
	go_down = 0;			    /* 1 if cursor to move */
	blank = 0;			    /* 1 if line is blank */
	highest_changed = -1;		    /* highest line changed */

	l = ed__curline;		    /* line to process */
	first = 1;			    /* "first line" flag */

	do {				    /* main loop starts */

		if ((single) && (!first)) { /* if single flag set do just 1 line */
			blank = 1;
			continue;
		}

		a = ed__array[l];
		if (!a) {		    /* no line - treat as blank */
			blank = 1;
			continue;
		}

		n = 0;			    /* work out indent level */

		if ((first) && (ed_opt__indent)
		    && (!strncmp(a, "Subject:", 8)))
			n = 8;
		for (; a[n] == ' '; n++);

		if (first) {		    /* first line - set expected indent */
			indent = n;
		} else {		    /* treat as blank if different indent */
			if (n != indent) {
				blank = 1;
				continue;
			}
		}

		if (indent >= ed_opt__margin) {	/* indent too large - abort */
			blank = 1;
			continue;
		}

		first = 0;		    /* next line will not be first... */

		if (a[n] == 0) {	    /* nothing but spaces - treat as blank */
			blank = 1;
			continue;
		}

		if (mstrlen(a) < ed_opt__margin) {	/* not overflowing margin */
			l++;		    /* ... try next line */
			continue;
		}

		n = strlen(a);
		n--;
		while ((n > indent) && (a[n] == ' '))
			n--;		    /* ignore trailing spaces */

		s = strlen(a) - (n + 1);    /* s = number of spaces */

		if ((mstrlen(a) - s) < ed_opt__margin) {	/* no longer overflowing */
			l++;		    /* ... try next line */
			continue;
		}

		/* By this point we have established that the line has the correct
		 * indentation level and is too long for the current margins - therefore
		 * we must at least try to wrap it.
		 */

		for (n = mstrindex(a, ed_opt__margin + 1); (n > indent) && (a[n] != ' '); n--);	/* find first breaking space */

		if (n <= indent) {	    /* no spaces found before margin */
			for (n = mstrindex(a, ed_opt__margin + 1); (a[n] != 0) && (a[n] != ' '); n++);	/* find next space */
			if (a[n] == 0) {    /* no spaces found - cannot wrap */
				l++;	    /* ... just go to next line */
				continue;
			}
		}

		/* So, we know we can wrap. From here on, "n" is the index into "a"
		 * (the current line) of the space at which to wrap.
		 */

		o = n;
		if (n < strlen(a)) {
			while (a[n + 1] == ' ')
				n++;	    /* break on last space */
		}

		a[strlen(a) - s] = 0;	    /* remove trailing whitespace */

		if (n >= strlen(a))
			n = strlen(a) - 1;  /* safeguard */

		changed = 1;
		if (l == ed__curline) {	    /* current line has been changed */
			if (ed__curchar > n) {	/* split before cursor */
				if (ed__curchar > strlen(a))
					ed__curchar = strlen(a);
				go_down = 1;
				ed__curcol =
				    mstrlen(a + o) - mstrlen(a +
							     ed__curchar) -
				    1;
				ed__curcol += indent;
				ed__curchar -= o;
				ed__curchar += indent;
				ed__curchar--;
				if (ed__curchar < 0)
					ed__curchar = 0;
				if (ed__curcol < 0)
					ed__curcol = 0;
			}
		}

		/* Now we must decide whether to create a new line for the spillover or
		 * to prefix the next line with it instead.
		 */

		make_new = single;	    /* always make a new line if single */

		if (l >= (ed__lines - 1))
			b = 0;
		else
			b = ed__array[l + 1];
		if (!b)
			make_new = 1;

		if (!make_new) {	    /* check indentation */
			for (i = 0; b[i] == ' '; i++);
			if (i != indent)
				make_new = 1;
			if (b[i] == 0)
				make_new = 1;	/* blank line - make new */
		}

		if (make_new) {		    /* create new line */
			x = indent + 2 + strlen(a) - n;
			ed__line_ins(l);
			if (l >= (ed__lines - 1))
				return (1); /* oops - failed */
			b = realloc(ed__array[l + 1], x);
			if (!b)
				return (1); /* failed again */
			ed__array[l + 1] = b;	/* store new ptr */
			b[0] = 0;
			for (i = 0; i < indent; i++)
				strcat(b, " ");
			a = ed__array[l];
			strcat(b, a + n + 1);
			highest_changed = ed__lines;
		} else {		    /* prefix next line */
			x = strlen(b) + 2 + strlen(a) - n;
			b = ed__array[l + 1];
			ed__array[l + 1] = realloc(b, x);
			b = ed__array[l + 1];
			i = indent;
			a = ed__array[l];
			mstrinsert(b, a + n + 1, &i, x);
			mstrinsert(b, " ", &i, x);
		}

		a = ed__array[l];
		if (o < strlen(a))
			a[o] = 0;	    /* terminate old line */
		b = realloc(a, strlen(a) + 1);	/* shrink its memory area */
		if (b)
			ed__array[l] = b;   /* store if successful */

		if (highest_changed < l)
			highest_changed = l;

		l++;			    /* move to next line */

	} while ((!blank) && (l < ed__lines));	/* main loop ends */

	if (changed) {			    /* redraw if necessary */

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

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

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

	if (go_down)
		ed__op_down();		    /* move down if necessary */

	return (changed);
}

/* EOF */
