#include <stdlib.h>
#include <assert.h>

#include "utils/nt_std_t.h"
#include "utils/text.h"
#include "html/html_string.h"
#include "_2ch/model_2ch.h"

extern void nt_set_selected_board(nt_2ch_model_tp modelp,
         nt_category_tp categoryp, nt_board_tp boardp)
{
	assert(modelp);
	assert(categoryp);
	assert(boardp);

	modelp->selected_categoryp = categoryp;
	modelp->selected_boardp = boardp;
	modelp->selected_threadp = NULL;
}

extern void nt_set_selected_thread(nt_2ch_model_tp modelp,
        nt_thread_tp threadp)
{
	assert(modelp);
	assert(threadp);

	modelp->selected_threadp = threadp;
}

nt_2ch_model_tp nt_2ch_model_alloc()
{
	return (nt_2ch_model_tp)calloc(1, sizeof(nt_2ch_model_t));
}

nt_category_tp nt_category_alloc(
		nt_2ch_model_tp modelp, const wchar_t *name)
{
	nt_link_tp linkp, ptr;
	nt_category_tp categoryp = malloc(sizeof(nt_category_t));
	if(!categoryp)
		return NULL;

	categoryp->name = nt_w_trim(name);
	if(!categoryp->name){
		free(categoryp);
		return NULL;
	}
	categoryp->boardlistp = NULL;
	linkp = modelp->categorylistp;
	ptr = nt_link_add_data(linkp, categoryp);
	if(!ptr){
		free(categoryp->name);
		free(categoryp);
		return NULL;
	}
	if(linkp == NULL)
		modelp->categorylistp = ptr;
	return categoryp;
}

nt_board_tp nt_board_alloc(
		nt_category_tp categoryp, const wchar_t *name,
		const wchar_t *addressp)
{
	nt_link_tp linkp, ptr;
	assert(categoryp);
	nt_board_tp boardp = malloc(sizeof(nt_board_t));
	if(!boardp)
		return NULL;

	boardp->name = nt_w_trim(name);
	if(!boardp->name){
		free(boardp);
		return NULL;
	}
	boardp->address = nt_w_trim_quotes(addressp);
	if(!boardp->address){
		free(boardp->name);
		free(boardp);
		return NULL;
	}
	boardp->threadlistp = NULL;
	linkp = categoryp->boardlistp;
	ptr = nt_link_add_data(linkp, boardp);
	if(!ptr){
		free(boardp->address);
		free(boardp->name);
		free(boardp);
		return NULL;
	}
	if(linkp == NULL)
		categoryp->boardlistp = ptr;
	return boardp;
}

nt_thread_tp nt_thread_alloc(
		nt_board_tp boardp, const wchar_t *name,
		const wchar_t *file_name, int num_res)
{
	nt_link_tp linkp, ptr;
	assert(boardp);
	nt_thread_tp threadp = malloc(sizeof(nt_thread_t));
	if(!threadp)
		return NULL;

	threadp->name = nt_w_trim(name);
	if(!threadp->name){
		free(threadp);
		return NULL;
	}
	threadp->file_name = nt_w_trim_quotes(file_name);
	if(!threadp->file_name){
		free(threadp->name);
		free(threadp);
		return NULL;
	}
	threadp->reslistp = NULL;

	linkp = boardp->threadlistp;
	ptr = nt_link_add_data(linkp, threadp);
	if(!ptr){
		free(threadp->file_name);
		free(threadp->name);
		free(threadp);
		return NULL;
	}
	if(linkp == NULL)
		boardp->threadlistp = ptr;
	return threadp;
}

nt_res_tp nt_res_alloc(nt_thread_tp threadp, 
		const wchar_t *name, const wchar_t *mail, 
		const wchar_t *misc, const wchar_t *msg)
{
	nt_link_tp linkp, ptr;
	wchar_t *cptr;
	assert(threadp);
	nt_res_tp resp = malloc(sizeof(nt_res_t));
	if(!resp)
		return NULL;

	cptr = nt_decord_html_entity(name);
	resp->name = cptr;
	if(!resp->name){
		free(resp);
		return NULL;
	}
	resp->mail = nt_w_trim(mail);
	if(!resp->mail){
		free(resp);
		return NULL;
	}
	resp->misc = nt_w_trim(misc);
	if(!resp->misc){
		free(resp);
		return NULL;
	}
	resp->msg = nt_w_trim(msg);
	if(!resp->msg){
		free(resp);
		return NULL;
	}
	resp->msg_header_line_num = 0;
	resp->msg_line_num = 0;
	resp->msg_line_linkp = NULL;

	linkp = threadp->reslistp;
	ptr = nt_link_add_data(linkp, resp);
	if(!ptr){
		free(resp->name);
		free(resp->mail);
		free(resp->misc);
		free(resp->msg);
		free(resp);
		return NULL;
	}
	if(linkp == NULL)
		threadp->reslistp = ptr;
	return resp;
}

