/* 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 <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ncursesw/ncurses.h>
#include <locale.h>
#include <iconv.h>
#include <netinet/in.h>
#include <assert.h>

#include "env.h"
#include "error.h"
#include "nt_string.h"
#include "utils/nt_std_t.h"
#include "net/nt_http.h"
#include "net/nt_socket.h"
#include "net/nt_cookie.h"
#include "utils/file.h"
#include "usr/usr_db_t.h"
#include "utils/nt_mutex.h"
#include "utils/nt_pthread.h"
#include "utils/nt_timer.h"
#include "usr/favorite_t.h"
#include "_2ch/_2ch.h"
#include "_2ch/maru_2ch.h"
#include "_2ch/search_2ch.h"
#include "ui/disp.h"
#include "ui/disp_win.h"
#include "ui/disp_string.h"

#define S_SIZE 	(1024)

static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr);
static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
			nt_favorite_handle h_favorite, 
			nt_favorite_grp_handle h_favorite_grp);
static void print_error(WINDOW *wp, const wchar_t *msg);

static void _2ch_selected_item_free(void *ptr)
{
	nt_2ch_selected_item_release_ref(
		(nt_2ch_selected_item_handle)ptr);

}

int main(int argc, char *argv[])
{
	int result = 1;
	WINDOW *scrp;
	nt_usr_db_handle usr_db_handle;
	nt_favorite_handle h_favorite;
	nt_favorite_grp_handle h_favorite_grp;
	nt_link_tp text_linkp, text2_linkp;
	const char *err_msg;

	if(0 != set_option(argc, argv)){
		return 1;
	}


	sleep(1);

	setlocale(LC_ALL, "ja_JP.UTF-8");

	usr_db_handle = nt_usr_db_init_lib(USR_LOG_DB_PATH);
	if(!usr_db_handle){
		fputs("Couldn't initialize usr database.\n", stderr);
		printf("Exit.");
		return 1;
	}

	scrp = initscr();
	if(!scrp){
		fputs("Couldn't initialize Curses libraly.\n", stderr);
		printf("Exit.");
		return 1;
	}

	nt_timer_lib_init();
	
	nt_mutex_lib_init();
	
	if(!nt_pthread_lib_init(
			NT_PTHREAD_POOL_SIZE, 
			NT_PTHREAD_POOL_QUEUE_SIZE, 
			&err_msg)){
		if(err_msg)
			fputs(err_msg, stderr);
		goto ERROR_TRAP;
	}
	
	if(!nt_2ch_model_init()){
		fputs("Failed to read board menu data.\n", stderr);
		goto ERROR_TRAP;
	}

	if(!nt_init_board_menu()){
		fputs("Failed to initialize board menu data.\n", stderr);
		goto ERROR_TRAP;
	}
	

	h_favorite = nt_favorite_alloc(L"favorite");
	if(!h_favorite){
		goto ERROR_TRAP;
	}
	h_favorite_grp = nt_favorite_grp_alloc(h_favorite, 
				L"お気に入りのスレッド",
				NT_FAVORITE_GRP_FLAG_FOLDER_OPEN);
	if(!h_favorite_grp){
		nt_favorite_release_ref(h_favorite);
		goto ERROR_TRAP;
	}
	
	text_linkp = nt_read_text_file(USR_FAVORITE_BOARD_FILE_PATH);
	if(text_linkp){
		nt_favorite_load_boards(h_favorite, text_linkp);
		nt_all_link_free(text_linkp, free);
	}
	text_linkp = nt_read_text_file(USR_FAVORITE_THREAD_FILE_PATH);
	if(text_linkp){
		nt_favorite_load_threads(h_favorite, h_favorite_grp, text_linkp);
		nt_all_link_free(text_linkp, free);
	}
	
	cbreak();
	noecho();

	if(DoLoop(scrp, usr_db_handle, h_favorite, h_favorite_grp))
		result = 0;

	echo();
	nocbreak();
	
	text_linkp = nt_favorite_retrieve_boards(h_favorite);
	if(text_linkp){
		nt_write_text_file(USR_FAVORITE_BOARD_FILE_PATH, text_linkp);
		nt_all_link_free(text_linkp, free);
	}else{
		unlink(USR_FAVORITE_BOARD_FILE_PATH);
	}
	if(nt_favorite_retrieve_threads(h_favorite, 
			&text_linkp, &text2_linkp)){
		if(text_linkp)
			nt_all_link_free(text_linkp, free);
		if(text2_linkp){
			nt_write_text_file(USR_FAVORITE_THREAD_FILE_PATH, text2_linkp);
			nt_all_link_free(text2_linkp, free);
		}else{
			unlink(USR_FAVORITE_THREAD_FILE_PATH);
		}
	}

	nt_favorite_grp_release_ref(h_favorite_grp);
	nt_favorite_release_ref(h_favorite);

ERROR_TRAP:
	clear();


	nt_2ch_model_release_ref(app_2ch_model);

	endwin();

	nt_usr_db_finish_lib(usr_db_handle);
	
	nt_pthread_lib_finish();
	
	nt_mutex_lib_finish();

	nt_timer_lib_finish();
	
	return (result);
}

#define TIMER_ID_AUTO_UPDATE_NONE 0
#define TIMER_ID_AUTO_UPDATE 1
#define TIMER_ID_AUTO_SCROLL 2
static int auto_update_timer_func(int id)
{
	switch(id){
	case TIMER_ID_AUTO_UPDATE:
		return TIMER_ID_AUTO_UPDATE;
	case TIMER_ID_AUTO_SCROLL:
		return TIMER_ID_AUTO_SCROLL;
	}
	return TIMER_ID_AUTO_UPDATE_NONE;
}

static BOOL DoLoop(WINDOW *scrp, nt_usr_db_handle db_handle,
		nt_favorite_handle h_favorite, 
		nt_favorite_grp_handle h_favorite_grp)
{
	int ch, state, num;
	int disp_state, nresult;
	nt_window_tp bwinp = NULL;
	nt_window_tp twinp = NULL;
	nt_window_tp rwinp = NULL;
	nt_window_tp search_winp = NULL;
	nt_window_tp favorite_winp = NULL;
	char buf[256];
	wchar_t title_buf[128];
	wchar_t wch;
	const wchar_t *title;
	const wchar_t *status_msg;
	BOOL result = FALSE;
	nt_write_data_handle h_write_data;
	nt_maru_2ch_tp marup;
	nt_cookie_tp cookiep;
	char *search;
	nt_searched_thread_handle h_searched_thread;
	nt_2ch_selected_item_handle h_sel_items;
	nt_2ch_selected_item_handle h_sel_items_tmp;
	nt_favorite_board_handle h_favorite_board;
	nt_favorite_thread_handle h_favorite_thread;
	void *handle;
	nt_pthread_result_t async_data;
	nt_link_tp linkp;
	BOOL auto_scrolling;
	nt_timer_handle h_timer_auto_update;
	nt_timer_handle h_timer_auto_scroll;
	nt_timer_handle h_timer;
	
	state = DISP_STATE_BOARDMENU;
	if(INIT_DISP_STATE == NT_INTI_DISP_FAVORITE){
		disp_state = DISP_STATE_FAVORITE; 
	}else{
		disp_state = DISP_STATE_BOARDMENU; 
	}
	cookiep = nt_load_cookies(USR_COOKIE_PATH);

	if(MARU_ID && MARU_PW) 
		marup = nt_maru_2ch_alloc(MARU_ID, MARU_PW);
	h_timer_auto_scroll = nt_timer_alloc(
			TIMER_ID_AUTO_SCROLL, -1, auto_update_timer_func);
	h_timer_auto_update = nt_timer_alloc(
			TIMER_ID_AUTO_UPDATE, NT_AUTO_UPDATE_INTERVAL, auto_update_timer_func);

	h_write_data = NULL;
	marup = NULL;
	status_msg = NULL;
	h_searched_thread = NULL;
	h_sel_items_tmp = NULL;
	h_sel_items = nt_2ch_selected_item_alloc();
	if(!h_sel_items)
		return FALSE;

	ch = NT_KEY_NONE;
	bwinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
	if(!bwinp)
		return FALSE;
	twinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
	if(!twinp)
		return FALSE;
	rwinp = nt_disp_win_alloc(scrp, LINES-1, COLS, 1, 0, buf);
	if(!rwinp)
		return FALSE;
	
	
	keypad(stdscr, true);
	while(1){
		if(FORCE_REFRESH)
			wclear(scrp);
		else
			werase(scrp);
			
		
		switch(disp_state){
		case DISP_STATE_BOARDMENU:
			werase(bwinp->wp);
			bwinp->key = ch;
			draw_title(scrp, L"板一覧", WA_REVERSE);
			if(!nt_disp_win_move(scrp, bwinp, LINES-1, COLS, 1, 0))
				goto END_WHILE;
			state = disp_board_menu(bwinp, app_2ch_model, h_sel_items);
			if(DISP_CMD(state)){
				if(DISP_CMD(state) == DISP_CMD_ADD_FAVORITE){
					h_favorite_board = nt_favorite_board_alloc(
						h_favorite,
						nt_2ch_selected_item_get_board_name(h_sel_items));
					if(h_favorite_board){
						nt_favorite_board_release_ref(h_favorite_board);
						//favorite_dump(h_favorite);
					}
				}
				state = DISP_STATE_BOARDMENU;
				ch = NT_KEY_NONE;
			}
			if(DISP_STATE_ERROR == state){
				goto END_WHILE;
			}else if(DISP_STATE_THREADTITLE == state){
				if(nt_read_board(h_sel_items)){
					disp_state = state;
					state = DISP_STATE_BOARDMENU;
					if(twinp->data){
						free_threadlist_ctx(twinp->data);
						twinp->data = NULL;
					}
					ch = NT_KEY_NONE;
					continue;
				}else{
					print_error(scrp, NT_ERR_MSG_COUDLNOT_READ_BOARD);
				}
			}else if(state == DISP_STATE_SEARCH_THREAD){
				state = DISP_STATE_BOARDMENU;
				disp_state = DISP_STATE_SEARCH_THREAD;
				ch = NT_KEY_NONE;
				continue;
			}else if(DISP_STATE_FAVORITE == state){
				state = DISP_STATE_BOARDMENU;
				disp_state = DISP_STATE_FAVORITE;
				ch = NT_KEY_NONE;
				continue;
			}
			break;
		case DISP_STATE_THREADTITLE:
			werase(twinp->wp);
			twinp->key = ch;
			twinp->status_msg = NULL;
			title = nt_2ch_selected_item_get_board_name(h_sel_items);
			draw_title(scrp, title, WA_REVERSE);
			if(!nt_disp_win_move(scrp, twinp, LINES-1, COLS, 1, 0))
				goto END_WHILE;
			state = disp_threadlist(twinp, state, h_sel_items, db_handle);
			if(DISP_CMD(state)){
				if(DISP_CMD(state) == DISP_CMD_ADD_FAVORITE){
					h_favorite_thread = nt_favorite_thread_alloc(
						h_favorite_grp,
						nt_2ch_selected_item_get_thread_dat_name(h_sel_items),
						nt_2ch_selected_item_get_board_name(h_sel_items),
						nt_2ch_selected_item_get_thread_title(h_sel_items));
					if(h_favorite_thread){
						nt_favorite_thread_release_ref(h_favorite_thread);
						//favorite_dump(h_favorite);
						status_msg = NT_INFO_ADD_FAVORITE_SUCCEEDED;
					}else{
						status_msg = NT_ERR_MSG_ADD_FAVORITE_FAILED;
					}
				}
				state = DISP_STATE_THREADTITLE;
				ch = NT_KEY_NONE;
			}else if(DISP_STATE_ERROR == state){
				goto END_WHILE;
			}else if(DISP_STATE_BOARDMENU == state){
					disp_state = state;
					ch = NT_KEY_NONE;
					continue;
			}else if(DISP_STATE_REFRESH == state){
				if(nt_read_board(h_sel_items)){
					if(twinp->data){
						free_threadlist_ctx(twinp->data);
						twinp->data = NULL;
					}
					ch = NT_KEY_NONE;
					status_msg = NT_INFO_REFRESH_BOARD_SUCCESS;
					continue;
				}else{
					status_msg = NT_ERR_MSG_COUDLNOT_READ_BOARD;
				}
				state = DISP_STATE_THREADTITLE;
			}else if(DISP_STATE_RESLIST == state){
				if(!nt_read_thread(h_sel_items)){
					wclear(scrp);
					ch = NT_KEY_NONE;
					continue;
				}
				if(twinp->data){
					init_threadlist_ctx(twinp->data);
				}
				if(rwinp->data){
					free_reslist_ctx(rwinp->data);
					rwinp->data = NULL;
				}
				disp_state = state;
				state = DISP_STATE_THREADTITLE;
				ch = NT_KEY_NONE;
				continue;
			}else if(DISP_STATE_SEARCH_THREAD == state){
				state = DISP_STATE_THREADTITLE;
				disp_state = DISP_STATE_SEARCH_THREAD;
				ch = NT_KEY_NONE;
				continue;
			}else if(DISP_STATE_FAVORITE == state){
				state = DISP_STATE_THREADTITLE;
				disp_state = DISP_STATE_FAVORITE;
				ch = NT_KEY_NONE;
				continue;
			}else{
				status_msg = twinp->status_msg;
			}
			break;
		case DISP_STATE_RESLIST:
			werase(rwinp->wp);
			title = nt_2ch_selected_item_get_thread_title(h_sel_items);
			if(!title){
				num = draw_title(scrp, L"Title not found.", WA_REVERSE);
			}else if(-1 == swprintf(title_buf, sizeof(title_buf)/sizeof(wchar_t),
					L"[%ls] - %ls", 
					nt_2ch_selected_item_get_board_name(h_sel_items),
					title)){
				num = draw_title(scrp, title, WA_REVERSE);
			}else{
				num = draw_title(scrp, title_buf, WA_REVERSE);
			}
			if(!nt_disp_win_move(scrp, rwinp, 
						LINES - num, COLS, num, 0))
				goto END_WHILE;
			rwinp->key = ch;
			state = disp_reslist(rwinp, state, h_sel_items, db_handle);
			auto_scrolling = FALSE;
			if(DISP_CMD(state)){
				if(DISP_CMD(state) == DISP_CMD_AUTO_SCROLL){
					if(0 >= nt_timer_get_interval(h_timer_auto_scroll)){
						nt_timer_set_interval(
							h_timer_auto_scroll, NT_AUTO_SCROLL_INTERVAL);
					}
					auto_scrolling = TRUE;
				}
				DISP_CLR_CMD(state);
			}
			if(!auto_scrolling){
				nt_timer_set_interval(h_timer_auto_scroll, -1);
			}
			if(DISP_STATE_ERROR == state){
				goto END_WHILE;
			}else if(state == DISP_STATE_REFRESH){
				state = DISP_STATE_RESLIST;
				ch = NT_KEY_NONE;
				if(!nt_read_thread(h_sel_items)){
					status_msg = NT_ERR_MSG_REFRESH_THREAD_FAILED;
					wclear(scrp);
					continue;
				}
				if(rwinp->data){
					free_reslist_ctx(rwinp->data);
					rwinp->data = NULL;
				}
				status_msg = NT_INFO_REFRESH_THREAD_SUCCESS;
				wclear(scrp);
				continue;
			}else if(state == DISP_STATE_SEARCH_THREAD){
				state = DISP_STATE_RESLIST;
				disp_state = DISP_STATE_SEARCH_THREAD;
				ch = NT_KEY_NONE;
				continue;
			}else if(DISP_STATE_FAVORITE == state){
				state = DISP_STATE_RESLIST;
				disp_state = DISP_STATE_FAVORITE;
				ch = NT_KEY_NONE;
				continue;
			}else if(state != DISP_STATE_RESLIST){
				disp_state = state;
				ch = NT_KEY_NONE;
				continue;
			}
			break;
		case DISP_STATE_EDITOR:
			disp_state = DISP_STATE_RESLIST;
			state = DISP_STATE_RESLIST;
			ch = NT_KEY_NONE;
			if(h_write_data)
				nt_write_data_release_ref(h_write_data);
			h_write_data = nt_write_data_alloc();
			if(!h_write_data)
				goto END_WHILE;
			if(disp_editor(h_write_data)){
				if(marup && !marup->sid)
					get_session_id(marup);
				if(nt_write_msg(h_sel_items, 
						h_write_data, cookiep, marup)){
					disp_state = DISP_STATE_HTML_RESULT;
					continue;
				}
			}
			status_msg = nt_write_data_get_status_msg(h_write_data);
			wclear(scrp);
			continue;
		case DISP_STATE_HTML_RESULT:
			nresult = disp_html_result(h_write_data);
			if(0 == nresult){
				if(!nt_read_thread(h_sel_items))
					break;
				if(rwinp->data){
					free_reslist_ctx(rwinp->data);
					rwinp->data = NULL;
				}
			}else if(1 == nresult){
				if(nt_write_msg(h_sel_items, 
						h_write_data, cookiep, marup)){
					if(0 == disp_html_result(h_write_data)){
						if(!nt_read_thread(h_sel_items))
							break;
						if(rwinp->data){
							free_reslist_ctx(rwinp->data);
							rwinp->data = NULL;
						}
					}
				}
			}
			disp_state = DISP_STATE_RESLIST;
			state = DISP_STATE_RESLIST;
			ch = NT_KEY_NONE;
			status_msg = nt_write_data_get_status_msg(h_write_data);
			wclear(scrp);
			continue;
		case DISP_STATE_SEARCH_THREAD:
			draw_title(scrp, L"全板検索", WA_REVERSE);
			if(!search_winp)
				search_winp = nt_disp_win_alloc(
						scrp, LINES-1, COLS, 1, 0, buf);
			if(!search_winp)
				goto END_WHILE;
			search_winp->key = ch;
			linkp = NULL;
			if(nt_get_search_text(buf, &search)){
				if(search){
					linkp = nt_search_all_board(
							app_2ch_model, search, &status_msg);
					free(search);
					buf[0] = '\0';
				}
			}
			h_searched_thread = NULL;
			disp_state = disp_thread_search(search_winp, 
					state, linkp, &h_searched_thread);
			ch = NT_KEY_NONE;
			if(h_searched_thread){
				if(nt_set_sel_item(app_2ch_model,
						&h_sel_items_tmp, h_searched_thread, &status_msg)){
					disp_state = DISP_STATE_RESLIST;
					nt_2ch_selected_item_release_ref(h_sel_items);
					h_sel_items = h_sel_items_tmp;
					if(rwinp->data){
						free_reslist_ctx(rwinp->data);
						rwinp->data = NULL;
					}
					if(twinp->data){
						free_threadlist_ctx(twinp->data);
						twinp->data = NULL;
					}
					nt_searched_thread_release_ref(h_searched_thread);
					h_searched_thread = NULL;
					continue;
				}
				nt_searched_thread_release_ref(h_searched_thread);
				h_searched_thread = NULL;
			}
			if(disp_state != DISP_STATE_SEARCH_THREAD){
				continue;
			}
			break;
		case DISP_STATE_FAVORITE:
			draw_title(scrp, L"お気に入り", WA_REVERSE);
			if(!favorite_winp)
				favorite_winp = nt_disp_win_alloc(
						scrp, LINES-1, COLS, 1, 0, buf);
			if(!favorite_winp)
				goto END_WHILE;
			favorite_winp->key = ch;
			h_searched_thread = NULL;
			if(!favorite_winp->data){
				linkp = nt_favorite_get_update_board_list(app_2ch_model, h_favorite);
				if(linkp){
					nt_read_board_list(linkp);
					nt_all_link_free(linkp, _2ch_selected_item_free);
				}
			}
			state = disp_favorite(favorite_winp, state, app_2ch_model,
							h_favorite, db_handle, 
							&handle,  &h_searched_thread);
			if(DISP_CMD(state)){
				ch = NT_KEY_NONE;
				if(DISP_CMD(state) == DISP_CMD_DEL_FAVORITE_BOARD){
					if(nt_favorite_board_remove(handle)){
						h_favorite_board = (nt_favorite_board_handle)handle;
						nt_favorite_board_release_ref(h_favorite_board);
						status_msg = NT_INFO_DEL_FAVORITE_SUCCEEDED;
					}else{
						status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
					}
				}else if(DISP_CMD(state) == DISP_CMD_DEL_FAVORITE_THREAD){
					if(nt_favorite_thread_remove(handle)){
						h_favorite_thread = (nt_favorite_thread_handle)handle;
						nt_favorite_thread_release_ref(h_favorite_thread);
						status_msg = NT_INFO_DEL_FAVORITE_SUCCEEDED;
					}else{
						status_msg = NT_ERR_MSG_DEL_FAVORITE_FAILED;
					}
				}else if(DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_BOARD ||
						DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_THREAD){
					assert(h_searched_thread);
					if(nt_set_sel_item(app_2ch_model,
							&h_sel_items_tmp, h_searched_thread, &status_msg)){
						disp_state = (DISP_CMD(state) == DISP_CMD_SEL_FAVORITE_BOARD)
							? DISP_STATE_THREADTITLE : DISP_STATE_RESLIST;
						state = DISP_STATE_FAVORITE;
						nt_2ch_selected_item_release_ref(h_sel_items);
						h_sel_items = h_sel_items_tmp;
						if(rwinp->data){
							free_reslist_ctx(rwinp->data);
							rwinp->data = NULL;
						}
						if(twinp->data){
							free_threadlist_ctx(twinp->data);
							twinp->data = NULL;
						}
					}
					nt_searched_thread_release_ref(h_searched_thread);
					h_searched_thread = NULL;
				}else{
					disp_state = state = DISP_STATE_FAVORITE;
				}
				continue;
			}else if(state == DISP_STATE_REFRESH){
				state = DISP_STATE_FAVORITE;
				ch = NT_KEY_NONE;
				if(favorite_winp->data){
					free_favorite_ctx(favorite_winp->data);
					favorite_winp->data = NULL;
				}
				status_msg = NT_INFO_REFRESH_FAVORITE_SUCCESS;
				wclear(scrp);
				continue;
			}else if(state != DISP_STATE_FAVORITE){
				ch = NT_KEY_NONE;
				disp_state = state;
				continue;
			}else{
				disp_state = DISP_STATE_FAVORITE;
			}
			break;
		default:
		 	goto END_WHILE;
		}/* end switch*/

		if(status_msg){
			print_error(scrp, status_msg);
			status_msg = NULL;
		}

		move(LINES-1,COLS-1);
		touchwin(scrp);
		wrefresh(scrp);
		
		timeout(NT_MAINLOOP_POLLING_INTERVAL);
		do{
			ch = getch();
			if(ch == ERR){
				async_data = nt_pthread_get_result_from_que();
				if(async_data.code == NT_PTHREAD_RESULT_UPDATE_BOARD){
					ch = NT_KEY_CMD_BOARD_UPDATE;
					//fprintf(stderr, "Async result recieved.!\n");
				}else{
					h_timer = nt_timer_ring_a_bell();
					if(h_timer){
						switch(nt_timer_get_id(h_timer)){
						case TIMER_ID_AUTO_SCROLL:
							ch = NT_KEY_CMD_AUTO_SCROLL;
							break;
						case TIMER_ID_AUTO_UPDATE:
							linkp = nt_favorite_get_update_board_list(
									app_2ch_model, h_favorite);
							if(linkp){
								nt_read_board_list(linkp);
								nt_all_link_free(linkp, _2ch_selected_item_free);
								//fprintf(stderr, "Update request calling.!\n");
							}
							break;
						}
						nt_timer_release_ref(h_timer);
					}
				}
			}
		}while(ch == '\n' || ch == '\r' || ch == ERR);
		timeout(-1);
		
		switch(ch){
		case NT_KEY_UP:
		case KEY_UP:
		case NT_KEY_DOWN:
		case KEY_DOWN:
		case NT_KEY_LEFT:
		case NT_KEY_RIGHT:
		case KEY_RIGHT:
		case NT_KEY_PAGEUP:
		case KEY_PPAGE:
		case NT_KEY_PAGEDOWN:
		case KEY_NPAGE:
		case NT_KEY_SELECT:
		case NT_KEY_ADD:
		case NT_KEY_DEL:
		case NT_KEY_BOTTOM:
		case KEY_END:
		case NT_KEY_REFRESH:
			break;
		case NT_KEY_CLOSE:
		case KEY_LEFT:
			wclear(scrp);
			break;
		case KEY_HOME:
			ch = NT_KEY_COMMAND1;
			nt_add_wch(scrp,ch,0);
			strncpy(buf,"1",2);
			break;
		case NT_KEY_COMMAND1:
		case NT_KEY_COMMAND2:
		case NT_KEY_COMMAND3:
			echo();
			nocbreak();
			wch = ch;
			move(LINES-1,0);
			nt_add_wch(scrp,wch,0);
			getstr(buf);
			cbreak();
			noecho();
			break;
		case NT_KEY_ERASE:
			wclear(scrp);
			break;
		case NT_KEY_QUIT:
			result = TRUE;
			goto END_WHILE;
		}/* end switch*/
	}/* end while */
