/* 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 <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <wchar.h>
#include <assert.h>
#include <iconv.h>

#define MODEL_2CH_PRIVATE_DATA

#include "env.h"
#include "utils/nt_std_t.h"
#include "utils/text.h"
#include "utils/nt_conv_char.h"
#include "_2ch/model_2ch.h"
#include "_2ch/search_2ch.h"
#include "net/nt_http.h"

#define NT_SEARCHED_THREAD_CHK_SUM (1178428)

#define NT_SEARCH_URL_REFERER "http://find.2ch.net/"
#define NT_SEARCH_URL "http://find.2ch.net/?STR=%s&SCEND=A&SORT=MODIFIED&COUNT=50&TYPE=TITLE&BBS=ALL"

typedef struct tag_nt_searched_thread_t *nt_searched_thread_tp;
typedef struct tag_nt_searched_thread_t{
	nt_searched_thread_handle_t handle;
	int ref_count;
	wchar_t *board_name;
	wchar_t *dat_name;
	wchar_t *title;
}nt_searched_thread_t;


static nt_searched_thread_tp parse_searched_thread(
			nt_2ch_model_handle h_model, wchar_t *line);

nt_searched_thread_handle nt_searched_thread_alloc(
		const wchar_t *board_name, const wchar_t *dat_name,
		const wchar_t *title)
{
	nt_searched_thread_tp sthreadp;
	
	sthreadp = malloc(sizeof(nt_searched_thread_t));
	if(!sthreadp)
		return NULL;
	
	if(board_name){
		sthreadp->board_name = nt_w_str_clone(board_name);
		if(!sthreadp->board_name){
			free(sthreadp);
			return NULL;
		}
	}else{
		sthreadp->board_name = NULL;
	}
	if(dat_name){
		sthreadp->dat_name = nt_w_str_clone(dat_name);
		if(!sthreadp->dat_name){
			free(sthreadp->board_name);
			free(sthreadp);
			return NULL;
		}
	}else{
		sthreadp->dat_name = NULL;
	}
	if(title){
		sthreadp->title = nt_w_str_clone(title);
		if(!sthreadp->title){
			free(sthreadp->dat_name);
			free(sthreadp->board_name);
			free(sthreadp);
			return NULL;
		}
	}else{
		sthreadp->title = NULL;
	}
	sthreadp->handle.chk_sum = NT_SEARCHED_THREAD_CHK_SUM;
	sthreadp->ref_count = 1;
	return &sthreadp->handle;
}

int nt_searched_thread_add_ref(nt_searched_thread_handle h_searched_thread)
{
	nt_searched_thread_tp sthreadp;
	assert(h_searched_thread);
	assert(h_searched_thread->chk_sum == NT_SEARCHED_THREAD_CHK_SUM);
	sthreadp = (nt_searched_thread_tp)h_searched_thread;
	assert(sthreadp->ref_count > 0);
	return ++sthreadp->ref_count;
}

int nt_searched_thread_release_ref(nt_searched_thread_handle h_searched_thread)
{
	nt_searched_thread_tp sthreadp;
	assert(h_searched_thread);
	assert(h_searched_thread->chk_sum == NT_SEARCHED_THREAD_CHK_SUM);
	sthreadp = (nt_searched_thread_tp)h_searched_thread;
	assert(sthreadp->ref_count > 0);
	if(0 != --sthreadp->ref_count)
		return sthreadp->ref_count;
		
	if(sthreadp->board_name)
		free(sthreadp->board_name);
	if(sthreadp->board_name)
		free(sthreadp->dat_name);
	if(sthreadp->board_name)
		free(sthreadp->title);
	free(sthreadp);
	return 0;
}

const wchar_t* nt_searched_thread_get_board_name(
			nt_searched_thread_handle h_searched_thread)
{
	nt_searched_thread_tp sthreadp;
	assert(h_searched_thread);
	assert(h_searched_thread->chk_sum == NT_SEARCHED_THREAD_CHK_SUM);
	sthreadp = (nt_searched_thread_tp)h_searched_thread;
	assert(sthreadp->ref_count > 0);
	return sthreadp->board_name;
}

const wchar_t* nt_searched_thread_get_dat_name(
			nt_searched_thread_handle h_searched_thread)
{
	nt_searched_thread_tp sthreadp;
	assert(h_searched_thread);
	assert(h_searched_thread->chk_sum == NT_SEARCHED_THREAD_CHK_SUM);
	sthreadp = (nt_searched_thread_tp)h_searched_thread;
	assert(sthreadp->ref_count > 0);
	return sthreadp->dat_name;
}

const wchar_t* nt_searched_thread_get_title(
			nt_searched_thread_handle h_searched_thread)
{
	nt_searched_thread_tp sthreadp;
	assert(h_searched_thread);
	assert(h_searched_thread->chk_sum == NT_SEARCHED_THREAD_CHK_SUM);
	sthreadp = (nt_searched_thread_tp)h_searched_thread;
	assert(sthreadp->ref_count > 0);
	return sthreadp->title;
}



BOOL nt_get_search_text(const char *in_text, char** out_text)
{
	const char *start, *end;
	int len;
	char *cptr;
	
	if(!nt_strtok(in_text, ' ', &start, &end))
		return FALSE;
	
	len = end - start;
	if(len <= 0)
		return FALSE;
	
	if(0 != strncmp(NT_COMMAND1_SEARCH_1, start, len) &&
			0 != strncmp(NT_COMMAND1_SEARCH_2, start, len))
		return FALSE;
	if(0 < strlen(end)){
		cptr = nt_trim(end);
		if(!cptr)
			return FALSE;
		*out_text = cptr;
	}else{
		*out_text = NULL;
	}
	return TRUE;
}

nt_link_tp nt_search_all_board(nt_2ch_model_handle h_model, 
			const char *search_text, const wchar_t** error_msg)
{
	char *url;
	FILE *tmp_fp;
	pid_t pid;
	char fname[512];
	nt_link_tp linkp, result_list;
	char buf[1024];
	char buf2[512];
	wchar_t wc[1024];
	iconv_t icd;
	nt_searched_thread_tp threadp;
	
	assert(error_msg);
	
	result_list = NULL;
	*error_msg = NULL;
	
	if(!search_text || strlen(search_text) == 0){
		*error_msg = L"検索文字列が指定されていません";
		return NULL;
	}
	
	icd =   iconv_open("EUC-JP", "UTF-8");
	if(((iconv_t)-1) == icd){
		*error_msg = L"文字コードの変換に失敗しました";
		return NULL;
	}
	if(!nt_conv_local2sjis(icd, search_text, buf, sizeof(buf))){
		*error_msg = L"文字コードの変換に失敗しました";
		return NULL;
	}
	iconv_close(icd);
	
	if(!url_encode(buf, buf2, sizeof(buf2))){
		*error_msg = L"URLエンコードに失敗しました";
		return NULL;
	}
	
	pid = getpid();

	sprintf(fname, "%s/msg%d.tmp", LOG_PATH, pid);
	tmp_fp = fopen(fname, "w");
	if(!tmp_fp){
		*error_msg = L"テンポラリファイルの作成に失敗しました";
		return NULL;
	}
	fclose(tmp_fp);
	
	url = malloc(strlen(NT_SEARCH_URL) + strlen(buf2) + 1);
	if(!url){
		*error_msg = L"メモリーエラー";
		return NULL;
	}
	
	sprintf(url, NT_SEARCH_URL, buf2);
	
	if(!nt_http_get(url, fname, NT_SEARCH_URL_REFERER,
			NULL, NULL, FALSE, TRUE)){
		*error_msg = L"ネットワーク接続に失敗しました";
		free(url);
		return NULL;
	}
	
	tmp_fp = fopen(fname, "r");
	if(!tmp_fp){
		*error_msg = L"テンポラリファイルの作成に失敗しました";
		free(url);
		return NULL;
	}
	
	icd =   iconv_open("wchar_t","EUC-JP");
	if(((iconv_t)-1) == icd){
		*error_msg = L"文字コードの変換に失敗しました";
		goto ERROR_TRAP;
	}
	while(fgets(buf, sizeof(buf), tmp_fp)){
		if(!nt_conv_sjis2wc(icd, buf, wc, 
					sizeof(wc)*sizeof(wchar_t))){
			//*error_msg = L"文字コードの変換に失敗しました";
			//iconv_close(icd);
			//goto ERROR_TRAP;
		}else{
			threadp = parse_searched_thread(h_model, wc);
			if(threadp){
				linkp = nt_link_add_data(result_list, threadp);
				if(!result_list)
					result_list = linkp;
			}
		}
	}
	iconv_close(icd);
	/*if(result_list){
		h_enum_result = nt_enum_set(result_list);
		if(h_enum_result){
			nt_enum_set_free_func(h_enum_result, free_searched_thread);
		}else{
			nt_all_link_free(result_list, free_searched_thread);
		}
	}*/
