/*
 * dml - Dialog Markup Language
 *
 * $Id: input.c,v 1.3 2003/04/04 10:08:27 malekith Exp $
 * Author: Michal Moskal <malekith@pld-linux.org>
 * include COPYING-GNU
 */

#include "pi.h"
#include <string.h>

void pi_input_draw(struct pi_input *self)
{
	int i, n, w, a = 0, x, y;
	
	pi_locate((struct pi_object*)self, &x, &y);
	
	if ((self->buf[0] == 0) || (self->pass==1)) {
		pi_color(self->ghosted ? pi_color_input_ghosted :
		            pi_is_active((struct pi_object*)self) ? 
			      pi_color_input_hl : pi_color_input);
		if (self->buf[0] == 0) 
			self->top = self->cur = 0;
			
		n = self->pos.w;
		
		if (self->buf[0] && n)
		{
		        pi_putch('x');
			n--;
		}
		while (n--)
		        pi_putch(' ');
			
		pi_goto(x, y);
		return;
	} 
	
	n = strlen(self->buf);
	if (self->top > n)
		self->top = 0;
	if (self->cur > n)
		self->cur = n;
	n -= self->top;
	w = self->pos.w;
	if (self->top) {
		w--;
		pi_color(pi_color_input_arrow);
		pi_putch('<');
	}
	if (n > w) {
		w--;	/* for '>' */
		a = 1;
	}
	pi_color(
		self->ghosted ? pi_color_input_ghosted :
		  pi_is_active((struct pi_object*)self) ? 
		   self->deadly ? 
		     pi_color_input_deadly : 
		       pi_color_input_hl : pi_color_input);
	if (n >= w) {
	        if (self->pass)
		{
		  for(n=w;n>0;n--)
	            pi_putch('*');
		}
		else
  		  pi_addstrn(self->buf + self->top, w);
		  
		if (a) {
			pi_color(pi_color_input_arrow);
			pi_putch('>');
		}
	} else {
	        if (self->pass)
		{
		  for (i=n;i>0;i--)
		        pi_putch('*');
		}
		else
  		  pi_addstr(self->buf + self->top);
		  
		pi_color(self->ghosted ? pi_color_input_ghosted :
		            pi_is_active((struct pi_object*)self) ? 
			      pi_color_input_hl : pi_color_input);
		n = w - n;
		while (n--)
			pi_putch(' ');
	}
	pi_goto(x + self->cur - self->top + (self->top != 0), y);
}

void pi_input_kill(struct pi_input *self)
{
	xfree(self->buf);
}

static void dead(struct pi_input *self)
{
	if (self->deadly) {
		self->buf[0] = 0;
		self->top = self->cur = 0;
	}
}

void pi_input_key(struct pi_input *self, int key)
{
	char *p;
	int n;
	
	/* p is char under cursor */
	p = self->buf + self->cur;
		
	switch (key) {
	case pi_key_left:
		if (self->cur)
			self->cur--;
		break;
	case pi_key_right:
		if (*p)
			self->cur++;
		break;
	case '\b':
		if (self->cur == 0)
			break;
		self->cur--;
		p--;
	case pi_key_del:
		if (p && *p) 
			memmove(p, p + 1, strlen(p));
		dead(self);
		break;
	case pi_key_home:
		self->cur = 0;
		break;
	case pi_key_end:
		self->cur = strlen(self->buf);
		break;
	default:
	        if ((key == '\n') && (self->res != 0))
		{
  		        self->parent->f->handle_cc(self->parent, self->res);
			return;
		}

		if (key >= ' ' && key < 256) {
			dead(self);
			n = strlen(self->buf);
			if (self->blen < n + 2) 
				self->buf = xrealloc(self->buf, 
						     self->blen *= 2);
			p = self->buf + self->cur;
			memmove(p + 1, p, strlen(p) + 1);
			*p = key;
			self->cur++;
		} else {
			pi_object_key((struct pi_object*)self, key);
			return;
		}
	}
	
	if (self->cur > (int)strlen(self->buf))
		self->cur = strlen(self->buf);
		
	if (self->cur < 0)
		self->cur = 0;
	if (self->top > self->cur)
		self->top = self->cur;
	
	if (self->cur - self->top > self->pos.w - 2)
		self->top = self->cur - self->pos.w + 2;
	else if (self->cur - self->top == self->pos.w - 2 && 
		 self->buf[self->cur])
		self->top++;
	self->deadly = 0;
	pi_draw((struct pi_object*)self);
}

const char *pi_input_fetch(struct pi_input *self)
{
	return self->buf;
}

static struct pi_funcs input_funcs = {
	1,
	(pi_handler_void)pi_input_draw,
	(pi_handler_int)pi_object_cc,
	(pi_handler_int)pi_input_key,
	(pi_handler_void)pi_input_kill,
	(pi_handler_rstring)pi_input_fetch,
};

struct pi_input *pi_new_input(int size)
{
	struct pi_input *self;

	if (size == 0)
		size = sizeof(struct pi_input);
	self = (struct pi_input*)pi_new_object(size);

	self->f = &input_funcs;
	self->buf = (char*)xmalloc(self->blen = 16);
	self->buf[0] = 0;

	return self;
}

void pi_input_set_caption(struct pi_input *i, const char *s)
{
	int n;

	n = strlen(s) + 1;
	
	if (i->blen < n) {
		pi_setstr(&i->buf, s);
		i->blen = n;
	} else 
		strcpy(i->buf, s);
	i->deadly = 1;
	i->cur = i->top = 0;
	n--;
	if (n < i->pos.w)
		i->cur = n;
}

struct pi_input *pi_add_input(struct pi_window *par, int x, int y, int w,
			      const char *s)
{
	struct pi_input *p;

	p = pi_new_input(0);
	pi_setpos((struct pi_object*)p, x, y, w, 1);
	pi_add_child((struct pi_object*)par, (struct pi_object*)p);
	pi_input_set_caption(p, s);
	
	return p;
}
