/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
    This file is part of ntch.

    The ntch is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    The ntch is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ntch.  If not, see <http://www.gnu.org/licenses/>.
    
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <wchar.h>
#include <ncursesw/ncurses.h>

#include "env.h"
#include "utils/nt_std_t.h"
#include "_2ch/model_2ch.h"
#include "ui/disp.h"
#include "ui/disp_string.h"

#define FOLDER_OPEN 1
#define IS_SET_F(a,b) ((a) & (b))
#define SET_F(a,b) ((a) |= (b))
#define UNSET_F(a,b) ((a) &= (~b))

#define NT_CMD_NONE 0
#define NT_CMD_SEARCH_THREAD 1
#define NT_CMD_FAVORITE 2


typedef struct tag_category_data_t *category_data_tp;
typedef struct tag_category_data_t{
	int flag;
	nt_category_handle h_category;
}category_data_t;

typedef struct tag_ctx_board_menu_t *ctx_board_menu_tp;
typedef struct tag_ctx_board_menu_t{
	int category_num;
	int cursor_pos;
	int scroll_pos;
	category_data_tp category_list;
}ctx_board_menu_t;

static BOOL disp_board(nt_window_tp wp, ctx_board_menu_tp ctxp,
		int *cur_line, nt_category_handle h_category, 
		BOOL selected, nt_board_handle *h_sel_boardp);
static ctx_board_menu_tp init_context(nt_2ch_model_handle h_model);


static int get_menu_disp_row(ctx_board_menu_tp ctxp);
static int increment_cursor(ctx_board_menu_tp ctxp);
static int decrement_cursor(ctx_board_menu_tp ctxp);
static int adjust_scroll_pos(nt_window_tp wp, ctx_board_menu_tp ctxp);
static int move_cursor_right_colmn(nt_window_tp wp, 
		ctx_board_menu_tp ctxp);
static int move_cursor_left_colmn(nt_window_tp wp, 
		ctx_board_menu_tp ctxp);
static int get_display_folder_contents_count(category_data_tp datap);
static BOOL adjust_scroll_pos2(nt_window_tp wp, 
		ctx_board_menu_tp ctxp, category_data_tp  datap);
static int page_up(nt_window_tp wp, ctx_board_menu_tp ctxp);
static int page_down(nt_window_tp wp, ctx_board_menu_tp ctxp);
static int parse_cmd1(const char *param);


