#include <stdlib.h>
#include <string.h>
#include <curses.h>
#include <menu.h>

struct node {
	char *str;
	struct node *next;
};

void init_test_items_list(struct node *list);
void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);

/* list manipulation functions */
struct node *create_list(void);
void free_list(struct node *list);
void add_item(struct node *list, char *str);
int count_nodes(struct node *list);

int main(void) {
	ITEM **items;
	MENU *menu;
	WINDOW *menu_win;
	int i, c, item_count;
	struct node *item_list, *list_ptr;

	item_list = create_list();
	init_test_items_list(item_list);

	initscr();
	start_color();
	cbreak();
	noecho();
	keypad(stdscr, TRUE);
	init_pair(1, COLOR_RED, COLOR_BLACK);
	init_pair(2, COLOR_CYAN, COLOR_BLACK);

	item_count = count_nodes(item_list);
	items = malloc(item_count * sizeof(ITEM*));
		
	list_ptr = item_list->next;	/* first element after the dummy node */
	for(i=0; list_ptr; i++) {
		items[i] = new_item(list_ptr->str, list_ptr->str);
		list_ptr = list_ptr->next;
	}
	items[i] = new_item(0, 0);

	menu = new_menu(items);
	menu_win = newwin(10, 40, 4, 4);
	keypad(menu_win, TRUE);

	set_menu_win(menu, menu_win);
	set_menu_sub(menu, derwin(menu_win, 6, 38, 3, 1));
	set_menu_format(menu, 5, 1);

	set_menu_mark(menu, " * ");

	box(menu_win, 0, 0);
	print_in_middle(menu_win, 1, 0, 40, "my menu", COLOR_PAIR(1));
	mvwaddch(menu_win, 2, 0, ACS_LTEE);
	mvwhline(menu_win, 2, 1, ACS_HLINE, 38);
	mvwaddch(menu_win, 2, 39, ACS_RTEE);

	post_menu(menu);
	wrefresh(menu_win);

	attron(COLOR_PAIR(2));
	mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items");
	mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)");
	attroff(COLOR_PAIR(2));
	refresh();

	while((c = wgetch(menu_win)) != KEY_F(1))
	{
		switch(c) {
		case KEY_DOWN:
			menu_driver(menu, REQ_DOWN_ITEM);
			break;
			
		case KEY_UP:
			menu_driver(menu, REQ_UP_ITEM);
			break;
			
		case KEY_NPAGE:
			menu_driver(menu, REQ_SCR_DPAGE);
			break;
			
		case KEY_PPAGE:
			menu_driver(menu, REQ_SCR_UPAGE);
			break;
		}
		wrefresh(menu_win);
	}

	unpost_menu(menu);
	free_menu(menu);
	
	for(i=1; i<item_count; i++) {
		free_item(items[i]);
	}
	endwin();

	free_list(item_list);

	return 0;
}

/* adds some test items to the list */
void init_test_items_list(struct node *list) {
	/* Since the nodes are added in the front of the list
	 * if I add them sequentially they will be held in reverse
	 * so I add them in reverse order.
	 */
	add_item(list, "doh");
	add_item(list, "eat my shorts");
	add_item(list, "ass");
	add_item(list, "metal");
	add_item(list, "shiny");
	add_item(list, "my");
	add_item(list, "bite");
	add_item(list, "bar");
	add_item(list, "foo");
}

void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) {
	int length, x, y;
	float temp;

	if(!win) win = stdscr;
	getyx(win, y, x);
	if(startx) x = startx;
	if(starty) y = starty;
	if(!width) width = 80;

	length = strlen(string);
	temp = (width - length) / 2;
	x = startx + (int)temp;
	wattron(win, color);
	mvwprintw(win, y, x, "%s", string);
	wattroff(win, color);
	refresh();
}


/* ----- list manipulation ----- */

/* creates a list with a dummy element which is always ignored */
struct node *create_list(void) {
	struct node *n = malloc(sizeof(struct node*));
	n->str = 0;
	n->next = 0;
	return n;
}

/* frees all the nodes */
void free_list(struct node *list) {
	while(list) {
		struct node *tmp = list;
		list = list->next;
		free(tmp->str);
		free(tmp);
	}
}

/* adds an item to the list */
void add_item(struct node *list, char *str) {
	struct node *n = malloc(sizeof(struct node*));
	if(str) {
		n->str = malloc(strlen(str) + 1);
		strcpy(n->str, str);
	} else {
		n->str = str;
	}
	
	n->next = list->next;
	list->next = n;
}

int count_nodes(struct node *list) {
	int count = 0;
	
	list = list->next;
	while(list) {
		count++;
		list = list->next;
	}
	return count;
}
