use libtui;
use libtui::widget;
use libtui::widget::list;
use sort;
use slices;
use encoding::utf8;
use fmt;
use bufio;
use os;
use regex;
use io;
use strings;
use unix::tty;

let itemscopy: []str = [];

fn globalrunehandler(ui: *libtui::ttyui, r: libtui::key) bool = {
	match (r) {
	case let r: rune =>
		if (r == 'q') {
			return true;
		};
	case let r: libtui::specialkey =>
		yield;
	};
	return false;
};

fn runehandler(l: *widget::widget, r: libtui::key) bool = {
	const l = l: *list::listwidget;
	const r = match (r) {
	case let r: rune =>
		yield r;
	case let r: libtui::specialkey =>
		return false;
	};
	switch (r) {
	case 'j' =>
		list::down(l);
	case 'k' =>
		list::up(l);
	case 'd' =>
		list::pagedown(l);
	case 'u' =>
		list::pageup(l);
	case 'l' =>
		// to print properly suspend the ui, print, then resume
		libtui::suspend(&l.widget.ui);
		//fmt::println(l.items[l.cursor])!;
		match (list::selected(*l)) {
		case let s: str =>
			fmt::println(s)!;
		case let s: []str =>
			defer free(s);
			const out = strings::join("\n", s...);
			defer free(out);
			fmt::println(out)!;
		};
		libtui::resume(&l.widget.ui);
		return true;
	case 'g' =>
		list::top(l);
	case 'G' =>
		list::bottom(l);
	case 'n' =>
		if (searchforward) {
			list::search(l, searchterm);
		} else {
			list::rsearch(l, searchterm);
		};
	case 'N' =>
		if (searchforward) {
			list::rsearch(l, searchterm);
		} else {
			list::search(l, searchterm);
		};
	case '?' =>
		// TODO add commandline support maybe
		libtui::suspend(&l.widget.ui);
		fmt::fprint(l.widget.ui.f, '?')!;
		let line = match (bufio::scanline(l.widget.ui.f)) {
		case let s: []u8 =>
			yield s;
		case io::EOF =>
			fmt::fprintln(os::stderr, "EOF")!;
			return true;
		case let e: io::error =>
			fmt::fprintln(os::stderr, io::strerror(e))!;
			return true;
		};
		//defer free(line);
		searchterm = strings::fromutf8(line);
		searchforward = false;
		let c = l.cursor;
		list::rsearch(l, searchterm);
		libtui::resume(&l.widget.ui);
	case '/' =>
		// TODO add commandline support maybe
		libtui::suspend(&l.widget.ui);
		fmt::fprint(l.widget.ui.f, '/')!;
		let line = match (bufio::scanline(l.widget.ui.f)) {
		case let s: []u8 =>
			yield s;
		case io::EOF =>
			fmt::fprintln(os::stderr, "EOF")!;
			return true;
		case let e: io::error =>
			fmt::fprintln(os::stderr, io::strerror(e))!;
			return true;
		};
		//defer free(line);
		searchterm = strings::fromutf8(line);
		searchforward = true;
		let c = l.cursor;
		list::search(l, searchterm);
		libtui::resume(&l.widget.ui);
	case 'f' =>
		//filter
		libtui::suspend(&l.widget.ui);
		fmt::fprint(l.widget.ui.f, "f: ")!;
		let line = match (bufio::scanline(l.widget.ui.f)) {
		case let s: []u8 =>
			yield s;
		case io::EOF =>
			fmt::fprintln(os::stderr, "EOF")!;
			return true;
		case let e: io::error =>
			fmt::fprintln(os::stderr, io::strerror(e))!;
			return true;
		};
		defer free(line);
		let newitems: []str = [];
		defer strings::freeall(newitems);
		for (let i = 0z; i < len(l.items); i += 1) {
			if (strings::contains(l.items[i], strings::fromutf8(line))) {
				append(newitems, l.items[i]);
			};
		};
		list::setitems(l, newitems...);
		libtui::resume(&l.widget.ui);
	case 'o' =>
		// order
		list::clearmarked(l);
		sort::strings(l.items);
	case 'O' =>
		// reverse order
		list::clearmarked(l);
		sort::strings(l.items);
		slices::reverse(l.items: []void, size(str));
	case 'p' =>
		list::setitems(l, itemscopy...);
	case 's' =>
		// TODO add commandline support maybe
		libtui::suspend(&l.widget.ui);
		fmt::fprint(l.widget.ui.f, "s: ")!;
		let line = match (bufio::scanline(l.widget.ui.f)) {
		case let s: []u8 =>
			yield s;
		case io::EOF =>
			fmt::fprintln(os::stderr, "EOF")!;
			return true;
		case let e: io::error =>
			fmt::fprintln(os::stderr, io::strerror(e))!;
			return true;
		};
		defer free(line);
		list::containsmark(l, strings::fromutf8(line));
		libtui::resume(&l.widget.ui);
	case 'S' =>
		// TODO add commandline support maybe
		libtui::suspend(&l.widget.ui);
		fmt::fprint(l.widget.ui.f, "S: ")!;
		let line = match (bufio::scanline(l.widget.ui.f)) {
		case let s: []u8 =>
			yield s;
		case io::EOF =>
			fmt::fprintln(os::stderr, "EOF")!;
			return true;
		case let e: io::error =>
			fmt::fprintln(os::stderr, io::strerror(e))!;
			return true;
		};
		defer free(line);
		list::fnmatchmark(l, strings::fromutf8(line));
		libtui::resume(&l.widget.ui);
	case 'r' =>
		// TODO add commandline support maybe
		libtui::suspend(&l.widget.ui);
		fmt::fprint(l.widget.ui.f, "r: ")!;
		let line = match (bufio::scanline(l.widget.ui.f)) {
		case let s: []u8 =>
			yield s;
		case io::EOF =>
			fmt::fprintln(os::stderr, "EOF")!;
			return true;
		case let e: io::error =>
			fmt::fprintln(os::stderr, io::strerror(e))!;
			return true;
		};
		defer free(line);
		match (regex::compile(strings::fromutf8(line))) {
		case let re: regex::regex =>
			list::regexmark(l, &re);
			regex::finish(&re);
		case let e: regex::error =>
			fmt::fprintln(os::stderr, regex::strerror(e))!;
		};
		libtui::resume(&l.widget.ui);
	case ' ' =>
		list::tmark(l);
		list::down(l);
	case 'c' =>
		list::clearmarked(l);
	case '\n' =>
		// For some reason enter doesn't send r == '\n'
		fmt::fprintln(os::stderr, "This is not detected")!;
	case =>
		let us = utf8::encoderune(r);
		if (len(us) > 0 && us[0] == 13u8) {
			fmt::fprintln(os::stderr, "newline")!;
		};
	};
	return false;
};