int disp_board_menu(nt_window_tp wp, 
		nt_2ch_model_handle h_model, nt_2ch_selected_item_handle h_select)
{
	nt_category_handle h_category;
	nt_board_handle h_sel_board;
	//nt_enum_handle h_enum_category;
	ctx_board_menu_tp ctxp;
	category_data_tp  datap;
	int i;
	int cur_line = 0;
	int offset_y, offset_x;
	BOOL selected = FALSE;
	BOOL add_favorite = FALSE;
	int cmd;
	int result_state;

	const wchar_t *cname;
	attr_t attr;

	assert(h_model);
	assert(wp);
	
	result_state = DISP_STATE_BOARDMENU;

	ctxp = (ctx_board_menu_tp)wp->data;
	if(!ctxp){
		ctxp = init_context(h_model);
		if(!ctxp)
			return DISP_STATE_ERROR;
		wp->data = ctxp;
	}
	switch(wp->key){
	case NT_KEY_UP:
	case KEY_UP:
		decrement_cursor(ctxp);
		adjust_scroll_pos(wp, ctxp);
		break;
	case NT_KEY_DOWN: 
	case KEY_DOWN: 
		increment_cursor(ctxp);
		adjust_scroll_pos(wp, ctxp);
		break;
	case NT_KEY_LEFT:
		move_cursor_left_colmn(wp, ctxp);
		break;
	case NT_KEY_RIGHT:
		move_cursor_right_colmn(wp, ctxp);
		break;
	case NT_KEY_PAGEUP:
	case KEY_PPAGE:
		page_up(wp, ctxp);
		break;
	case NT_KEY_PAGEDOWN:
	case KEY_NPAGE:
		page_down(wp, ctxp);
		break;
	case NT_KEY_SELECT: 
	case KEY_RIGHT:
		selected = TRUE;
		break;
	//case NT_KEY_DEL:
	//	fprintf(stderr, "check in\n");
	case NT_KEY_ADD:
		add_favorite = TRUE;
		break;
	case NT_KEY_COMMAND1:
		assert(wp->cmd_param);
		cmd = parse_cmd1(wp->cmd_param);
		switch(cmd){
		case NT_CMD_SEARCH_THREAD:
			return DISP_STATE_SEARCH_THREAD;
		case NT_CMD_FAVORITE:
			return DISP_STATE_FAVORITE;
		}
	}

	//h_enum_category = nt_2ch_model_get_category_enum(h_model);
	//if(h_enum_category == NULL)
	//	return DISP_STATE_ERROR;
	
	for(i = 0; i < ctxp->category_num; i++){
		offset_y = cur_line - ctxp->scroll_pos;
		if(offset_y == (wp->lines*2)){
			return result_state;
		}else if(offset_y >= wp->lines){
			offset_y -= wp->lines;
			offset_x = wp->cols / 2;
		}else{
			offset_x = 0;
		}

		datap = ctxp->category_list + i;
		h_category = datap->h_category;
		if(cur_line == ctxp->cursor_pos){
			attr = WA_BOLD | WA_REVERSE;
			if(selected){
				if(IS_SET_F(datap->flag,FOLDER_OPEN)){
					UNSET_F(datap->flag, FOLDER_OPEN);
				}else{
					SET_F(datap->flag, FOLDER_OPEN);
					if(adjust_scroll_pos2(wp, ctxp, datap)){
						i = -1;
						cur_line = 0;
						selected = FALSE;
						continue;
					}
				}
			}
		}else{
			attr = WA_BOLD;
		}

		wmove(wp->wp, offset_y, offset_x); 

		cname = nt_category_get_name(h_category);
		if(cur_line >= ctxp->scroll_pos){
			nt_add_wstr(wp->wp, L" + ", attr);
			nt_add_wstr(wp->wp, cname, attr);
			nt_add_wstr(wp->wp, L"\n", 0);
		}
		cur_line++;
		if(!IS_SET_F(datap->flag, FOLDER_OPEN))
			continue;
		h_sel_board = NULL;
		if(!disp_board(wp, ctxp, &cur_line, h_category,
					(selected | add_favorite), &h_sel_board))
			return DISP_STATE_ERROR;
		if(selected && h_sel_board){
			nt_set_selected_board(h_select, h_category, h_sel_board);
			return DISP_STATE_THREADTITLE;
		}else if(add_favorite && h_sel_board){
			nt_set_selected_board(h_select, h_category, h_sel_board);
			result_state |= DISP_CMD_ADD_FAVORITE;
			add_favorite = FALSE;
		}
	}

	touchwin(wp->wp);
	wrefresh(wp->wp);

	return result_state;
}

static BOOL disp_board(nt_window_tp wp, ctx_board_menu_tp ctxp,
		int *cur_line, nt_category_handle h_category, 
		BOOL selected, nt_board_handle *h_sel_boardp)
{
	nt_enum_handle h_enum_board;
	nt_board_handle h_board;
	const wchar_t *bname;
	int tmp;
	int offset_y;
	attr_t attr;


	h_enum_board = nt_category_get_board_enum(h_category);
	if(!h_enum_board)
		return TRUE;
	while(NULL != (h_board = (nt_board_handle)nt_enum_fetch(h_enum_board))){
		offset_y = *cur_line - ctxp->scroll_pos;
		if(offset_y == (wp->lines*2)){
			nt_enum_unset(h_enum_board);
			return TRUE;
		}else if(offset_y >= wp->lines){
			offset_y -= wp->lines;
			wmove(wp->wp, offset_y, wp->cols / 2); 
		}else{
			wmove(wp->wp, offset_y, 0); 
		}
		if(*cur_line == ctxp->cursor_pos){
			if(selected){
				*h_sel_boardp = h_board;
				//return TRUE;
			}
			attr = WA_REVERSE;
		}else{
			attr = 0;
		}
		bname = nt_board_get_name(h_board);
		if((*cur_line) >= ctxp->scroll_pos){
			nt_add_wstr(wp->wp, L"    - ", attr);
			nt_add_wstr(wp->wp, bname, attr);
			nt_add_wstr(wp->wp, L"\n", attr);
		}
		tmp = *cur_line;
		*cur_line = tmp + 1;
	}
	nt_enum_unset(h_enum_board);
	return TRUE;
}