void nt_2ch_model_free(nt_2ch_model_tp ptr)
{
	nt_link_tp curp, nextp;
	nt_category_tp categoryp;
	if(!ptr)
		return;
	nt_link_tp listp = ptr->categorylistp;
	if(!listp)
		return;
	curp = listp->next;
	while(listp != curp){
		nextp = curp->next;
		categoryp = (nt_category_tp)curp->data;
		nt_category_free(categoryp);
		curp = nt_link_remove(listp, curp);
		assert(curp);
		free(curp);
		curp = nextp;
	}
	categoryp = (nt_category_tp)curp->data;
	nt_category_free(categoryp);
	free(curp);
	free(ptr);
}

void nt_category_free(nt_category_tp ptr)
{
	nt_link_tp curp, nextp;
	nt_board_tp boardp;
	assert(ptr);
	nt_link_tp listp = ptr->boardlistp;
	if(!listp){
		free(ptr->name);
		free(ptr);
		return;
	}
	curp = listp->next;
	while(listp != curp){
		nextp = curp->next;
		boardp = (nt_board_tp)curp->data;
		nt_board_free(boardp);
		curp = nt_link_remove(listp, curp);
		assert(curp);
		free(curp);
		curp = nextp;
	}
	boardp = (nt_board_tp)curp->data;
	nt_board_free(boardp);
	free(curp);
	free(ptr->name);
	free(ptr);
}

void nt_board_free(nt_board_tp ptr)
{
	nt_link_tp curp, nextp;
	nt_thread_tp threadp;
	assert(ptr);
	nt_link_tp listp = ptr->threadlistp;
	if(!listp){
		free(ptr->address);
		free(ptr->name);
		free(ptr);
		return;
	}
	curp = listp->next;
	while(listp != curp){
		nextp = curp->next;
		threadp = (nt_thread_tp)curp->data;
		nt_thread_free(threadp);
		curp = nt_link_remove(listp, curp);
		assert(curp);
		free(curp);
		curp = nextp;
	}
	threadp = (nt_thread_tp)curp->data;
	nt_thread_free(threadp);
	free(curp);
	free(ptr->address);
	free(ptr->name);
	free(ptr);
}

void nt_board_children_free(nt_board_tp ptr)
{
	nt_link_tp curp, nextp;
	nt_thread_tp threadp;
	assert(ptr);
	nt_link_tp listp = ptr->threadlistp;
	if(!listp){
		return;
	}
	curp = listp->next;
	while(listp != curp){
		nextp = curp->next;
		threadp = (nt_thread_tp)curp->data;
		nt_thread_free(threadp);
		curp = nt_link_remove(listp, curp);
		assert(curp);
		free(curp);
		curp = nextp;
	}
	threadp = (nt_thread_tp)curp->data;
	nt_thread_free(threadp);
	free(curp);
	ptr->threadlistp = NULL;
}


void nt_thread_free(nt_thread_tp ptr)
{
	nt_link_tp curp, nextp;
	nt_res_tp resp;
	assert(ptr);
	nt_link_tp listp = ptr->reslistp;
	if(!listp){
		free(ptr->file_name);
		free(ptr->name);
		free(ptr);
		return;
	}
	curp = listp->next;
	while(listp != curp){
		nextp = curp->next;
		resp = (nt_res_tp)curp->data;
		nt_res_free(resp);
		curp = nt_link_remove(listp, curp);
		assert(curp);
		free(curp);
		curp = nextp;
	}
	resp = (nt_res_tp)curp->data;
	nt_res_free(resp);
	free(curp);
	free(ptr->file_name);
	free(ptr->name);
	free(ptr);
}

void nt_thread_children_free(nt_thread_tp ptr)
{
	nt_link_tp curp, nextp;
	nt_res_tp resp;
	assert(ptr);
	nt_link_tp listp = ptr->reslistp;
	if(!listp){
		return;
	}
	curp = listp->next;
	while(listp != curp){
		nextp = curp->next;
		resp = (nt_res_tp)curp->data;
		nt_res_free(resp);
		curp = nt_link_remove(listp, curp);
		assert(curp);
		free(curp);
		curp = nextp;
	}
	resp = (nt_res_tp)curp->data;
	nt_res_free(resp);
	free(curp);
	ptr->reslistp = NULL;
}

void nt_res_free(nt_res_tp ptr)
{
	assert(ptr);
	nt_res_msg_free(ptr);
	free(ptr->name);
	free(ptr->mail);
	free(ptr->misc);
	free(ptr->msg);
	free(ptr);
}

void nt_res_msg_free(nt_res_tp ptr)
{
	nt_link_tp curp, nextp;
	assert(ptr);
	if(ptr->msg_line_linkp){
		curp = ptr->msg_line_linkp->next;
		while(curp != ptr->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);
		ptr->msg_line_linkp = NULL;
	}
}


nt_write_data_tp nt_write_data_alloc()
{
	nt_write_data_tp writep
		= (nt_write_data_tp)calloc(1,
				sizeof(nt_write_data_t));
	return writep;
}

void nt_write_data_free(nt_write_data_tp ptr)
{
	assert(ptr);
	if(ptr->name)
		free(ptr->name);
	if(ptr->mail)
		free(ptr->mail);
	if(ptr->msg)
		free(ptr->msg);
	if(ptr->result_html)
		free(ptr->result_html);
	if(ptr->cookies)
		nt_all_link_free(ptr->cookies, free);

	free(ptr);
}


