#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <assert.h>
#include <wchar.h>
#include <iconv.h>
#include <errno.h>
#include <time.h>

#include "env.h"
#include "utils/nt_std_t.h"
#include "utils/file.h"
#include "utils/base64.h"
#include "net/nt_http.h"
#include "net/nt_cookie.h"
#include "_2ch/model_2ch.h"
#include "_2ch/_2ch.h"

char *URL_2CH_BOARDMENU = "http://menu.2ch.net/bbsmenu.html";
nt_2ch_model_tp app_2ch_modelp;


#define S_SIZE  (1024*2)

static BOOL conv_sjis2wc(iconv_t icd, 
	const char *src, wchar_t *data, size_t data_len);
static BOOL conv_wc2sjis(iconv_t icd, 
	const wchar_t *src, char *data, size_t data_len);
static BOOL conv_local2sjis(iconv_t icd, 
	const char *src, char *data, size_t data_len);
static BOOL set_post_data(char *data, size_t data_len,
		const wchar_t *bbs, const wchar_t *id, 
		const char *name, const char *mail, 
		const char *msg);

BOOL nt_2ch_model_init(){
	app_2ch_modelp = nt_2ch_model_alloc();
	return (NULL != app_2ch_modelp);
}

BOOL nt_init_board_menu()
{
	char	*outp;
	char	*url = URL_2CH_BOARDMENU;
	iconv_t	icd;
	FILE	*fp_src;
	char	s_src[S_SIZE],	s_dst[S_SIZE*sizeof(wchar_t)];
	char	*p_src,	*p_dst;
	size_t	n_src,	n_dst;

	memset(s_src, '\0', S_SIZE);
	memset(s_dst, '\0', S_SIZE*sizeof(wchar_t));

	if(!nt_make_sha1_path(LOG_PATH, url, &outp)){
		return	FALSE;
	}


	if(!nt_http_get(url, outp, NULL, NULL, NULL, FALSE)){
		free(outp);
		return FALSE;
	}

	fp_src	=	fopen(outp, "r");
	if(!fp_src){
		free(outp);
		return FALSE;
	}
	icd	=	iconv_open("wchar_t", "cp932");
	if(((iconv_t)-1) == icd){
		free(outp);
		return FALSE;
	}
	while(1){
		if(feof(fp_src))
			break;
		s_src[0] = '\0';
		fgets(s_src, S_SIZE, fp_src);
		p_src = s_src;
		p_dst = s_dst;

		n_src	=	strlen(s_src);
		n_dst	=	S_SIZE-1;
		while(0	<	n_src){
			size_t sz = iconv(icd, &p_src, &n_src, &p_dst, &n_dst);
			if(sz == -1){
				//fprintf(stderr, "errno: %d %s\n", errno, s_src);
				break;
			}
		}
		//*p_dst	=	'\0';
		*((wchar_t*)p_dst) = L'\0';
		parse_board_menu(app_2ch_modelp, (const wchar_t*)s_dst);
	}

	if(fp_src)
		fclose(fp_src);
	iconv_close(icd);

	free(outp);
	
	return TRUE;
}


