#include <atari.h>
#include <string.h>
#include "addrs.h"
#include "screen.h"
#include "edbox.h"
#include "complete.h"
#include "keytab.h"
#include "irc.h"
#include "memclear.h"

/* private API stuff (not in edbox.h) that's been rewritten in asm. */
void hide_cursor(void);
void show_cursor(void);
void storechr(char c);
void copy_to_old(void);
void restore_old(void);
void backspace(void);
void inschr(char c);

char old_edbox[EDBOX_SIZE];
char old_len;
char typeover;

char edbox_visible = 0;
char edbox_pos; /* range 0 to EDBOX_SIZE - 1 */
char edbox_len; /* idem */

void edbox_show(void) {
	u16 addr;

	if(edbox_pos < 80)
		addr = (u16)edit_box;
	else
		addr = (u16)edit_box + edbox_pos - 79;

	scr_waitvcount_116();

	*dlist_status_lms = addr;
	*dlist_last_line = 0x02; /* ANTIC GR.0 */
	edbox_visible = 1;
	show_cursor();
}

void edbox_hide(void) {
	scr_end_scrollback(); /* exit Start+E mode */
	edbox_visible = 0;
	scr_refresh();
}

void move_right(void) {
	memmove(edit_box + edbox_pos + 1, edit_box + edbox_pos, EDBOX_MAXPOS - edbox_pos);
}

/* note: c will never be an EOL.
   idea: when the edbox is completely full (240 chars), go
   ahead and pretend the user pressed Return.
   Not sure if this is more or less annoying than just
   refusing to accept more input until Return is pressed. */
void edbox_putc(char c) {
	if(!c)
		return; /* no inserting nulls */

	/* cannot insert *or* typeover at end of buffer! */
	if(edbox_pos == EDBOX_MAXPOS) {
		bell();
		return;
	}

	if(typeover) {
		storechr(c);
		edbox_pos++;
	} else {
		inschr(c);
	}
}


void del_char(void) {
	if(!edbox_len) return;
	memmove(edit_box + edbox_pos, edit_box + edbox_pos + 1, EDBOX_MAXPOS - edbox_pos);
	edbox_len--;
}

static void del_to_end(void) {
	while(edbox_len > edbox_pos)
		del_char();
}

static void up(void) {
	if(!edbox_len) {
		restore_old();
	} else {
		if(edbox_pos > 39)
			edbox_pos -= 40;
		else
			edbox_pos = 0;
	}
}

static void down(void) {
	if(edbox_pos > 199) return;
	edbox_pos += 40;
	if(edbox_pos > edbox_len)
		edbox_pos = edbox_len;
}

static void word_left(char del) {
	if(!edbox_pos) return;
	if(!del) edbox_pos--;
	while(edbox_pos && edit_box[edbox_pos] == ' ') {
		if(del) del_char();
		edbox_pos--;
	}
	while(edbox_pos && edit_box[edbox_pos] != ' ') {
		if(del) del_char();
		edbox_pos--;
	}
	// XXX: what's this good for?
	if(del && !edbox_pos) edit_box[edbox_pos] = /* ' ' */ 0;
}

static void forward_word(void) {
	while(edbox_pos < edbox_len && edit_box[edbox_pos] == ' ')
		edbox_pos++;
	while(edbox_pos < edbox_len && edit_box[edbox_pos] != ' ')
		edbox_pos++;
}

static void del_to_start(void) {
	if(!edbox_pos) return;
	memmove(edit_box, edit_box + edbox_pos, EDBOX_MAXPOS - edbox_pos);
	edbox_len -= edbox_pos;
	memclear(edit_box + edbox_len, EDBOX_MAXPOS - edbox_len);
	edbox_pos = 0;
}

void left(void) {
	if(edbox_pos) edbox_pos--;
}

void right(void) {
	if(edbox_pos < edbox_len) edbox_pos++;
}

void edbox_keystroke(char c) {
	if(c == CH_ESC) {
		start_latch = 1;
		return;
	}

	if(c != XCH_TAB)
		comp_complete_done();

	if(c >= XCH_SCR1 && c <= XCH_SCR7) {
		start_keystroke(c & 0x7f);
		return;
	} else if(c == XCH_ACTIVE) {
		start_keystroke('a');
		return;
	}

	edbox_show();
	hide_cursor();

	switch(c) {
		case CH_EOL:
			copy_to_old();
			edbox_hide();
			cmd_execute();
			edbox_clear();
			break;
		case XCH_TAB:
			comp_complete();
			break;
		case XCH_UP:
			up();
			break;
		case XCH_DOWN:
			down();
			break;
		case XCH_LEFT:
			left();
			break;
		case XCH_RIGHT:
			right();
			break;
		case XCH_LWORD:
			word_left(0);
			break;
		case XCH_RWORD:
			forward_word();
			break;
		case XCH_CLS:
			edbox_clear();
			edbox_hide();
			return;
		case CH_DELCHR:
		case 0x18: /* ^X */
			del_char();
			break;
		case CH_DELLINE:
			edbox_clear();
			break;
		case XCH_INSCHR:
			inschr(' ');
			break;
		case CH_INSLINE:
			typeover = !typeover;
			break;
		case 0x15: /* ^U */
			del_to_start();
			break;
		case 0x0b: /* ^K */
			del_to_end();
			break;
		case XCH_BS:
			if(!edbox_len)
				edbox_hide();
			else
				backspace();
			break;
		case 0x17: /* ^W */
			word_left(1);
			break;
		case 0x01: /* ^A */
			edbox_pos = 0;
			break;
		case 0x05: /* ^E */
			edbox_pos = edbox_len;
			break;
		default:
			edbox_putc(c);
			break;
	}

	show_cursor();
	if(edbox_visible) edbox_show();
}
