/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <wchar.h>
#include <ncursesw/ncurses.h>
#include <regex.h>

#include	"env.h"
#include	"error.h"
#include	"utils/nt_std_t.h"
#include	"usr/usr_db_t.h"
#include	"utils/text.h"
#include	"_2ch/_2ch.h"
#include	"_2ch/model_2ch.h"
#include	"_2ch/parse_2ch.h"
#include	"ui/disp.h"
#include	"ui/disp_string.h"

#define NT_CMD_NONE -1
#define NT_CMD_WRITE 1
#define NT_CMD_JMP_NEW 2
#define NT_CMD_TREE 3
#define NT_CMD_ID 4
#define NT_CMD_SEARCH_THREAD 5
#define NT_CMD_FAVORITE 6
#define NT_CMD_AUTO_SCROLL 7

#define AUTO_SCROLL_NONE 0
#define AUTO_SCROLL_UP  -1
#define AUTO_SCROLL_DOWN 1

typedef struct tag_ctx_reslist_t *ctx_reslist_tp;
typedef struct tag_ctx_reslist_t
{
	int prev_state;
	int res_num;
	int cur_res;
	int cur_res_offset;
	int max_cur_res;
	int max_cur_offset;
	int prev_read_cnt;
	nt_stack_tp	selected_num_stackp;

	regex_t regex;
	BOOL regex_init;
	int sel_res_no;
	int sel_res_line;
	
	int auto_scroll;

	nt_link_tp res_disp_list;
	
	nt_stack_tp child_ctx_stackp;
	
} ctx_reslist_t;

typedef struct tag_res_data_t *res_data_tp;
typedef struct tag_res_data_t {
	nt_res_handle h_res;
	wchar_t *res_msg;
	nt_link_tp cite_num_list;
	nt_link_tp cited_num_list;
	int msg_line_num;
	int msg_header_line_num;
	nt_link_tp msg_line_linkp;
	int id_num;
}res_data_t;

static ctx_reslist_tp init_context(nt_2ch_selected_item_handle h_select, 
			nt_usr_db_handle usr_db_handle);
static BOOL reslist_clone(nt_thread_handle h_thread, ctx_reslist_tp ctxp);
static void int_ptr_free(void *ptr);
static int parse_cmd1(const char *param, const char **end);
static BOOL search_line_asc(regex_t *regexp, nt_link_tp reslistp, 
			int *sel_res_no, int *sel_res_line, int column);
static BOOL search_line_desc(regex_t *regexp, ctx_reslist_tp ctxp,
			nt_link_tp reslistp, 
			int *sel_res_no, int *sel_res_line, int column);
static int parse_res_msg(nt_link_tp disp_res_list, 
			res_data_tp res_datap, size_t colmns);
static void res_msg_free(void *ptr);
static nt_link_tp get_cited_num_list(nt_link_tp res_listp, int seq_no);
static BOOL reslist_copy(ctx_reslist_tp ctxp, ctx_reslist_tp copy_ctxp, 
			nt_link_tp num_listp);
static ctx_reslist_tp init_sub_context(ctx_reslist_tp ctxp, nt_link_tp num_listp);
static void free_reslist_sub_ctx(void *ptr);
static nt_link_tp parse_tree_list(ctx_reslist_tp ctxp, const char *param);
static nt_link_tp parse_id_list(ctx_reslist_tp ctxp, const char *param);
static void search_up_tree(int seq_no, nt_link_tp disp_list, nt_link_tp *num_linkp);
static void search_down_tree(int seq_no, nt_link_tp disp_list, nt_link_tp *num_linkp);
static int get_id_num(ctx_reslist_tp ctxp, const wchar_t *misc);
static BOOL set_res_header(ctx_reslist_tp ctxp, res_data_tp res_datap,
				wchar_t *buf, size_t buf_len);