BOOL nt_read_thread(nt_2ch_model_tp modelp)
{
	wchar_t url[1024];
	wchar_t referer[1024];
	wchar_t buf[1024];
	char	*outp;
	wchar_t *file_name, *cptr;
	wchar_t *server_name, *board_name;
	nt_board_tp boardp;
	nt_thread_tp threadp;
	int len;
	iconv_t icd;
	FILE	*fp_src;
	char	s_src[S_SIZE*sizeof(wchar_t)];
	char	s_dst[S_SIZE*sizeof(wchar_t)];
	char	*p_src,	*p_dst;
	size_t	n_src,	n_dst;

	memset(s_src, '\0', sizeof(s_src));
	memset(s_dst, '\0', sizeof(s_dst));


	if(!modelp->selected_categoryp)
		return FALSE;
	if(!modelp->selected_boardp)
		return FALSE;
	if(!modelp->selected_threadp)
		return FALSE;

	boardp = modelp->selected_boardp;
	threadp = modelp->selected_threadp;
	file_name = threadp->file_name;

	wcscpy(url, boardp->address);
	len = wcslen(url);
	if(len <= 0)
		return FALSE;
	if(url[len-1] != L'/'){
		url[len] = L'/';
		len++;
		url[len] = L'\0';
	}
	wcscat(url, L"dat/");
	wcscat(url, file_name);

	if(!nt_parse_server_name_and_board_name(boardp->address,
		buf, sizeof(buf), &server_name, &board_name)){
		return FALSE;
	}

	wcscpy(referer, L"http://");
	wcscat(referer, server_name);
	wcscat(referer, L"/test/read.cgi/");
	wcscat(referer, board_name);
	wcscat(referer, L"/");
	cptr = nt_rid_sufix(file_name);
	if(!cptr)
		return FALSE;
	wcscat(referer, cptr);
	free(cptr);
	wcscat(referer, L"/");
	len = wcstombs(s_src, url, sizeof(s_src)-1);
	if(len <= 0)
		return FALSE;
	len = wcstombs(s_dst, referer, sizeof(s_dst)-1);
	if(len <= 0)
		return FALSE;
	if(!nt_make_sha1_path(LOG_PATH, s_src, &outp)){
		return	FALSE;
	}

	if(!nt_http_get(s_src, outp, s_dst, NULL, NULL, TRUE)){
		free(outp);
		return FALSE;
	}
	fp_src = fopen(outp, "r");
	if(!fp_src){
		free(outp);
		return FALSE;
	}
	icd	=	iconv_open("wchar_t", "cp932");
	if(((iconv_t)-1) == icd){
		fclose(fp_src);
		free(outp);
		return FALSE;
	}
	threadp->num_res = 0;
	while(1){
		if(feof(fp_src))
			break;
		s_src[0] = '\0';
		fgets(s_src, S_SIZE, fp_src);
		p_src = s_src;
		p_dst = s_dst;

		n_src	=	strlen(s_src);
		n_dst	=	sizeof(s_dst)-1;
		while(0	< n_src){
			size_t sz = iconv(icd, &p_src, &n_src, &p_dst, &n_dst);
			if(sz == -1){
				//fprintf(stderr, "errno: %d %s\n", errno, s_src);
				break;
			}
		}
		*((wchar_t*)p_dst) = L'\0';
		parse_thread(threadp, (const wchar_t*)s_dst);
	}

	fclose(fp_src);
	iconv_close(icd);
	free(outp);
	return (threadp->num_res > 0);
}

BOOL nt_read_board(nt_2ch_model_tp modelp)
{
	wchar_t *address;
	char data[256+1];
	iconv_t icd;
	char *outp;
	int len;
	FILE	*fp_src;
	char	s_src[S_SIZE],	s_dst[S_SIZE*sizeof(wchar_t)];
	char	*p_src,	*p_dst;
	size_t	n_src,	n_dst;
	nt_board_tp boardp;

	memset(data, 0, sizeof(data));
	memset(s_src, '\0', S_SIZE);
	memset(s_dst, '\0', S_SIZE*sizeof(wchar_t));

	if(!modelp->selected_categoryp)
		return FALSE;
	if(!modelp->selected_boardp)
		return FALSE;

	boardp = modelp->selected_boardp;
	nt_board_children_free(boardp);
	address = boardp->address;
	assert(address);

	len = wcstombs(data, address, sizeof(data)-1);
	if(len <= 0)
		return FALSE;

	if(data[len-1] != '/')
		strcat(data, "/");
	strcat(data, "subject.txt");


	if(!nt_make_sha1_path(LOG_PATH, data, &outp)){
		return	FALSE;
	}

	if(!nt_http_get(data, outp, URL_2CH_BOARDMENU, NULL, NULL, FALSE)){
		free(outp);
		return FALSE;
	}

	fp_src = fopen(outp, "r");
	if(!fp_src){
		free(outp);
		return FALSE;
	}
	icd	=	iconv_open("wchar_t", "cp932");
	if(((iconv_t)-1) == icd){
		fclose(fp_src);
		free(outp);
		return FALSE;
	}
	while(1){
		if(feof(fp_src))
			break;
		s_src[0] = '\0';
		fgets(s_src, S_SIZE, fp_src);
		p_src = s_src;
		p_dst = s_dst;

		n_src	=	strlen(s_src);
		n_dst	=	S_SIZE-1;
		while(0	<	n_src){
			size_t sz = iconv(icd, &p_src, &n_src, &p_dst, &n_dst);
			if(sz == -1){
				//fprintf(stderr, "errno: %d %s\n", errno, s_src);
				break;
			}
		}
		*((wchar_t*)p_dst) = L'\0';
		parse_board(boardp, (const wchar_t*)s_dst);
	}

	fclose(fp_src);
	iconv_close(icd);

	free(outp);
	return TRUE;
}