ERROR_TRAP:
	fclose(tmp_fp);
	unlink(fname);
	free(url);
	return result_list;
}

		
static nt_searched_thread_tp parse_searched_thread(
			nt_2ch_model_handle h_model, wchar_t *line)
{
	nt_searched_thread_tp threadp;
	nt_board_handle h_board;
	wchar_t *cptr, *cptr2;
	const wchar_t *board_name;
	wchar_t dat_name[20];
	wchar_t *dat, *title;
	
	assert(line);
	cptr = wcsstr(line, L"<dt><a href=\"");
	if(!cptr)
		return NULL;
	cptr += wcslen(L"<dt><a href=\"");
	
	cptr = wcsstr(cptr, L"test/read.cgi/");
	if(!cptr)
		return NULL;
	cptr += wcslen(L"test/read.cgi/");
	
	cptr2 = wcsstr(cptr, L"/");
	if(!cptr2)
		return NULL;
	*cptr2 = L'\0';
	cptr2++;
	
	h_board = nt_get_board_by_address_match(h_model, cptr);
	if(!h_board){
		return NULL;
	}
	board_name = nt_board_get_name(h_board);
	
	cptr = wcsstr(cptr2, L"/");
	if(!cptr)
		goto ERROR_TRAP;
	
	*cptr = L'\0';
	cptr++;
	
	dat = cptr2;
	
	cptr2 = wcsstr(cptr, L">");
	if(!cptr2)
		goto ERROR_TRAP;
	
	cptr2++;
	
	cptr = wcsstr(cptr2, L"</a>");
	if(!cptr)
		goto ERROR_TRAP;
	*cptr = L'\0';
	
	title = cptr2;
	
	wcscpy(dat_name, dat);
	cptr = wcsstr(dat, L".");
	if(!cptr)
		wcscat(dat_name, L".dat");
	
	threadp = (nt_searched_thread_tp)nt_searched_thread_alloc(
				board_name, dat_name, title);
	if(!threadp)
		goto ERROR_TRAP;
		
	nt_board_release_ref(h_board);
	return threadp;
ERROR_TRAP:
	nt_board_release_ref(h_board);
	return NULL;
}