int disp_reslist(nt_window_tp wp, int prev_state, nt_2ch_selected_item_handle h_select,
	nt_usr_db_handle usr_db_handle)
{
	ctx_reslist_tp ctxp, child_ctxp;
	res_data_tp res_datap;
	nt_link_tp clistp;
	nt_link_tp linkp;
	nt_stack_tp stackp;
	int i, rows;
	int wlines;
	int len, ch;
	int num;
	int res_offset;
	int *nptr;
	void *ptr;
	wchar_t buf[1024*3+1];
	wchar_t *cptr;
	nt_link_tp link_curp;
	BOOL search_asc;
	BOOL adjust;
	BOOL set_value;
	int line_num;
	int  cmd;
	attr_t new_res_attr;
	const char *endp;
	int result_state;
	int auto_scroll_state;
	
	ctxp = (ctx_reslist_tp)wp->data;
	if(!ctxp){
		ctxp = init_context(h_select, usr_db_handle);
		if(!ctxp)
			return DISP_STATE_ERROR;
		wp->data = ctxp;
	}else if(ctxp->child_ctx_stackp){
		ctxp = (ctx_reslist_tp)nt_stack_peek(
					ctxp->child_ctx_stackp);
		if(!ctxp){
			ctxp->child_ctx_stackp = NULL;
			ctxp = (ctx_reslist_tp)wp->data;
		}
	}
	
	if(prev_state != DISP_STATE_RESLIST)
		ctxp->prev_state = prev_state;

	ch = wp->key;
	result_state = DISP_STATE_RESLIST;

	if(ctxp->max_cur_res < 0 || ctxp->max_cur_offset < 0){
		wlines = wp->lines;
		int cur_res = ctxp->res_num - 1;
		/* get the bottom scroll position*/
		clistp = ctxp->res_disp_list->prev;
		while(clistp != ctxp->res_disp_list){
			res_datap = (res_data_tp)clistp->data;
			if(!res_datap->msg_line_linkp){
				parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
			}

			if(res_datap->msg_header_line_num <= 0){
				if(!set_res_header((ctx_reslist_tp)wp->data, 
						res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
					res_datap->msg_header_line_num = 1;
				}else{
					len = wcslen(buf);
					cptr = buf;
					while(len > 0){
						num = nt_get_wc_count_within_colmns(
									cptr, wp->cols);
						if(num <= 0)
							break;
						res_datap->msg_header_line_num++;
						len -= num;
						cptr += num;
					}
				}
			}
			wlines--;
			if(wlines == 0){
				ctxp->max_cur_offset = res_datap->msg_header_line_num;
				ctxp->max_cur_offset += res_datap->msg_line_num;
				ctxp->max_cur_res = cur_res;
				break;
			}
			if(wlines <= res_datap->msg_line_num){
				ctxp->max_cur_offset = res_datap->msg_header_line_num;
				ctxp->max_cur_offset += res_datap->msg_line_num - wlines;
				ctxp->max_cur_res = cur_res;
				break;
			}
			wlines -= res_datap->msg_line_num;
			if(wlines <= res_datap->msg_header_line_num){
				ctxp->max_cur_offset = 
						res_datap->msg_header_line_num - wlines;
				ctxp->max_cur_res = cur_res;
				break;
			}
			wlines -= res_datap->msg_header_line_num;
			cur_res--;
			if(cur_res < 0){
				ctxp->max_cur_offset = 0;
				ctxp->max_cur_res = 0;
				break;
			}
			clistp = clistp->prev;
		}
	}
	
	auto_scroll_state = ctxp->auto_scroll;
	if(ch == NT_KEY_CMD_AUTO_SCROLL){
		result_state |= DISP_CMD_AUTO_SCROLL;
		if(ctxp->auto_scroll == AUTO_SCROLL_UP){
			ch = NT_KEY_UP;
		}else{
			ch = NT_KEY_DOWN;
			ctxp->auto_scroll = AUTO_SCROLL_DOWN;
		}
	}else{
		ctxp->auto_scroll = AUTO_SCROLL_NONE;
	}

	switch(ch){
	case NT_KEY_CMD_BOARD_UPDATE:
		if(auto_scroll_state != AUTO_SCROLL_NONE){
			result_state |= DISP_CMD_AUTO_SCROLL;
			ctxp->auto_scroll = auto_scroll_state;
		}
		break;
	case NT_KEY_REFRESH:
		return DISP_STATE_REFRESH; 
	case NT_KEY_CLOSE:
	case KEY_LEFT:
		return ctxp->prev_state; 
	case NT_KEY_BOTTOM:
	case KEY_END:
		if(ctxp->cur_res == ctxp->res_num - 1)
			break;
		if(!ctxp->res_disp_list)
			break;
		clistp = ctxp->res_disp_list->prev;
		ctxp->cur_res = ctxp->max_cur_res;
		ctxp->cur_res_offset = ctxp->max_cur_offset;
		break;
	case NT_KEY_LEFT:
		if(!ctxp->selected_num_stackp)
			break;
		if(0 >= nt_stack_get_position(ctxp->selected_num_stackp)){
			if((ctx_reslist_tp)wp->data != ctxp){
				stackp = ((ctx_reslist_tp)wp->data)->child_ctx_stackp;
				if(stackp){
					if(0 >= nt_stack_get_position(stackp)){
						ctxp = (ctx_reslist_tp)wp->data;
						nt_stack_free(stackp, free_reslist_sub_ctx);
						((ctx_reslist_tp)wp->data)->child_ctx_stackp = NULL;
						break;
					}
					child_ctxp = nt_stack_pop(stackp);
					if(!child_ctxp)
						break;
					child_ctxp = nt_stack_peek(stackp);
					if(!child_ctxp)
						break;
					ctxp = child_ctxp;
				}
			}
			break;
		}
		nptr = malloc(sizeof(int));
		*nptr = ctxp->cur_res;
		ptr = nt_stack_add_last(ctxp->selected_num_stackp, nptr);
		if(!ptr){
			free(nptr);
		}
		nptr = nt_stack_pop(ctxp->selected_num_stackp);
		if(!nptr)
			break;
		num = *nptr;
		if(ctxp->cur_res == num)
			break;
		if(num >= ctxp->res_num)
			break;
		ctxp->cur_res = num;
		ctxp->cur_res_offset = 0;
		if(!ctxp->res_disp_list)
			break;
		clistp = ctxp->res_disp_list;
		for(i = 0; i < num; i++)
			clistp = clistp->next;
		break;
	case NT_KEY_RIGHT:
		if(!ctxp->selected_num_stackp)
			break;
		nptr = nt_stack_cursor_next(ctxp->selected_num_stackp);
		if(!nptr)
			break;
		num = *nptr;
		if(ctxp->cur_res == num)
			break;
		if(num >= ctxp->res_num)
			break;
		ctxp->cur_res = num;
		ctxp->cur_res_offset = 0;
		if(!ctxp->res_disp_list)
			break;
		clistp = ctxp->res_disp_list;
		for(i = 0; i < num; i++)
			clistp = clistp->next;
		break;
	case NT_KEY_COMMAND2:
	case NT_KEY_COMMAND3:
		search_asc = (ch == NT_KEY_COMMAND2);
		if(wp->cmd_param && wp->cmd_param[0] != '\0'){
			if(0 != regcomp(&(ctxp->regex), 
					wp->cmd_param, REG_EXTENDED)){
				if(ctxp->regex_init){
					regfree(&(ctxp->regex));
					ctxp->regex_init = FALSE;
					break;
				}
			}
			if(!ctxp->regex_init)
				ctxp->regex_init = TRUE;
		}
		if(!ctxp->regex_init)
			break;
		adjust = FALSE;
		if(search_asc){
			if(search_line_asc(&(ctxp->regex),ctxp->res_disp_list,
					&ctxp->sel_res_no, &ctxp->sel_res_line, 
					wp->cols - 5)){
				adjust = TRUE;
			}
		}else{
			if(search_line_desc(&(ctxp->regex),ctxp,
					ctxp->res_disp_list,
					&ctxp->sel_res_no, &ctxp->sel_res_line, 
					wp->cols - 5)){
				adjust = TRUE;
			}
		}
		if(adjust){
			set_value = FALSE;
			rows = ctxp->res_num - 1;
			wlines = wp->lines / 2;
			wlines -= ctxp->sel_res_line;
			clistp = ctxp->res_disp_list->prev;
			do{
				if(rows <= ctxp->sel_res_no){
					res_datap = (res_data_tp)clistp->data;
					//resp = (nt_res_tp)clistp->data;
					if(!res_datap->msg_line_linkp){
						parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
					}
					if(res_datap->msg_header_line_num <= 0){
						if(!set_res_header((ctx_reslist_tp)wp->data, 
								res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
							res_datap->msg_header_line_num = 1;
						}else{
							len = wcslen(buf);
							cptr = buf;
							while(len > 0){
								num = nt_get_wc_count_within_colmns(
											cptr, wp->cols);
								if(num <= 0)
									break;
								res_datap->msg_header_line_num++;
								len -= num;
								cptr += num;
							}
						}
					}
					if(rows == ctxp->sel_res_no){
						if(wlines <= ctxp->sel_res_line){
							ctxp->cur_res = rows;
							ctxp->cur_res_offset = 
									res_datap->msg_header_line_num + 
									(ctxp->sel_res_line - wlines);
							set_value = TRUE;
							break;
						}
						wlines -= ctxp->sel_res_line;
					}else if(wlines <= (res_datap->msg_line_num+1)){
						ctxp->cur_res = rows;
						ctxp->cur_res_offset = 
								res_datap->msg_header_line_num + wlines;
						set_value = TRUE;
						break;
					}else{
						wlines -= res_datap->msg_line_num + 1;
					}
					if(wlines <= res_datap->msg_header_line_num){
						ctxp->cur_res = rows;
						ctxp->cur_res_offset = 
								res_datap->msg_header_line_num - wlines;
						set_value = TRUE;
						break;
					}
					wlines -= res_datap->msg_header_line_num;
				}
				rows--;
				clistp = clistp->prev;
			}while(clistp != ctxp->res_disp_list->prev);
			if(!set_value){
				ctxp->cur_res = 0;
				ctxp->cur_res_offset = 0;
			}
		}
		break;
	case NT_KEY_COMMAND1:
		assert(wp->cmd_param);
		cmd = parse_cmd1(wp->cmd_param, &endp);
		switch(cmd){
		case NT_CMD_AUTO_SCROLL:
			return DISP_CMD_AUTO_SCROLL | DISP_STATE_RESLIST;
		case NT_CMD_SEARCH_THREAD:
			return DISP_STATE_SEARCH_THREAD;
		case NT_CMD_FAVORITE:
			return DISP_STATE_FAVORITE;
		case NT_CMD_WRITE:
			return DISP_STATE_EDITOR;
		case NT_CMD_JMP_NEW:
			if(ctxp->prev_read_cnt <= 0)
				ctxp->cur_res = 0;
			else if(ctxp->prev_read_cnt >= ctxp->res_num){
				ctxp->cur_res = ctxp->res_num - 1;
			}else{
				ctxp->cur_res = ctxp->prev_read_cnt;
			}
			ctxp->cur_res_offset = 0;
			break;
		default:
			if(cmd == NT_CMD_TREE){
				linkp = parse_tree_list((ctx_reslist_tp)wp->data, endp);
			}else if(cmd == NT_CMD_ID){
				linkp = parse_id_list((ctx_reslist_tp)wp->data, endp);
			}else{
				linkp = nt_parse_number_list(wp->cmd_param, NULL);
			}
			if(!linkp)
				break;
			num = nt_link_num(linkp);
			if(0 >= num){
				break;
			}else if(1 == num){
				num = linkp->n_data;
				free(linkp);
				num--;
				if(ctxp->cur_res == num)
					break;
				if(num >= ctxp->res_num)
					break;
				nptr = malloc(sizeof(int));
				*nptr = ctxp->cur_res;
				ctxp->cur_res = num;
				ctxp->cur_res_offset = 0;
				if(!ctxp->res_disp_list){
					free(nptr);
					break;
				}
				clistp = ctxp->res_disp_list;
				for(i = 0; i < num; i++)
					clistp = clistp->next;
				nt_stack_push(ctxp->selected_num_stackp, nptr);
			}else{
				child_ctxp = init_sub_context((ctx_reslist_tp)wp->data, linkp);
				if(child_ctxp){
					ctxp = child_ctxp;
				}
				nt_all_link_free(linkp, NULL);
			}
			break;
		}/* end switch */
		break;
	case NT_KEY_UP:
	case KEY_UP:
		if(auto_scroll_state != AUTO_SCROLL_NONE){
			result_state |= DISP_CMD_AUTO_SCROLL;
			ctxp->auto_scroll = AUTO_SCROLL_UP;
		}
		ctxp->cur_res_offset--;
		if(0 <= ctxp->cur_res_offset){
			break;
		}
		if(0 >= ctxp->cur_res){
			ctxp->cur_res_offset = 0;
			ctxp->cur_res = 0;
			break;
		}
		ctxp->cur_res--;
		clistp = ctxp->res_disp_list;
		for(i = 0; i < ctxp->res_num; i++){
			if(i == ctxp->cur_res)
				break;
			clistp = clistp->next;
		}
		if(i == ctxp->res_num)
			break;
		res_datap = (res_data_tp)clistp->data;
		if(!res_datap->msg_line_linkp){
			parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
		}
		if(res_datap->msg_header_line_num <= 0){
			if(!set_res_header((ctx_reslist_tp)wp->data, 
						res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
				res_datap->msg_header_line_num = 1;
			}else{
				len = wcslen(buf);
				cptr = buf;
				while(len > 0){
					num = nt_get_wc_count_within_colmns(
								cptr, wp->cols);
					if(num <= 0)
						break;
					res_datap->msg_header_line_num++;
					len -= num;
					cptr += num;
				}
			}
		}
		num = res_datap->msg_header_line_num;
		num += res_datap->msg_line_num;
		ctxp->cur_res_offset = num;
		break;
	case NT_KEY_DOWN:
	case KEY_DOWN:
		if(auto_scroll_state != AUTO_SCROLL_NONE){
			result_state |= DISP_CMD_AUTO_SCROLL;
			ctxp->auto_scroll = AUTO_SCROLL_DOWN;
		}
		ctxp->cur_res_offset++;
		clistp = ctxp->res_disp_list;
		for(i = 0; i < ctxp->res_num; i++){
			if(i == ctxp->cur_res)
				break;
			clistp = clistp->next;
		}
		if(i == ctxp->res_num)
			break;
		res_datap = (res_data_tp)clistp->data;
		if(!res_datap->msg_line_linkp){
			parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
		}
		if(res_datap->msg_header_line_num <= 0){
			if(!set_res_header((ctx_reslist_tp)wp->data, 
					res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
				res_datap->msg_header_line_num = 1;
			}else{
				len = wcslen(buf);
				cptr = buf;
				while(len > 0){
					num = nt_get_wc_count_within_colmns(
								cptr, wp->cols);
					if(num <= 0)
						break;
					res_datap->msg_header_line_num++;
					len -= num;
					cptr += num;
				}
			}
		}
		num = res_datap->msg_header_line_num;
		num += res_datap->msg_line_num + 1;
		if(ctxp->cur_res_offset >= num){
			ctxp->cur_res++;
			ctxp->cur_res_offset = 0;
		}
		break;
	case NT_KEY_PAGEUP:
	case KEY_PPAGE:
		if(auto_scroll_state != AUTO_SCROLL_NONE){
			result_state |= DISP_CMD_AUTO_SCROLL;
			ctxp->auto_scroll = AUTO_SCROLL_UP;
		}
		ctxp->cur_res_offset -= wp->lines;
		if(ctxp->cur_res_offset >= 0){
			break;
		}
		ctxp->cur_res--;
		clistp = ctxp->res_disp_list;
		for(i = 0; i < ctxp->res_num; i++){
			if(i == ctxp->cur_res)
				break;
			clistp = clistp->next;
		}
		if(i == ctxp->res_num){
			ctxp->cur_res_offset = 0;
			break;
		}
		for( ; i > 0; i--){
			res_datap = (res_data_tp)clistp->data;
			if(!res_datap->msg_line_linkp){
				parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
			}
			if(res_datap->msg_header_line_num <= 0){
				if(!set_res_header((ctx_reslist_tp)wp->data, 
						res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
					res_datap->msg_header_line_num = 1;
				}else{
					len = wcslen(buf);
					cptr = buf;
					while(len > 0){
						num = nt_get_wc_count_within_colmns(
									cptr, wp->cols);
						if(num <= 0)
							break;
						res_datap->msg_header_line_num++;
						len -= num;
						cptr += num;
					}
				}
			}
			num = res_datap->msg_header_line_num;
			num += res_datap->msg_line_num;
			if(ctxp->cur_res_offset + num < 0){
				ctxp->cur_res_offset += num;
				ctxp->cur_res--;
				clistp = clistp->prev;
				continue;
			}
			ctxp->cur_res_offset += num;
			break;
		}
		if(i == 0){
			ctxp->cur_res = 0;
			ctxp->cur_res_offset = 0;
		}
		break;
	case NT_KEY_PAGEDOWN:
	case KEY_NPAGE:
		if(auto_scroll_state != AUTO_SCROLL_NONE){
			result_state |= DISP_CMD_AUTO_SCROLL;
			ctxp->auto_scroll = AUTO_SCROLL_DOWN;
		}
		clistp = ctxp->res_disp_list;
		if(0 > ctxp->cur_res)
			ctxp->cur_res = 0;
		for(i = 0; i < ctxp->res_num; i++){
			if(i == ctxp->cur_res)
				break;
			clistp = clistp->next;
		}
		if(i == ctxp->res_num)
			break;
				
		ctxp->cur_res_offset += wp->lines;
		for( ; i < ctxp->res_num; i++){
			res_datap = (res_data_tp)clistp->data;
			if(!res_datap->msg_line_linkp){
				parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
			}
			if(res_datap->msg_header_line_num <= 0){
				if(!set_res_header((ctx_reslist_tp)wp->data, 
						res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
					res_datap->msg_header_line_num = 1;
				}else{
					len = wcslen(buf);
					cptr = buf;
					while(len > 0){
						num = nt_get_wc_count_within_colmns(
									cptr, wp->cols);
						if(num <= 0)
							break;
						res_datap->msg_header_line_num++;
						len -= num;
						cptr += num;
					}
				}
			}
			num = res_datap->msg_header_line_num;
			num += res_datap->msg_line_num + 1;
			if(num > ctxp->cur_res_offset){
				break;
			}
			ctxp->cur_res++;
			ctxp->cur_res_offset -= num;

			clistp = clistp->next;
		}
		break;
	}/* end switch */

	if(ctxp->cur_res > ctxp->max_cur_res ||
		(ctxp->cur_res == ctxp->max_cur_res && 
		ctxp->cur_res_offset > ctxp->max_cur_offset)){
		ctxp->cur_res = ctxp->max_cur_res;
		ctxp->cur_res_offset = ctxp->max_cur_offset;
	}

	clistp = ctxp->res_disp_list;
	res_offset = 0;
	rows = 0;
	for(i = 0; i < ctxp->res_num; i++){
		if(i < ctxp->cur_res){
			clistp = clistp->next;
			continue;
		}

		if(rows == wp->lines)
			break;

		res_datap = (res_data_tp)clistp->data;
		
		if(!set_res_header((ctx_reslist_tp)wp->data, 
				res_datap, buf, sizeof(buf)/sizeof(buf[0]))){
			continue;
		}
		len = wcslen(buf);
		num = nt_get_wc_count_within_colmns(buf, wp->cols);

		if(ctxp->res_num == ctxp->prev_read_cnt)
			new_res_attr = 0;
		else if(i+1 > ctxp->prev_read_cnt)
			new_res_attr = WA_BOLD;
		else
			new_res_attr = 0;

		if(num < len){
			if(!nt_w_str_move(buf, sizeof(buf), num, 1))
				break;
			if(res_offset >= ctxp->cur_res_offset){
				wmove(wp->wp, rows, 0);
				nt_add_wstr(wp->wp, buf, new_res_attr);
				rows++;
			}else{
				res_offset++;
			}
			if(rows == wp->lines)
				break;
			if(res_offset >= ctxp->cur_res_offset){
				wmove(wp->wp, rows, 0);
				nt_add_wnch(wp->wp, L' ', WA_UNDERLINE, 5);
				nt_add_wnstr(wp->wp, buf + num + 1, 
							new_res_attr | WA_UNDERLINE,
							wp->cols - 5);
				rows++;
			}else{
				res_offset++;
			}
		}else{
			if(res_offset >= ctxp->cur_res_offset){
				wmove(wp->wp, rows, 0);
				nt_add_wstr(wp->wp, buf, 
							new_res_attr | WA_UNDERLINE);
				rows++;
			}else{
				res_offset++;
			}
		}
		if(rows == wp->lines)
			break;
		if(!res_datap->msg_line_linkp){
			parse_res_msg(ctxp->res_disp_list, res_datap, wp->cols-5);
		}
		if(0 == res_datap->msg_line_num)
			continue;

		link_curp = res_datap->msg_line_linkp;
		line_num = 0;
		do{
			cptr = (wchar_t*)link_curp->data;
			if(res_offset >= ctxp->cur_res_offset){
				wmove(wp->wp, rows, 5);
				if(i == ctxp->sel_res_no &&
					line_num == ctxp->sel_res_line){
					/*fprintf(stderr, "hilighted no: %d, line: %d\n",
						i, line_num);*/
					nt_add_wstr(wp->wp, cptr, WA_REVERSE);
				}else{
					nt_add_wstr(wp->wp, cptr, 0);
				}
				rows++;
				if(rows == wp->lines)
					goto END_FOR;
			}else{
				res_offset++;
			}
			line_num++;
			link_curp = link_curp->next;
		}while(res_datap->msg_line_linkp != link_curp);

		if(rows == wp->lines)
			goto END_FOR;
		if(res_offset >= ctxp->cur_res_offset){
			wmove(wp->wp, rows, 0);
			nt_add_wnch(wp->wp, L' ', 0, wp->cols);
			if(res_datap->cited_num_list){
				cptr = nt_w_format_number_list(
						res_datap->cited_num_list);
				if(cptr){
					wmove(wp->wp, rows, 0);
					nt_add_wnch(wp->wp, L' ', 0, 6);
					nt_add_wstr(wp->wp, L"<<", 0);
					nt_add_wnstr(wp->wp, cptr, 
							0, wp->cols - 8);
					free(cptr);
				}
			}else{
			}
			rows++;
		}else{
			res_offset++;
		}
		clistp = clistp->next;
	}/* end for */
END_FOR:
	
	return result_state; 
}

static int get_id_num(ctx_reslist_tp ctxp, const wchar_t *misc)
{
	int num;
	num = 0;
	res_data_tp datap;
	wchar_t *cptr;
	const wchar_t *misc2;
	nt_link_tp linkp, disp_list;
	
	assert(ctxp);
	
	cptr = wcsstr(misc, L"ID:");
	if(!cptr)
		return 0;
	
	cptr = nt_w_trim(cptr);
	if(!cptr)
		return 0;
	
	disp_list = ctxp->res_disp_list;
	linkp = disp_list;
	do{
		datap = (res_data_tp)linkp->data;
		misc2 = nt_res_get_misc(datap->h_res);
		if(wcsstr(misc2, cptr))
			num++;
		linkp = linkp->next;
	}while(linkp != disp_list);
	
	free(cptr);
	return num;
}

static BOOL set_res_header(ctx_reslist_tp ctxp, res_data_tp res_datap,
				wchar_t *buf, size_t buf_len)
{
	const wchar_t *name, *mail, *misc;
	int seq_no, id_num;
	
	seq_no = nt_res_get_seq_number(res_datap->h_res);
	name = nt_res_get_name(res_datap->h_res);
	mail = nt_res_get_mail(res_datap->h_res);
	misc = nt_res_get_misc(res_datap->h_res);
	
	id_num = res_datap->id_num;
	if(id_num < 0){
		id_num = get_id_num(ctxp, misc);
		res_datap->id_num = id_num;
	}
	if(id_num <= 1){
		if(-1 == swprintf(buf, buf_len-1, 
				L"%5d. %ls %ls %ls", seq_no, name, mail, misc)){
			return FALSE;
		}
	}else{
		if(-1 == swprintf(buf, buf_len-1, 
				L"%5d. %ls %ls %ls(%d)", seq_no, name, mail, misc, id_num)){
			return FALSE;
		}
	}
	return TRUE;
}

static int parse_cmd1(const char *param, const char **end)
{
	int len;
	const char *start;
	
	assert(param);
	
	if(!nt_strtok(param, ' ', &start, end))
		return NT_CMD_NONE;
	
	len = *end - start;
	if(len <= 0)
		return NT_CMD_NONE;
	
	if(0 == strncmp(NT_COMMAND1_WRITE_MSG_1, start,len) ||
		0 == strncmp(NT_COMMAND1_WRITE_MSG_2, start,len)){
		return NT_CMD_WRITE;
	}else if(0 == strncmp(NT_COMMAND1_JMP_NEW_1,start,len) ||
		0 == strncmp(NT_COMMAND1_JMP_NEW_2, start,len)){
		return NT_CMD_JMP_NEW;
	}else if(0 == strncmp(NT_COMMAND1_TREE_1, start,len) ||
		0 == strncmp(NT_COMMAND1_TREE_2, start,len)){
		return NT_CMD_TREE;
	}else if(0 == strncmp(NT_COMMAND1_ID_1, start,len) ||
		0 == strncmp(NT_COMMAND1_ID_2, start,len)){
		return NT_CMD_ID;
	}else 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 if(0 == strncmp(NT_COMMAND1_AUTOSCROLL_1,param,
			strlen(NT_COMMAND1_AUTOSCROLL_1)) ||
		0 == strncmp(NT_COMMAND1_AUTOSCROLL_2,param,
			strlen(NT_COMMAND1_AUTOSCROLL_2))){
		return NT_CMD_AUTO_SCROLL;
	}
	return NT_CMD_NONE;
}

static ctx_reslist_tp init_context(nt_2ch_selected_item_handle h_select,
	nt_usr_db_handle usr_db_handle)
{
	nt_thread_handle h_thread;
	ctx_reslist_tp ctxp;
	const wchar_t *board_name, *dat_name;
	BOOL b_result;
	
	board_name = nt_2ch_selected_item_get_board_name(h_select);
	dat_name = nt_2ch_selected_item_get_thread_dat_name(h_select);
	assert(board_name && dat_name);

	ctxp = (ctx_reslist_tp)calloc(1,sizeof(ctx_reslist_t));

	if(!ctxp)
		return NULL;
	
	h_thread = nt_get_selected_thread(h_select);
	if(!h_thread){
		free(ctxp);
		return NULL;
	}
	ctxp->cur_res = 0;
	ctxp->cur_res_offset = 0;
	ctxp->max_cur_res = -1;
	ctxp->max_cur_offset = -1;
	ctxp->selected_num_stackp = nt_stack_alloc();
	ctxp->regex_init = FALSE;
	ctxp->sel_res_no = -1;
	ctxp->sel_res_line = -1;
	ctxp->child_ctx_stackp = NULL;
	ctxp->prev_state = DISP_STATE_THREADTITLE;
	ctxp->auto_scroll = AUTO_SCROLL_NONE;

	b_result = reslist_clone(h_thread, ctxp);
	nt_thread_release_ref(h_thread);
	if(!b_result){
		free_reslist_ctx(ctxp);
		return NULL;
	}
	
	ctxp->prev_read_cnt = 
		nt_usr_db_update_read_count(usr_db_handle, 
				board_name, dat_name,
				ctxp->res_num);
	if(ctxp->prev_read_cnt < 0)
		ctxp->prev_read_cnt = 0;
	if(ctxp->prev_read_cnt > 0){
		ctxp->cur_res = ctxp->prev_read_cnt;
	}
	
	return ctxp;
}

static ctx_reslist_tp init_sub_context(ctx_reslist_tp ctxp, nt_link_tp num_listp)
{
	ctx_reslist_tp child_ctxp;
	child_ctxp = (ctx_reslist_tp)calloc(1,sizeof(ctx_reslist_t));
	if(!child_ctxp)
		return NULL;
	
	child_ctxp->cur_res = 0;
	child_ctxp->cur_res_offset = 0;
	child_ctxp->max_cur_res = -1;
	child_ctxp->max_cur_offset = -1;
	child_ctxp->selected_num_stackp = nt_stack_alloc();
	child_ctxp->regex_init = FALSE;
	child_ctxp->sel_res_no = -1;
	child_ctxp->sel_res_line = -1;
	child_ctxp->child_ctx_stackp = NULL;
	child_ctxp->prev_read_cnt = 0;
	child_ctxp->prev_state = ctxp->prev_state;

	if(!reslist_copy(ctxp, child_ctxp, num_listp)){
		nt_stack_free(child_ctxp->selected_num_stackp, NULL);
		free(child_ctxp);
		return NULL;
	}
	
	if(!ctxp->child_ctx_stackp){
		ctxp->child_ctx_stackp = nt_stack_alloc();
		if(!ctxp->child_ctx_stackp){
			nt_stack_free(child_ctxp->selected_num_stackp, NULL);
			free(child_ctxp);
			return NULL;
		}
	}
	if(!nt_stack_push(ctxp->child_ctx_stackp, child_ctxp)){
		nt_stack_free(child_ctxp->selected_num_stackp, NULL);
		free(child_ctxp);
		return NULL;
	}
	return child_ctxp;
}

static BOOL reslist_clone(nt_thread_handle h_thread, ctx_reslist_tp ctxp)
{
	nt_enum_handle h_enum_res;
	nt_link_tp linkp;
	nt_res_handle h_res;
	res_data_tp datap;
	int num_res;
	
	h_enum_res = nt_thread_get_res_enum(h_thread);
	if(!h_enum_res)
		return FALSE;
	
	num_res = 0;
	while(NULL != (h_res = (nt_res_handle)nt_enum_fetch(h_enum_res))){
		datap = (res_data_tp)calloc(1, sizeof(res_data_t));
		if(datap){
			datap->id_num = -1;
			datap->h_res = h_res;
			datap->res_msg = nt_parse_res_msg(
					nt_res_get_msg(h_res),
					&datap->cite_num_list);
			if(!datap->res_msg){
				datap->res_msg = nt_w_str_clone(NT_ERR_MSG_DECODE_TEXT);
			}
			linkp = nt_link_add_data(ctxp->res_disp_list, datap);
			if(!linkp){
				free(datap->res_msg);
				free(datap);
				continue;
			}
			if(!ctxp->res_disp_list)
				ctxp->res_disp_list = linkp;
			nt_res_add_ref(h_res);
			num_res++;
		}
	}
	nt_enum_unset(h_enum_res);
	ctxp->res_num = num_res;
	return TRUE;
}

static BOOL reslist_copy(ctx_reslist_tp ctxp, ctx_reslist_tp copy_ctxp, nt_link_tp num_listp)
{
	nt_link_tp linkp, r_linkp;
	nt_link_tp d_linkp;
	nt_res_handle h_res;
	res_data_tp datap;
	int num_res;
	int seq_no;
	
	assert(ctxp && copy_ctxp && num_listp);
	
	num_res = 0;
	linkp = num_listp;
	do{
		seq_no = linkp->n_data;
		d_linkp = ctxp->res_disp_list;
		do{
			datap = (res_data_tp)d_linkp->data;
			h_res = datap->h_res;
			if(seq_no == nt_res_get_seq_number(h_res)){
				r_linkp = nt_link_add_data(copy_ctxp->res_disp_list, datap);
				if(r_linkp){
					if(!copy_ctxp->res_disp_list)
						copy_ctxp->res_disp_list = r_linkp;
					num_res++;
				}
				break;
			}
			d_linkp = d_linkp->next;
		}while(d_linkp != ctxp->res_disp_list);
		linkp = linkp->next;
	}while(linkp != num_listp);
	copy_ctxp->res_num = num_res;
	return TRUE;
}

void free_reslist_ctx(void *ptr)
{
	ctx_reslist_tp ctxp;
	nt_stack_tp stackp;
	if(!ptr)
		return;
	ctxp = (ctx_reslist_tp)ptr;
	nt_stack_free(ctxp->selected_num_stackp, &int_ptr_free);
	if(ctxp->regex_init)
		regfree(&(ctxp->regex));
	if(ctxp->res_disp_list){
		nt_all_link_free(ctxp->res_disp_list, res_msg_free);
	}
	stackp = ctxp->child_ctx_stackp;
	if(stackp){
		nt_stack_free(stackp, free_reslist_sub_ctx);
	}
	free(ptr);
}
static void free_reslist_sub_ctx(void *ptr)
{
	ctx_reslist_tp ctxp;
	if(!ptr)
		return;
	ctxp = (ctx_reslist_tp)ptr;
	nt_stack_free(ctxp->selected_num_stackp, &int_ptr_free);
	if(ctxp->regex_init)
		regfree(&(ctxp->regex));
	if(ctxp->res_disp_list){
		nt_all_link_free(ctxp->res_disp_list, NULL);
	}
	free(ptr);
}

static void int_ptr_free(void *ptr)
{
	free(ptr);
}

static void res_msg_free(void *ptr)
{
	nt_link_tp curp, nextp;
	res_data_tp res_datap;
	
	assert(ptr);
	
	res_datap = (res_data_tp)ptr;
	
	free(res_datap->res_msg);
	
	nt_res_release_ref(res_datap->h_res);
	
	if(res_datap->cite_num_list)
		nt_all_link_free(res_datap->cite_num_list, NULL);
	if(res_datap->cited_num_list)
		nt_all_link_free(res_datap->cited_num_list, NULL);
	
	if(res_datap->msg_line_linkp){
		curp = res_datap->msg_line_linkp->next;
		while(curp != res_datap->msg_line_linkp){
			nextp = curp->next;
			/* We must not free the data pointer
			 * except the first one
			 * because they're alocated as a same block.
			 * This is wrong --> free(curp->data);
			 */
			free(curp);
			curp = nextp;
		}
		free(curp->data);
		free(curp);
		res_datap->msg_line_linkp = NULL;
	}
	free(res_datap);
}

		

static nt_link_tp get_cited_num_list(nt_link_tp res_listp, int seq_no)
{
	nt_link_tp linkp, wrkp, wrk2p;
	nt_link_tp num_listp;
	res_data_tp res_datap;
	
	num_listp = NULL;
	
	linkp = res_listp;
	do{
		res_datap = (res_data_tp)linkp->data;
		if(res_datap->cite_num_list){
			wrkp = res_datap->cite_num_list;
			do{
				if(wrkp->n_data == seq_no){
					wrk2p = nt_link_add_n_data(
							num_listp, 
							nt_res_get_seq_number(res_datap->h_res));
					if(wrk2p && !num_listp)
						num_listp = wrk2p;
					break;
				}
				wrkp = wrkp->next;
			}while(wrkp != res_datap->cite_num_list);
		}
		linkp = linkp->next;
	}while(linkp != res_listp);
	if(num_listp)
		nt_link_n_sort(&num_listp, nt_comp_int);
	return num_listp;
}

static int parse_res_msg(nt_link_tp disp_res_list, 
				res_data_tp res_datap, size_t colmns)
{
	int i, len, start, lines;
	wchar_t ch;
	wchar_t *buf, *cptr, *srcp, *wrk_buf;
	int offset;
	nt_link_tp linkp;
	int consume_colmns;
	int buf_idx, buf_size;
	const int delta = 64;

	assert(res_datap);
	assert(res_datap->h_res);
	assert(res_datap->res_msg);

	//res_msg_free(res_datap);
	res_datap->msg_line_num = 0;

	len = wcslen(res_datap->res_msg);
	if(len == 0)
		return 0;
	buf_size = len + delta;

	if(len == 0)
		return 0;
	buf = malloc(sizeof(wchar_t) * (buf_size));
	if(!buf)
		return 0;
	buf_idx = 0;

	srcp = res_datap->res_msg;

	lines = 0;
	start = 0;
	consume_colmns = 0;
	for(i = 0; i < len; i++){
		ch = srcp[i];
		switch(ch){
		case L'\n':
			cptr = buf + start;
			buf[buf_idx] = L'\0';
			buf_idx++;
			linkp = nt_link_add_data(
					res_datap->msg_line_linkp, cptr);
			if(!linkp)
				goto END_FOR;
			if(res_datap->msg_line_linkp == NULL)
				res_datap->msg_line_linkp = linkp;

			consume_colmns = 0;
			lines++;
			start = buf_idx;
			break;
		default:
			if(ch <= 128 || (ch >= 0xff66 && ch <= 0xff9d))
				offset = 1;
			else
				offset = 2;

			if(consume_colmns + offset > colmns){
				cptr = buf + start;
				buf[buf_idx] = L'\0';
				linkp = nt_link_add_data(
						res_datap->msg_line_linkp, cptr);
				if(!linkp)
					goto END_FOR;
				if(res_datap->msg_line_linkp == NULL)
					res_datap->msg_line_linkp = linkp;
					
				lines++;
				buf_idx++;
				start = buf_idx;
				consume_colmns = 0;
				i--;
			}else{
				consume_colmns += offset;
				buf[buf_idx] = ch;
				buf_idx++;
			}
			break;
		}/* end switch */
		if(buf_idx >= (buf_size-1)){
			wrk_buf = nt_w_str_resize(buf, buf_size, (buf_size + delta));
			if(!wrk_buf){
				nt_all_link_free(
					res_datap->msg_line_linkp, NULL);
				free(buf);
				res_datap->msg_line_linkp = NULL;
				return 0;
			}
			buf = wrk_buf;
			buf_size += delta;
		}
	} /* end for */
END_FOR:
	if(consume_colmns > 0){
		cptr = buf + start;
		buf[buf_idx] = L'\0';
		linkp = nt_link_add_data(
				res_datap->msg_line_linkp, cptr);
		if(linkp){
			if(res_datap->msg_line_linkp == NULL)
				res_datap->msg_line_linkp = linkp;
			lines++;
		}
	}
	res_datap->msg_line_num = lines;
	
	if(!res_datap->cited_num_list){
		res_datap->cited_num_list = 
			get_cited_num_list(disp_res_list, 
				nt_res_get_seq_number(res_datap->h_res));
	}
	return lines;
}

static BOOL search_line_asc(regex_t *regexp, nt_link_tp reslistp, 
			int *sel_res_no, int *sel_res_line, int column)
{
	nt_link_tp clistp, listp;
	//nt_res_tp resp;
	res_data_tp res_datap;
	int cur, line, res_no, res_line;
	wchar_t *cptr;
	char buf[256];
	size_t nmatch = 5;
	regmatch_t pmatch[5];

	if(!reslistp)
		return FALSE;
	
	if(*sel_res_no < 0)
		res_no = 0;
	else
		res_no = *sel_res_no;
	if(*sel_res_line < 0)
		res_line = 0;
	else
		res_line = *sel_res_line + 1;
		
	cur = 0;
	clistp = reslistp;
	do{
		if(cur >= res_no){
			res_datap = (res_data_tp)clistp->data;
			//resp = res_datap->resp;
			if(!res_datap->msg_line_linkp)
				parse_res_msg(reslistp, res_datap, column);
			listp = res_datap->msg_line_linkp;
			line = 0;
			do{
				if(line >= res_line){
					cptr = (wchar_t*)listp->data;
					if(0 < wcstombs(buf, cptr, sizeof(buf))){
						if(0 == regexec(regexp, buf, 
								nmatch, pmatch, 0)){
							*sel_res_line = line;
							*sel_res_no = cur;
							return TRUE;
						}
					}
				}
				line++;
				listp = listp->next;
			}while(listp != res_datap->msg_line_linkp);
			res_line = 0;
		}
		cur++;
		clistp = clistp->next;
	}while(clistp != reslistp);

	cur = 0;
	clistp = reslistp;
	do{
		if(cur >= res_no)
			break;

		res_datap = (res_data_tp)clistp->data;
		if(!res_datap->msg_line_linkp)
			parse_res_msg(reslistp, res_datap, column);
		listp = res_datap->msg_line_linkp;
		line = 0;
		do{
			if(line >= res_line){
				cptr = (wchar_t*)listp->data;
				if(0 < wcstombs(buf, cptr, sizeof(buf))){
					if(0 == regexec(regexp, buf, 
							nmatch, pmatch, 0)){
						*sel_res_line = line;
						*sel_res_no = cur;
						return TRUE;
					}
				}
			}
			line++;
			listp = listp->next;
		}while(listp != res_datap->msg_line_linkp);
		res_line = 0;
		cur++;
		clistp = clistp->next;
	}while(clistp != reslistp);
	return FALSE;
}

static BOOL search_line_desc(regex_t *regexp, ctx_reslist_tp ctxp,
			nt_link_tp reslistp, 
			int *sel_res_no, int *sel_res_line, int column)
{
	nt_link_tp clistp, listp;
	//nt_res_tp resp;
	res_data_tp res_datap;
	int cur, line, res_no, res_line;
	wchar_t *cptr;
	char buf[256];
	size_t nmatch = 5;
	regmatch_t pmatch[5];

	if(!reslistp)
		return FALSE;
	
	if(*sel_res_no < 0){
		res_no = ctxp->res_num - 1;
	}else{
		res_no = *sel_res_no;
	}
	if(*sel_res_line < 0){
		res_line = INT_MAX;
	}else{
		res_line = *sel_res_line - 1;
	}
		
	cur = ctxp->res_num - 1;
	clistp = reslistp->prev;
	do{
		if(cur <= res_no){
			res_datap = (res_data_tp)clistp->data;
			//resp = res_datap->resp;
			if(!res_datap->msg_line_linkp)
				parse_res_msg(reslistp, res_datap, column);
			listp = res_datap->msg_line_linkp->prev;
			line = res_datap->msg_line_num - 1;
			do{
				if(line <= res_line){
					cptr = (wchar_t*)listp->data;
					if(0 < wcstombs(buf, cptr, sizeof(buf))){
						if(0 == regexec(regexp, buf, 
								nmatch, pmatch, 0)){
							*sel_res_line = line;
							*sel_res_no = cur;
							return TRUE;
						}
					}
				}
				line--;
				listp = listp->prev;
			}while(listp != res_datap->msg_line_linkp->prev);
			res_line = res_datap->msg_line_num - 1;
		}
		cur--;
		clistp = clistp->prev;
	}while(clistp != reslistp->prev);

	cur = ctxp->res_num - 1;
	clistp = reslistp->prev;
	do{
		if(cur <= res_no)
			break;

		res_datap = (res_data_tp)clistp->data;
		//resp = (nt_res_tp)clistp->data;
		if(!res_datap->msg_line_linkp)
			parse_res_msg(reslistp, res_datap, column);
		listp = res_datap->msg_line_linkp->prev;
		line = res_datap->msg_line_num - 1;
		do{
			if(line >= res_line){
				cptr = (wchar_t*)listp->data;
				if(0 < wcstombs(buf, cptr, sizeof(buf))){
					if(0 == regexec(regexp, buf, 
							nmatch, pmatch, 0)){
						*sel_res_line = line;
						*sel_res_no = cur;
						return TRUE;
					}
				}
			}
			line--;
			listp = listp->prev;
		}while(listp != res_datap->msg_line_linkp->prev);
		res_line = res_datap->msg_line_num - 1;
		cur--;
		clistp = clistp->prev;
	}while(clistp != reslistp->prev);
	return FALSE;
}


static nt_link_tp parse_id_list(ctx_reslist_tp ctxp, const char *param)
{
	nt_link_tp  linkp, disp_list;
	nt_link_tp wrkp, num_linkp;
	char buf[64];
	wchar_t wc[64];
	wchar_t *cptr;
	const wchar_t *misc;
	int len;
	const char *start, *end;
	res_data_tp res_datap;
	nt_res_handle h_res;
	int seq_no;
	
	assert(ctxp);
	assert(ctxp->res_disp_list);
	
	if(!nt_strtok(param, ' ', &start, &end))
		return NULL;
	len = end - start;
	if(len <= 0)
		return NULL;
	
	strcpy(buf,"ID:");
	strncat(buf, start, len);
	
	if((size_t)-1 == mbstowcs(wc, buf, sizeof(wc)/sizeof(wchar_t)-1))
		return NULL;
		
	num_linkp = NULL;
	disp_list = ctxp->res_disp_list;
	linkp = disp_list;
	do{
		res_datap = (res_data_tp)linkp->data;
		h_res = res_datap->h_res;
		misc = nt_res_get_misc(h_res);
		cptr = wcsstr(misc, wc);
		if(cptr){
			seq_no = nt_res_get_seq_number(h_res);
			wrkp = nt_link_add_n_data(num_linkp, seq_no);
			if(!num_linkp)
				num_linkp = wrkp;
		}
		linkp = linkp->next;
	}while(linkp != disp_list);
	
	return num_linkp;
}


static nt_link_tp parse_tree_list(ctx_reslist_tp ctxp, const char *param)
{
	nt_link_tp  linkp, disp_list;
	nt_link_tp wrkp, num_linkp;
	int len;
	const char *start, *end;
	res_data_tp res_datap;
	nt_res_handle h_res;
	int num;
	
	assert(ctxp);
	assert(ctxp->res_disp_list);
	
	if(!nt_strtok(param, ' ', &start, &end))
		return NULL;
	len = end - start;
	if(len <= 0)
		return NULL;
	
	num = atoi(start);
	if(num == 0)
		return NULL;
	num_linkp = nt_link_add_n_data(NULL, num);
	if(!num_linkp)
		return NULL;
	
	disp_list = ctxp->res_disp_list;
	linkp = disp_list;
	do{
		res_datap = (res_data_tp)linkp->data;
		h_res = res_datap->h_res;
		if(num == nt_res_get_seq_number(h_res)){
			if(res_datap->cite_num_list){
				wrkp = res_datap->cite_num_list;
				do{
					if(wrkp->n_data < num)
						search_up_tree(wrkp->n_data, disp_list, &num_linkp);
					wrkp = wrkp->next;
				}while(wrkp != res_datap->cite_num_list);
			}
			if(res_datap->cited_num_list){
				wrkp = res_datap->cited_num_list;
				do{
					if(wrkp->n_data > num)
						search_down_tree(wrkp->n_data, disp_list, &num_linkp);
					wrkp = wrkp->next;
				}while(wrkp != res_datap->cited_num_list);
			}
			break;
		}
		linkp = linkp->next;
	}while(linkp != disp_list);
	if(num_linkp)
		nt_link_n_sort(&num_linkp, nt_comp_int);
	return num_linkp;
}
static void search_up_tree(int seq_no, nt_link_tp disp_list, nt_link_tp *num_linkp)
{
	nt_link_tp  linkp, wrkp;
	nt_link_add_n_data(*num_linkp, seq_no);
	res_data_tp res_datap;
	nt_res_handle h_res;
	
	linkp = disp_list;
	do{
		res_datap = (res_data_tp)linkp->data;
		h_res = res_datap->h_res;
		if(seq_no == nt_res_get_seq_number(h_res)){
			if(res_datap->cite_num_list){
				wrkp = res_datap->cite_num_list;
				do{
					if(wrkp->n_data < seq_no)
						search_up_tree(wrkp->n_data, disp_list, num_linkp);
					wrkp = wrkp->next;
				}while(wrkp != res_datap->cite_num_list);
			}
			break;
		}
		linkp = linkp->next;
	}while(linkp != disp_list);
}

static void search_down_tree(int seq_no, nt_link_tp disp_list, nt_link_tp *num_linkp)
{
	nt_link_tp  linkp, wrkp;
	nt_link_add_n_data(*num_linkp, seq_no);
	res_data_tp res_datap;
	nt_res_handle h_res;
	
	linkp = disp_list;
	do{
		res_datap = (res_data_tp)linkp->data;
		h_res = res_datap->h_res;
		if(seq_no == nt_res_get_seq_number(h_res)){
			if(res_datap->cited_num_list){
				wrkp = res_datap->cited_num_list;
				do{
					if(wrkp->n_data > seq_no)
						search_down_tree(wrkp->n_data, disp_list, num_linkp);
					wrkp = wrkp->next;
				}while(wrkp != res_datap->cited_num_list);
			}
			break;
		}
		linkp = linkp->next;
	}while(linkp != disp_list);
}