BOOL nt_write_msg(nt_2ch_model_tp modelp, nt_write_data_tp writep,
			nt_cookie_tp cookiep, nt_maru_2ch_tp marup)
{
	wchar_t	url[1024];	
	wchar_t	referer[1024];
	char	post_data[1024*4];
	wchar_t	buf[512];
	char	out_buf[1024*4];
	wchar_t	*dat_name;
	wchar_t	*file_name;
	wchar_t	*server_name,	*board_name;
	nt_board_tp	boardp;
	nt_thread_tp	threadp;
	int	len;
	char	s_src[S_SIZE*sizeof(wchar_t)];
	char	s_dst[S_SIZE*sizeof(wchar_t)];
	BOOL result = FALSE;
	iconv_t icd = 0;

	memset(s_src,	'\0',	sizeof(s_src));
	memset(s_dst,	'\0',	sizeof(s_dst));
	memset(post_data,	'\0',	sizeof(post_data));

	assert(modelp);

	if(!modelp->selected_categoryp)
		return	FALSE;
	if(!modelp->selected_boardp)
		return	FALSE;
	if(!modelp->selected_threadp)
		return	FALSE;

	boardp = modelp->selected_boardp;
	threadp = modelp->selected_threadp;
	file_name = threadp->file_name;

	if(!nt_parse_server_name_and_board_name(boardp->address,
		buf, sizeof(buf), &server_name, &board_name)){
		return FALSE;
	}

	wcscpy(url, L"http://");
	wcscat(url, server_name);
	wcscat(url, L"/test/bbs.cgi");
	
	wcscpy(referer, L"http://");
	wcscat(referer, server_name);
	wcscat(referer, L"/test/read.cgi/");
	wcscat(referer, board_name);
	wcscat(referer, L"/");
	dat_name = nt_rid_sufix(file_name);
	if(!dat_name)
		return FALSE;
	wcscat(referer, dat_name);
	wcscat(referer, L"/");

	len = wcstombs(s_src, url, sizeof(s_src)-1);
	if(len <= 0)
		goto ERROR_TRAP;
	len = wcstombs(s_dst, referer, sizeof(s_dst)-1);
	if(len <= 0)
		goto ERROR_TRAP;
	if(!set_post_data(post_data, sizeof(post_data),
			board_name, dat_name, writep->name,
			writep->mail, writep->msg)){
		goto ERROR_TRAP;
	}
	strcat(post_data, "&yuki=akari");

	if(marup && marup->sid){
		strcat(post_data, "&sid=");
		strcat(post_data, marup->sid);
	}
	if(!nt_http_post(s_src, post_data, out_buf, sizeof(out_buf),
	            s_dst, NULL, NULL, cookiep)){
		goto ERROR_TRAP;
	}
	icd =   iconv_open("wchar_t", "cp932");
	if(((iconv_t)-1) == icd){
		icd = 0;
		goto ERROR_TRAP;
	}
	if(writep->result_html)
		free(writep->result_html);
	writep->result_html = malloc(1024*sizeof(wchar_t)*4);
	if(!writep->result_html)
		goto ERROR_TRAP;

	if(!conv_sjis2wc(icd, out_buf, writep->result_html, 
				1024*sizeof(wchar_t)*4)){
		goto ERROR_TRAP;
	}
	result = TRUE;
ERROR_TRAP:
	if(icd)
		iconv_close(icd);
	free(dat_name);
	return (result);
}