static int adjust_scroll_pos(nt_window_tp wp, 
			ctx_board_menu_tp ctxp)
{
	int scr_lines = wp->lines;
	int cursor_pos = ctxp->cursor_pos;
	int scroll_pos = ctxp->scroll_pos;

	if(cursor_pos < scroll_pos){
		scroll_pos = cursor_pos;
		ctxp->scroll_pos = scroll_pos;
	}else if((scroll_pos + (scr_lines*2)) <= cursor_pos){
		scroll_pos = cursor_pos - (scr_lines*2) + 1;
		ctxp->scroll_pos = scroll_pos;
	}
	return 0;
}

static BOOL adjust_scroll_pos2(nt_window_tp wp, 
		ctx_board_menu_tp ctxp, category_data_tp  datap)
{
	int scr_lines = wp->lines;
	int cursor_pos = ctxp->cursor_pos;
	int scroll_pos = ctxp->scroll_pos;
	int contents_count = get_display_folder_contents_count(datap);
	if(contents_count == 0)
		return FALSE;
	cursor_pos += contents_count;

	if(cursor_pos < scroll_pos){
		scroll_pos = cursor_pos;
		ctxp->scroll_pos = scroll_pos;
		return TRUE;
	}else if((scroll_pos + (scr_lines*2)) <= cursor_pos){
		scroll_pos = cursor_pos - (scr_lines*2) + 1;
		ctxp->scroll_pos = scroll_pos;
		return TRUE;
	}
	return FALSE;
}


static int page_up(nt_window_tp wp, ctx_board_menu_tp ctxp)
{
	int scroll_pos = ctxp->scroll_pos;
	int cursor_pos = ctxp->cursor_pos - scroll_pos;

	scroll_pos -= wp->lines;
	if(scroll_pos < 0)
		scroll_pos = 0;
	ctxp->scroll_pos = scroll_pos;
	ctxp->cursor_pos = scroll_pos + cursor_pos;
	return 0;
}
static int page_down(nt_window_tp wp, ctx_board_menu_tp ctxp)
{
	int scr_lines = wp->lines;
	int scroll_pos = ctxp->scroll_pos;
	int cursor_pos = ctxp->cursor_pos - scroll_pos;
	int menu_disp_row = get_menu_disp_row(ctxp);

	menu_disp_row -= scr_lines*2;
	if(menu_disp_row <= 0){
		ctxp->scroll_pos = 0;
		ctxp->cursor_pos = cursor_pos;
		return 0;
	}
	scroll_pos += wp->lines;
	if(scroll_pos >= menu_disp_row)
		scroll_pos = menu_disp_row -1;
	ctxp->scroll_pos = scroll_pos;
	ctxp->cursor_pos = scroll_pos + cursor_pos;
	return 0;
}


static ctx_board_menu_tp init_context(nt_2ch_model_handle h_model)
{
	int idx;
	nt_enum_handle h_enum_category;
	nt_category_handle h_category;
	
	ctx_board_menu_tp ctxp = 
		(ctx_board_menu_tp)calloc(1,sizeof(ctx_board_menu_t));
	if(!ctxp)
		return NULL;

	h_enum_category = nt_2ch_model_get_category_enum(h_model);
	if(!h_enum_category)
		return NULL;

	ctxp->category_num = nt_enum_get_count(h_enum_category);
	ctxp->category_list = 
		calloc(ctxp->category_num, sizeof(category_data_t));
	if(!ctxp->category_list){
		free(ctxp);
		nt_enum_unset(h_enum_category);
		return NULL;
	}

	idx = 0;
	while(NULL != (h_category =
			(nt_category_handle)nt_enum_fetch(h_enum_category))){
		ctxp->category_list[idx].h_category = h_category;
		nt_category_add_ref(h_category);
		idx++;
	}
	assert(idx == ctxp->category_num);	
	nt_enum_unset(h_enum_category);
	return ctxp;
}