END_WHILE:
	if(h_timer_auto_update)
		nt_timer_release_ref(h_timer_auto_update);
	if(h_timer_auto_scroll)
		nt_timer_release_ref(h_timer_auto_scroll);
	if(cookiep)
		nt_unload_cookie(cookiep);
	if(marup)
		nt_maru_2ch_free(marup);
	if(h_write_data)
		nt_write_data_release_ref(h_write_data);
	if(h_searched_thread)
		nt_searched_thread_release_ref(h_searched_thread);
	nt_2ch_selected_item_release_ref(h_sel_items);
	free_board_menu_ctx(bwinp->data);
	free_threadlist_ctx(twinp->data);
	free_reslist_ctx(rwinp->data);
	if(search_winp){
		if(search_winp->data)
			free_search_thread_ctx(search_winp->data);
		nt_disp_win_free(search_winp);
	}
	if(favorite_winp){
		if(favorite_winp->data)
			free_favorite_ctx(favorite_winp->data);
		nt_disp_win_free(favorite_winp);
	}
	nt_disp_win_free(bwinp);
	nt_disp_win_free(twinp);
	nt_disp_win_free(rwinp);
	
	return result;
}



static int draw_title(WINDOW *wp, const wchar_t *title, attr_t attr)
{
	move(0,0);
	int  num;
	num = nt_get_wc_count_within_colmns(title, COLS-1);
	if(num == 0)
		return 0;
	
	nt_add_wnch(wp, L' ', attr, COLS);
	move(0,1);
	nt_add_wnstr(wp, title, WA_REVERSE, COLS - 1);
	return 1;
}



static void print_error(WINDOW *wp, const wchar_t *msg)
{
	move(LINES-1,0);
	nt_add_wstr(wp, msg, 0);
}