static BOOL set_post_data(char *data, size_t data_len,
		const wchar_t *bbs, const wchar_t *id, 
		const char *name, const char *mail, 
		const char *msg)
{
	iconv_t icd;
	time_t t;
	char buf[1024*4];
	char buf2[1024*4];
	char *cptr;
	assert(bbs && id && name && mail && msg);

	memset(buf, 0, sizeof(buf));
	memset(buf2, 0, sizeof(buf2));

	icd =   iconv_open("cp932", "wchar_t");
	if(((iconv_t)-1) == icd){
	    return FALSE;
	}
	t =  time(NULL);
	t -= 600;

	cptr = data;
	strcpy(cptr, "bbs=");
	cptr += strlen(data);
	if(!conv_wc2sjis(icd, bbs, buf, sizeof(buf)))
		return FALSE;
	strcpy(cptr, buf);
	cptr+= strlen(cptr);
	strcpy(cptr, "&key=");
	cptr += strlen(cptr);
	if(!conv_wc2sjis(icd, id, buf, sizeof(buf)))
		return FALSE;
	strcpy(cptr, buf);
	cptr+= strlen(cptr);
	strcpy(cptr, "&time=");
	cptr += strlen(cptr);
	sprintf(buf, "%ld&FROM=", t);
	strcpy(cptr, buf);
	cptr+= strlen(cptr);

	iconv_close(icd);

	icd =   iconv_open("cp932", "UTF-8");
	if(icd == (iconv_t)-1){
		perror("e");
		return FALSE;
	}

	if(name && 0 < strlen(name)){
		if(!conv_local2sjis(icd, name, buf, sizeof(buf)))
			return FALSE;
		if(!url_encode(buf, buf2, sizeof(buf2)))
			return FALSE;
		strcpy(cptr, buf2);
		cptr += strlen(buf2);
	}
	strcpy(cptr, "&mail=");
	cptr += strlen(cptr);
	if(mail && 0 < strlen(mail)){
		if(!conv_local2sjis(icd, mail, buf, sizeof(buf)))
			return FALSE;
		if(!url_encode(buf, buf2, sizeof(buf2)))
			return FALSE;
		strcpy(cptr, buf2);
		cptr += strlen(buf2);
	}
	strcpy(cptr, "&MESSAGE=");
	cptr += strlen(cptr);
	if(msg && 0 < strlen(msg)){
		if(!conv_local2sjis(icd, msg, buf, sizeof(buf)))
			return FALSE;
		if(!url_encode(buf, buf2, sizeof(buf2)))
			return FALSE;
		strcpy(cptr, buf2);
		cptr += strlen(buf2);
	}
	strcpy(cptr, "&submit=8F%91%82%AB%8D%9E%82%DE");

	iconv_close(icd);
	
	return TRUE;
}

static BOOL conv_sjis2wc(iconv_t icd, 
	const char *src, wchar_t *data, size_t data_len)
{
	char    *p_src, *p_dst;
	size_t  n_src,  n_dst, sz;
	p_src = (char*)src;
	p_dst = (char*)data;
	n_src   =   strlen(src) * sizeof(char);
	n_dst   =   data_len;
	while(0 < n_src){
		sz = iconv(icd, &p_src, &n_src, &p_dst, &n_dst);
		if(sz == -1){
			perror("e");
			return FALSE;
		}
	}
	*((wchar_t*)p_dst) = L'\0';
	return TRUE;
}

static BOOL conv_wc2sjis(iconv_t icd, 
	const wchar_t *src, char *data, size_t data_len)
{
	char    *p_src, *p_dst;
	size_t  n_src,  n_dst, sz;
	p_src = (char*)src;
	p_dst = data;
	n_src   =   wcslen(src) * sizeof(wchar_t);
	n_dst   =   data_len;
	while(0 < n_src){
		sz = iconv(icd, &p_src, &n_src, &p_dst, &n_dst);
		if(sz == -1){
			perror("e");
			return FALSE;
		}
	}
	*p_dst = '\0';
	return TRUE;
}


static BOOL conv_local2sjis(iconv_t icd, 
	const char *src, char *data, size_t data_len)
{
	char    *p_src, *p_dst;
	size_t  n_src,  n_dst, sz;
	p_src = (char*)src;
	p_dst = data;
	n_src   =   strlen(p_src);
	n_dst   =   data_len;
	while(0 < n_src){
		sz = iconv(icd, &p_src, &n_src, &p_dst, &n_dst);
		if(((size_t)-1) == sz){
			return FALSE;
		}
	}
	*p_dst = '\0';
	return TRUE;
}
