/* 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 <wchar.h>
#include <assert.h>

#define MODEL_2CH_PRIVATE_DATA

#include "utils/nt_std_t.h"
#include "_2ch/model_2ch.h"

static BOOL address_match(const wchar_t *address, const wchar_t *param);

nt_board_handle nt_get_board_by_name(
		nt_2ch_model_handle h_model, const wchar_t *board_name,
		nt_category_handle *h_categoryp)
{
	nt_2ch_model_tp modelp;
	nt_category_tp catep;
	nt_board_tp boardp;
	nt_link_tp cate_list, board_list;
	nt_link_tp clinkp, blinkp;
	
	assert(h_model);
	assert(h_model->chk_sum == NT_2CH_MODEL_CHK_SUM);
	
	modelp = (nt_2ch_model_tp)h_model;
	
	cate_list = modelp->categorylistp;
	if(!cate_list)
		return NULL;
	
	clinkp = cate_list;
	do{
		catep = (nt_category_tp)clinkp->data;
		board_list = catep->boardlistp;
		blinkp = board_list;
		if(blinkp){
			do{
				boardp = (nt_board_tp)blinkp->data;
				if(0 == wcscmp(boardp->name, board_name)){
					*h_categoryp = &catep->handle;
					nt_category_add_ref(&catep->handle);
					nt_board_add_ref(&boardp->handle);
					return &boardp->handle;
				}
				blinkp = blinkp->next;
			}while(blinkp != board_list);
		}
		clinkp = clinkp->next;
	}while(clinkp != cate_list);
	return NULL;
}

nt_board_handle nt_get_board_by_address_match(
		nt_2ch_model_handle h_model, const wchar_t *param)
{
	nt_2ch_model_tp modelp;
	nt_category_tp catep;
	nt_board_tp boardp;
	nt_link_tp cate_list, board_list;
	nt_link_tp clinkp, blinkp;
	
	assert(h_model);
	assert(h_model->chk_sum == NT_2CH_MODEL_CHK_SUM);
	
	modelp = (nt_2ch_model_tp)h_model;
	
	cate_list = modelp->categorylistp;
	if(!cate_list)
		return NULL;
	
	clinkp = cate_list;
	do{
		catep = (nt_category_tp)clinkp->data;
		board_list = catep->boardlistp;
		blinkp = board_list;
		if(blinkp){
			do{
				boardp = (nt_board_tp)blinkp->data;
				if(address_match(boardp->address, param)){
					nt_board_add_ref(&boardp->handle);
					return &boardp->handle;
				}
				blinkp = blinkp->next;
			}while(blinkp != board_list);
		}
		clinkp = clinkp->next;
	}while(clinkp != cate_list);
	return NULL;
}


static BOOL address_match(const wchar_t *address, const wchar_t *param)
{
	wchar_t *cptr;
	assert(address);
	
	cptr = wcsstr(address, L"http://");
	if(!cptr)
		return FALSE;
	
	cptr = wcsstr(cptr, L"/");
	if(!cptr)
		return FALSE;
	cptr = wcsstr(cptr, param);
	return (cptr == NULL) ? FALSE : TRUE;
}

nt_thread_handle nt_get_thread_by_seq_no(
		nt_board_handle h_board, int seq_no)
{
	nt_board_tp boardp;
	nt_link_tp linkp;
	nt_thread_tp threadp;

	assert(h_board);
	assert(h_board->chk_sum == NT_2CH_BOARD_CHK_SUM);
	boardp = (nt_board_tp)h_board;

	if(boardp->threadlistp){
		linkp = boardp->threadlistp;
		do{
			threadp = (nt_thread_tp)linkp->data;
			if(seq_no == threadp->seq_no){
				nt_thread_add_ref(&threadp->handle);
				return &threadp->handle;
			}
			linkp = linkp->next;
		}while(linkp != boardp->threadlistp);
	}
	return NULL;
}

nt_thread_handle nt_get_thread_by_dat_name(
		nt_board_handle h_board, const wchar_t *dat_name)
{
	nt_board_tp boardp;
	nt_link_tp linkp;
	nt_thread_tp threadp;

	assert(h_board);
	assert(h_board->chk_sum == NT_2CH_BOARD_CHK_SUM);
	boardp = (nt_board_tp)h_board;

	if(boardp->threadlistp){
		linkp = boardp->threadlistp;
		do{
			threadp = (nt_thread_tp)linkp->data;
			if(0 == wcscmp(dat_name, threadp->file_name)){
				nt_thread_add_ref(&threadp->handle);
				return &threadp->handle;
			}
			linkp = linkp->next;
		}while(linkp != boardp->threadlistp);
	}
	return NULL;
}

nt_thread_handle nt_get_thread_by_board_and_dat_name(
		nt_2ch_model_handle h_model,
		const wchar_t *board_name, const wchar_t *dat_name)
{
	nt_category_handle h_category;
	nt_board_handle h_board;
	nt_thread_handle h_thread;
	
	assert(board_name && dat_name);
	assert(h_model);
	assert(h_model->chk_sum == NT_2CH_MODEL_CHK_SUM);
	
	h_board = nt_get_board_by_name(h_model, board_name,
			&h_category);
	if(!h_board)
		return NULL;
	nt_category_release_ref(h_category);
	
	h_thread = nt_get_thread_by_dat_name(h_board, dat_name);
	nt_board_release_ref(h_board);
	if(!h_thread)
		return NULL;
	return h_thread;
}

nt_enum_handle nt_2ch_model_get_category_enum(nt_2ch_model_handle h_model)
{
	nt_2ch_model_tp modelp;
	
	assert(h_model);
	assert(h_model->chk_sum == NT_2CH_MODEL_CHK_SUM);
	modelp = (nt_2ch_model_tp)h_model;
	assert(modelp->ref_count > 0);
	
	if(!modelp->categorylistp)
		return NULL;
	
	return nt_enum_set(modelp->categorylistp);
}

nt_enum_handle nt_category_get_board_enum(nt_category_handle h_category)
{
	nt_category_tp categoryp;
	
	assert(h_category);
	assert(h_category->chk_sum == NT_2CH_CATEGORY_CHK_SUM);
	categoryp = (nt_category_tp)h_category;
	assert(categoryp->ref_count > 0);
	
	if(!categoryp->boardlistp)
		return NULL;
	
	return nt_enum_set(categoryp->boardlistp);
}

nt_enum_handle nt_board_get_thread_enum(nt_board_handle h_board)
{
	nt_board_tp boardp;
	
	assert(h_board);
	assert(h_board->chk_sum == NT_2CH_BOARD_CHK_SUM);
	boardp = (nt_board_tp)h_board;
	assert(boardp->ref_count > 0);
	
	if(!boardp->threadlistp)
		return NULL;
	
	return nt_enum_set(boardp->threadlistp);
}

nt_enum_handle nt_thread_get_res_enum(nt_thread_handle h_thread)
{
	nt_thread_tp threadp;
	
	assert(h_thread);
	assert(h_thread->chk_sum == NT_2CH_THREAD_CHK_SUM);
	threadp = (nt_thread_tp)h_thread;
	assert(threadp->ref_count > 0);
	
	if(!threadp->reslistp)
		return NULL;
	
	return nt_enum_set(threadp->reslistp);
}

nt_mutex_handle nt_2ch_model_get_mutex(nt_2ch_model_handle h_model)
{
	nt_2ch_model_tp modelp;
	nt_mutex_handle h_mutex;
	
	assert(h_model);
	assert(h_model->chk_sum == NT_2CH_MODEL_CHK_SUM);
	modelp = (nt_2ch_model_tp)h_model;
	assert(modelp->ref_count > 0);
	
	nt_2ch_model_add_ref(h_model);
	
	h_mutex = nt_mutex_get_one_time_handle(modelp->key);
	
	nt_2ch_model_release_ref(h_model);
	if(!h_mutex){
		return NULL;
	}
	return h_mutex;
}

nt_mutex_handle nt_category_get_mutex(nt_category_handle h_category)
{
	nt_category_tp categoryp;
	nt_mutex_handle h_mutex;
	
	assert(h_category);
	assert(h_category->chk_sum == NT_2CH_CATEGORY_CHK_SUM);
	categoryp = (nt_category_tp)h_category;
	assert(categoryp->ref_count > 0);
	
	if(!categoryp->parent)
		return NULL;
	nt_category_add_ref(h_category);
	
	h_mutex = nt_2ch_model_get_mutex(&categoryp->parent->handle);
	if(!h_mutex){
		nt_category_release_ref(h_category);
		return NULL;
	}
	if(!nt_mutex_add_moniker(h_mutex, categoryp->name)){
		nt_category_release_ref(h_category);
		return NULL;
	}
	nt_category_release_ref(h_category);
	return h_mutex;
}

nt_mutex_handle nt_board_get_mutex(nt_board_handle h_board)
{
	nt_board_tp boardp;
	nt_mutex_handle h_mutex;
	
	assert(h_board);
	assert(h_board->chk_sum == NT_2CH_BOARD_CHK_SUM);
	boardp = (nt_board_tp)h_board;
	assert(boardp->ref_count > 0);
	
	if(!boardp->parent)
		return NULL;
	nt_board_add_ref(h_board);
	
	h_mutex = nt_category_get_mutex(&boardp->parent->handle);
	if(!h_mutex){
		nt_board_release_ref(h_board);
		return NULL;
	}
	if(!nt_mutex_add_moniker(h_mutex, boardp->name)){
		nt_board_release_ref(h_board);
		return NULL;
	}
	nt_board_release_ref(h_board);
	return h_mutex;
}

nt_mutex_handle nt_thread_get_mutex(nt_thread_handle h_thread)
{
	nt_thread_tp threadp;
	nt_mutex_handle h_mutex;
	
	assert(h_thread);
	assert(h_thread->chk_sum == NT_2CH_THREAD_CHK_SUM);
	threadp = (nt_thread_tp)h_thread;
	assert(threadp->ref_count > 0);
	
	if(!threadp->parent)
		return NULL;
	nt_thread_add_ref(h_thread);
	
	h_mutex = nt_board_get_mutex(&threadp->parent->handle);
	if(!h_mutex){
		nt_thread_release_ref(h_thread);
		return NULL;
	}
	if(!nt_mutex_add_moniker(h_mutex, threadp->file_name)){
		nt_thread_release_ref(h_thread);
		return NULL;
	}
	nt_thread_release_ref(h_thread);
	return h_mutex;
}



