#include <stdlib.h>
#include <string.h>
#include "vt.h"
#include "misc.h"
#include "xio.h"
#include "edline.h"

static void
do_exit(struct edline *el, u8 *buf)
{
    xio_set_cursor(el->xw, 999, 999);
    xio_set_handler(el->xw, el->old_handler, el->old_data);
    el->exit_func(el->exit_data, buf);
    free(el);
}

static void
redraw(struct edline *el)
{
    u8 buf[40];
    u8 *p;
    int l;

    p = el->buf;
    l = el->len;

    if (l > 39 - el->plen)
    {
	l = 39 - el->plen;
	p = el->buf + el->len - l;
    }

    memset(buf, ' ', sizeof(buf));
    memcpy(buf, el->prompt, el->plen);
    memcpy(buf + el->plen, p, l);

    xio_set_cursor(el->xw, el->plen + l, 24);
    xio_put_line(el->xw, 24, buf);
}

static void
ev_handler(struct edline *el, struct vt_event *ev)
{
    switch (ev->type)
    {
	case EV_KEY:
	    switch (ev->i1)
	    {
		case '\e':
		case '\3':
		    do_exit(el, 0);
		    return;
		case '\r':
		case '\n':
		    el->buf[el->len] = 0;
		    do_exit(el, el->buf);
		    return;
		case KEY_INS:
		    xio_query_selection(el->xw);
		    return;
		case KEY_LEFT:
		case '\b':
		    if (el->len)
		    {
			el->len--;
			redraw(el);
		    }
		    else
			do_exit(el, 0);
		    return;
		case 0x20 ... 0x7e:
		case 0xa0 ... 0xff:
		    if (el->len < (int)sizeof(el->buf)-1)
		    {
			el->buf[el->len++] = ev->i1;
			redraw(el);
			return;
		    }
		    break;
	    }
	    xio_bell(el->xw);
	    return;
	case EV_SELECTION:
	{
	    u8 *p = ev->p1;
	    int n = ev->i1;

	    while (n-- && el->len < (int)sizeof(el->buf)-1)
	    {
		if (*p >= 0x20 && *p <= 0x7e || *p >= 0xa0 && *p <= 0xff)
		    el->buf[el->len++] = *p;
		p++;
	    }
	    redraw(el);
	    return;
	}
	case EV_MOUSE:
	    if (ev->i4 == 24)
	    {
		if (ev->i1 == 2)
		    xio_query_selection(el->xw);
		else
		    xio_bell(el->xw);
		return;
	    }
	    break;
    }
    el->old_handler(el->old_data, ev);
}




struct edline *
edline_new(struct xio_win *xw, u8 *prompt, u8 *str, void *exit_func, void *data)
{
    struct edline *el;
    int plen, slen;

    if ((plen = strlen(prompt)) > 20)
	goto fail1;
    if ((slen = strlen(str)) > (int)sizeof(el->buf) - 1)
	goto fail1;

    if (not(el = malloc(sizeof(*el))))
	goto fail1;

    el->xw = xw;
    el->prompt = prompt;
    el->exit_func = exit_func;
    el->exit_data = data;

    el->old_handler = xw->handler;	//TODO: func to retrieve curr handler
    el->old_data = xw->data;
    xio_set_handler(el->xw, ev_handler, el);

    el->plen = plen;
    el->len = slen;
    strcpy(el->buf, str);

    redraw(el);
    return el;


fail2:
    free(el);
fail1:
    return 0;
}


void
edline_abort(struct edline *el)
{
    do_exit(el, 0);
}