void free_board_menu_ctx(void *ptr)
{
	ctx_board_menu_tp ctxp;
	nt_category_handle h_category;
	int i;
	
	if(!ptr)
		return;
		
	ctxp = (ctx_board_menu_tp)ptr;
	
	for(i = 0; i < ctxp->category_num; i++){
		h_category = ctxp->category_list[i].h_category;
		nt_category_release_ref(h_category);
	}
	free(ctxp->category_list);
	free(ctxp);
}


static int move_cursor_right_colmn(nt_window_tp wp, 
		ctx_board_menu_tp ctxp)
{
	int scr_lines = wp->lines;
	int cur_pos = ctxp->cursor_pos;
	int scroll_pos = ctxp->scroll_pos;
	int menu_disp_num;

	if(cur_pos - scroll_pos >= scr_lines)
		return cur_pos;
	cur_pos += scr_lines;
	menu_disp_num = get_menu_disp_row(ctxp);
	if(menu_disp_num > cur_pos)
		ctxp->cursor_pos = cur_pos;
	else 
		ctxp->cursor_pos = menu_disp_num - 1;
	return ctxp->cursor_pos;
}

static int move_cursor_left_colmn(nt_window_tp wp, 
		ctx_board_menu_tp ctxp)
{
	int scr_lines = wp->lines;
	int cur_pos = ctxp->cursor_pos;
	int scroll_pos = ctxp->scroll_pos;
	
	if(cur_pos - scroll_pos < scr_lines)
		return cur_pos;
	cur_pos -= scr_lines;

	if(0 > cur_pos-scroll_pos)
		ctxp->cursor_pos = scroll_pos;
	else 
		ctxp->cursor_pos = cur_pos;
	return ctxp->cursor_pos;
}

static int increment_cursor(ctx_board_menu_tp ctxp)
{
	int cur_pos = ctxp->cursor_pos + 1;
	int menu_disp_num = get_menu_disp_row(ctxp);
	if(menu_disp_num > cur_pos)
		ctxp->cursor_pos = cur_pos;
	return ctxp->cursor_pos;
}

static int decrement_cursor(ctx_board_menu_tp ctxp)
{
	int cur_pos = ctxp->cursor_pos - 1;
	if(0 <= cur_pos)
		ctxp->cursor_pos = cur_pos;
	return ctxp->cursor_pos;
}

static int get_display_folder_contents_count(category_data_tp datap)
{
	nt_enum_handle h_enum;
	int num;
	
	if(!IS_SET_F(datap->flag, FOLDER_OPEN))
		return 0;
	h_enum = nt_category_get_board_enum(datap->h_category);
	if(!h_enum)
		return 0;
	num = nt_enum_get_count(h_enum);
	nt_enum_unset(h_enum);
	return num;
}

static int get_menu_disp_row(ctx_board_menu_tp ctxp)
{
	int i;
	int num = 0;
	category_data_tp datap;

	for(i = 0; i < ctxp->category_num; i++){
		num++;
		datap = ctxp->category_list + i;
		if(IS_SET_F(datap->flag, FOLDER_OPEN)){
			num += nt_category_get_board_count(datap->h_category);
		}
	}
	return num;
}

static int parse_cmd1(const char *param)
{
	assert(param);
	if(0 == strncmp(NT_COMMAND1_SEARCH_1,param,
			strlen(NT_COMMAND1_SEARCH_1)) ||
		0 == strncmp(NT_COMMAND1_SEARCH_2,param,
			strlen(NT_COMMAND1_SEARCH_2))){
		return NT_CMD_SEARCH_THREAD;
	}else if(0 == strncmp(NT_COMMAND1_FAVORITE_1,param,
			strlen(NT_COMMAND1_FAVORITE_1)) ||
		0 == strncmp(NT_COMMAND1_FAVORITE_2,param,
			strlen(NT_COMMAND1_FAVORITE_2))){
		return NT_CMD_FAVORITE;
	}else{
		return NT_CMD_NONE;
	}
}


