/* 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 "nt_string.h"
#include "utils/nt_std_t.h"
#include "utils/text.h"
#include "_2ch/model_2ch.h"
#include "_2ch/search_2ch.h"
#include "ui/disp.h"
#include "ui/disp_string.h"
#include "usr/usr_db_t.h"


typedef struct tag_favorite_ctx_t *favorite_ctx_tp;
typedef struct tag_favorite_ctx_t {
	int prev_state;
	int cur_cursor;
	int scroll_pos;
	int visible_rows;
	int visible_items;
	BOOL board_folder_open;
}favorite_ctx_t;

static favorite_ctx_tp init_context();
static void set_visible_row_count(
		favorite_ctx_tp ctxp, nt_favorite_handle h_favorite);
static int get_screen_offset(
		favorite_ctx_tp ctxp, nt_favorite_handle h_favorite, int cursor);

int disp_favorite(nt_window_tp wp, 
		int prev_state, nt_2ch_model_handle h_model,
		nt_favorite_handle h_favorite, nt_usr_db_handle h_usr_db,
		void **result_hadle, nt_searched_thread_handle *h_sel_threadp)
{
	favorite_ctx_tp ctxp;
	attr_t attr;
	nt_mutex_handle h_mutex;
	nt_favorite_board_handle h_board;
	nt_favorite_grp_handle h_grp;
	nt_favorite_thread_handle h_thread;
	const wchar_t * cptr;
	int row, len , nwrite, cursor;
	nt_enum_handle h_enum, h_enum_thread;
	wchar_t wc[256];
	const wchar_t *board_name, *title, *dat_name;
	int result_state;
	BOOL del_flag;
	BOOL sel_flag;
	BOOL sel_flag2;
	int offset;
	int read_count, num_res;
	
	result_state = DISP_STATE_FAVORITE;
	del_flag = FALSE;
	sel_flag = FALSE;
	sel_flag2 = FALSE;
	
	ctxp = (favorite_ctx_tp)wp->data;
	if(!ctxp){
		ctxp = init_context();
		if(!ctxp)
			return DISP_STATE_ERROR;
		wp->data = ctxp;
	}
	if(prev_state != DISP_STATE_FAVORITE){
		if(!nt_favorite_set_read_count(h_favorite, h_usr_db)){
			fputs("Couldn't open user_db handle", stderr);
		}
		ctxp->prev_state = prev_state;
	}
	
	switch(wp->key){
	case NT_KEY_CMD_BOARD_UPDATE:
		if(!nt_favorite_set_num_res(h_model, h_favorite)){
			fputs("Couldn't open user_db handle", stderr);
		}
		break;
	case NT_KEY_REFRESH:
		return DISP_STATE_REFRESH; 
	case NT_KEY_CLOSE:
	case KEY_LEFT:
		return DISP_STATE_BOARDMENU;
	case NT_KEY_RIGHT:
		return ctxp->prev_state;
	case NT_KEY_LEFT:
		sel_flag2 = TRUE;
		break;
	case NT_KEY_UP:
	case KEY_UP:
		if(ctxp->cur_cursor > 0)
			ctxp->cur_cursor--;
		offset = get_screen_offset(
				ctxp, h_favorite, ctxp->cur_cursor);
		if(offset < ctxp->scroll_pos)
			ctxp->scroll_pos = offset;
		break;
	case NT_KEY_DOWN:
	case KEY_DOWN:
		if(ctxp->cur_cursor < (ctxp->visible_items-1))
			ctxp->cur_cursor++;
		offset = get_screen_offset(
				ctxp, h_favorite, ctxp->cur_cursor);
		if(offset >= ctxp->scroll_pos + wp->lines)
			ctxp->scroll_pos = offset - wp->lines + 2;
		break;
	case NT_KEY_DEL:
		del_flag = TRUE;
		break;
	case NT_KEY_SELECT:
	case KEY_RIGHT:
		sel_flag = TRUE;
		break;
	case NT_KEY_PAGEUP:
	case KEY_PPAGE:
	case NT_KEY_PAGEDOWN:
	case KEY_NPAGE:
	case NT_KEY_BOTTOM:
	case KEY_END:
	default:
		break;
	}
	
	h_mutex = nt_favorite_get_mutex(h_favorite);
	if(!h_mutex){
		return DISP_STATE_ERROR;
	}
	if(!nt_mutex_lock(h_mutex)){
		return DISP_STATE_ERROR;
	}
	set_visible_row_count(ctxp, h_favorite);
	if(ctxp->cur_cursor >= (ctxp->visible_items-1))
		ctxp->cur_cursor = ctxp->visible_items-1;
	
	row = 0;
	cursor = 0;
	attr = 0;
	
	if(cursor == ctxp->cur_cursor)
		attr = WA_REVERSE;
	else
		attr = 0;
	if(row >= ctxp->scroll_pos){
		wmove(wp->wp, row - ctxp->scroll_pos, 0);
		nt_add_wstr(wp->wp, L" + お気に入りの板", WA_BOLD | attr);
	}
	cursor++;
	row++;
	
	
	
	if(ctxp->board_folder_open){
		h_enum = nt_favorite_acquire_board_enum(h_favorite);
		if(h_enum){
			while(NULL != (h_board =
					(nt_favorite_board_handle)nt_enum_fetch(h_enum))){
				cptr = nt_favorite_board_get_name(h_board);
				if(!cptr)
					continue;
				if(cursor == ctxp->cur_cursor){
					attr = WA_REVERSE;
					if(del_flag){
						*result_hadle = h_board;
						result_state |= DISP_CMD_DEL_FAVORITE_BOARD;
					}else if(sel_flag){
						board_name = nt_favorite_board_get_name(h_board);
						(*h_sel_threadp) = nt_searched_thread_alloc(
							board_name, NULL, NULL);
						if((*h_sel_threadp))
							result_state |= DISP_CMD_SEL_FAVORITE_BOARD;
					}
				}else{
					attr = 0;
				}
				if(row >= ctxp->scroll_pos){
					wmove(wp->wp, row - ctxp->scroll_pos, 0);
					nt_add_wstr(wp->wp, L"    - ", attr);
					nt_add_wstr(wp->wp, cptr, attr);
				}
				cursor++;
				row++;
			}
			nt_enum_unset(h_enum);
		}
	}
	
	
	h_enum = nt_favorite_acquire_grp_enum(h_favorite);
	if(h_enum){
		while(NULL != (h_grp =
				(nt_favorite_grp_handle)nt_enum_fetch(h_enum))){
			cptr = nt_favorite_grp_get_name(h_grp);
			if(!cptr)
				continue;
			if(cursor == ctxp->cur_cursor)
				attr = WA_REVERSE;
			else
				attr = 0;
			wmove(wp->wp, row, 0); 
			nt_add_wstr(wp->wp, L" + ", WA_BOLD | attr);
			nt_add_wstr(wp->wp, cptr, WA_BOLD | attr);
			row++;
			cursor++;
			h_enum_thread = nt_favorite_acquire_thread_enum(h_grp);
			if(!h_enum_thread)
				continue;
			while(NULL != (h_thread =
					(nt_favorite_thread_handle)nt_enum_fetch(h_enum_thread))){
				board_name = nt_favorite_thread_get_board_name(h_thread);
				dat_name = nt_favorite_thread_get_dat_name(h_thread);
				read_count = nt_favorite_thread_get_read_count(h_thread);
				num_res = nt_favorite_thread_get_estimate_res_count(h_thread);
				title = nt_favorite_thread_get_title(h_thread);
				if(cursor == ctxp->cur_cursor){
					attr = WA_REVERSE;
					if(del_flag){
						*result_hadle = h_thread;
						result_state |= DISP_CMD_DEL_FAVORITE_THREAD;
					}else if(sel_flag){
						(*h_sel_threadp) = nt_searched_thread_alloc(
							board_name, dat_name, title);
						if((*h_sel_threadp))
							result_state |= DISP_CMD_SEL_FAVORITE_THREAD;
					}else if(sel_flag2){
						(*h_sel_threadp) = nt_searched_thread_alloc(
							board_name, NULL, NULL);
						if((*h_sel_threadp))
							result_state |= DISP_CMD_SEL_FAVORITE_BOARD;
					}
				}else{
					attr = 0;
				}
				if(num_res > 0){
					if(num_res > read_count){
						if(-1 == swprintf(wc, sizeof(wc)/sizeof(wchar_t)-1, 
							L"[%ls] - %ls (%d)未読%d", board_name, title, num_res, num_res-read_count)){
							break;
						}
					}else if(read_count > 0){
						if(-1 == swprintf(wc, sizeof(wc)/sizeof(wchar_t)-1, 
							L"[%ls] - %ls (%d)未読0", board_name, title, num_res)){
							break;
						}
					}else{
						if(-1 == swprintf(wc, sizeof(wc)/sizeof(wchar_t)-1, 
							L"[%ls] - %ls (%d)", board_name, title, num_res)){
							break;
						}
					}
				}else{
					if(read_count > 0){
						if(-1 == swprintf(wc, sizeof(wc)/sizeof(wchar_t)-1, 
							L"%ls[%ls] - %ls (%d)", NT_TEXT_UNTRACKED_LOG_NAME,
							board_name, title, read_count)){
							break;
						}
					}else{
						if(-1 == swprintf(wc, sizeof(wc)/sizeof(wchar_t)-1, 
							L"%ls[%ls] - %ls", NT_TEXT_UNTRACKED_LOG_NAME,
							board_name, title)){
							break;
						}
					}
				}
				len = wcslen(wc);
				if(row >= ctxp->scroll_pos){
					wmove(wp->wp, row - ctxp->scroll_pos, 0);
					nt_add_wnch(wp->wp, L' ', attr, wp->cols);
					wmove(wp->wp, row - ctxp->scroll_pos, 0);
					nwrite = nt_add_wnstr(wp->wp, wc, attr, wp->cols);
				}else{
					nwrite = nt_get_wc_count_within_colmns(wc, wp->cols);
				}
				row++;
				if(row >= ctxp->scroll_pos){
					wmove(wp->wp, row - ctxp->scroll_pos, 0);
					nt_add_wnch(wp->wp, L' ', WA_UNDERLINE | attr, wp->cols);
					if(len > nwrite){
						wmove(wp->wp, row - ctxp->scroll_pos, 0);
						nwrite = nt_add_wnstr(wp->wp, wc + nwrite, WA_UNDERLINE | attr, wp->cols);
					}
				}
				row++;
				cursor++;
			}
			nt_enum_unset(h_enum_thread);
		}
		nt_enum_unset(h_enum);
	}
	if(!nt_mutex_unlock(h_mutex)){
		assert(0);
	}
	return result_state;
}

static void set_visible_row_count(
		favorite_ctx_tp ctxp, nt_favorite_handle h_favorite)
{
	nt_enum_handle h_enum, h_enum_thread;
	nt_favorite_grp_handle h_grp;
	int thread_cnt;
	
	ctxp->visible_rows = 1;
	
	if(ctxp->board_folder_open){
		h_enum = nt_favorite_acquire_board_enum(h_favorite);
		if(h_enum){
			ctxp->visible_rows += nt_enum_get_count(h_enum);
			nt_enum_unset(h_enum);
		}
	}
	ctxp->visible_items = ctxp->visible_rows;
	h_enum = nt_favorite_acquire_grp_enum(h_favorite);
	if(h_enum){
		while(NULL != (h_grp =
				(nt_favorite_grp_handle)nt_enum_fetch(h_enum))){
			ctxp->visible_items++;
			ctxp->visible_rows++;
			if(!nt_favorite_grp_get_flag(h_grp, NT_FAVORITE_GRP_FLAG_FOLDER_OPEN))
				continue;
			h_enum_thread = nt_favorite_acquire_thread_enum(h_grp);
			if(h_enum_thread){
				thread_cnt = nt_enum_get_count(h_enum_thread);
				ctxp->visible_items += thread_cnt;
				ctxp->visible_rows += thread_cnt * 2;
				nt_enum_unset(h_enum_thread);
			}
		}
		nt_enum_unset(h_enum);
	}
}


static int get_screen_offset(
		favorite_ctx_tp ctxp, nt_favorite_handle h_favorite, int cursor)
{
	nt_enum_handle h_enum, h_enum_thread;
	nt_favorite_grp_handle h_grp;
	int item;
	int row;
	int num;
	
	item = 0;
	row = 0;
	if(cursor == item)
		return 0;
	item++;
	
	if(ctxp->board_folder_open){
		h_enum = nt_favorite_acquire_board_enum(h_favorite);
		if(h_enum){
			item += nt_enum_get_count(h_enum);
			nt_enum_unset(h_enum);
			if(item > cursor){
				return cursor;
			}
		}
	}
	row = item;
	
	h_enum = nt_favorite_acquire_grp_enum(h_favorite);
	if(h_enum){
		while(NULL != (h_grp =
				(nt_favorite_grp_handle)nt_enum_fetch(h_enum))){
			if(cursor == item){
				nt_enum_unset(h_enum);
				return row;
			}
			item++;
			row++;
			if(!nt_favorite_grp_get_flag(h_grp, NT_FAVORITE_GRP_FLAG_FOLDER_OPEN))
				continue;
			h_enum_thread = nt_favorite_acquire_thread_enum(h_grp);
			if(h_enum_thread){
				num = nt_enum_get_count(h_enum_thread);
				if((item+num) > cursor){
					nt_enum_unset(h_enum);
					nt_enum_unset(h_enum_thread);
					return row + ((cursor-item)*2);
				}
				item += num;
				row += num * 2;
				nt_enum_unset(h_enum_thread);
			}
		}
		nt_enum_unset(h_enum);
	}
	return row;
}


static favorite_ctx_tp init_context()
{
	favorite_ctx_tp ctxp;
	ctxp = malloc(sizeof(favorite_ctx_t));
	if(!ctxp)
		return NULL;
	ctxp->prev_state = DISP_STATE_ERROR;
	ctxp->board_folder_open = TRUE;
	ctxp->cur_cursor = 0;
	ctxp->visible_rows = 0;
	ctxp->visible_items = 0;
	ctxp->scroll_pos = 0;
	return ctxp;
}

void free_favorite_ctx(void *ptr)
{
	favorite_ctx_tp ctxp;
	
	assert(ptr);
	
	ctxp = (favorite_ctx_tp)ptr;
	free(ctxp);
}

