#include <shinobi.h>
#include <Ninja.h>

#include "njuTask.h"

typedef struct {
	NJS_TASK	*task_top;
	NJS_TASK	*task_bottom;
} NJS_TASK_PRI;

static	NJS_TASK_PRI	*task_pri;
static	Int				task_pri_cnt;

Int		_nj_task_cnt_;

/****************************************************************/
/*  関数名：ｎｊｕＩｎｉｔＴａｓｋ								*/
/*  機  能：タスク処理の初期化		                            */
/*  入  力：Int	n:タスクプライオリティ数                        */
/*  出  力：なし                                                */
/*  戻り値：なし                                                */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
void njuInitTask( Int n )
{
	Int	i;

	task_pri = (NJS_TASK_PRI*)syMalloc( sizeof(NJS_TASK_PRI)*n );
	if( task_pri == NULL ) return;

	for( i=0; i<n; i++ ) {
		(task_pri+i)->task_top = NULL;
		(task_pri+i)->task_bottom = NULL;
	}
	task_pri_cnt = n;

	_nj_task_cnt_ = 0;
}

/****************************************************************/
/*  関数名：ｎｊｕＣｒｅａｔｅＴａｓｋ							*/
/*  機  能：タスクの生成			                            */
/*  入  力：func	:タスク関数                                 */
/*			name	:タスクの名前                               */
/*			pri		:タスクの優先度                             */
/*			size	:タスクのバッファサイズ                     */
/*			buf		:初期化バッファ                             */
/*			wktask	:タスク通信用ポインタ                       */
/*  出  力：なし                                                */
/*  戻り値：タスクポインタ                                      */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
NJS_TASK *njuCreateTask( void (*func)( NJS_TASK * ), Int name, Int pri, Int size, void *buf, NJS_TASK *wktask )
{
	NJS_TASK	*task;
	NJS_TASK	*task_top;
	NJS_TASK	*task_bottom;
	void		*work;

	if( pri >= task_pri_cnt ) return NULL;

	task = (NJS_TASK*)syMalloc( sizeof(NJS_TASK) );
	if( task == NULL ) return NULL;

	if( size != 0 ) {
		work = syMalloc( size );
		if( work == NULL ) {
			syFree( task );
			return NULL;
		}
	}
	else {
		work = NULL;
	}
	
	task_top = (task_pri+pri)->task_top;
	task_bottom = (task_pri+pri)->task_bottom;

	task->status = 0;
	task->func = func;
	task->buf = work;
	task->task = wktask;
	task->pri = pri;
	task->name = name;

	if( task_top == NULL ) {		/* 最初のタスク	*/
		task_top = task;
		task->next = NULL;
		task->prev = NULL;
		task_bottom = task;
	}
	else {							/* 最後に追加する	*/
		task->next = NULL;
		task->prev = task_bottom;
		task_bottom->next = task;
		task_bottom = task;
	}

	(task_pri+pri)->task_top = task_top;
	(task_pri+pri)->task_bottom = task_bottom;
	
	if( (buf != NULL) && (work != NULL) ) {
		syMemCopy( work, buf, size );
	}
	
	(*func)( task );
	
	_nj_task_cnt_ ++;

	return task;
}

/****************************************************************/
/*  関数名：													*/
/*  機  能：						                            */
/*  入  力：                                                    */
/*  出  力：なし                                                */
/*  戻り値：なし                                                */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
void njuDeleteTask( NJS_TASK *task )
{
	NJS_TASK	*task_top;
	NJS_TASK	*task_bottom;
	Int			pri;

	pri = task->pri;
	task_top = (task_pri+pri)->task_top;
	task_bottom = (task_pri+pri)->task_bottom;

	if( task->buf != NULL ) {
		syFree( task->buf );
	}
	
	if( task_top == task_bottom ) {		/* 最後の１つ	*/
		task_top = NULL;
		task_bottom = NULL;
	}
	else if( task == task_top ) {		/* トップのタスクが削除された	*/
		task_top = task->next;
		task_top->prev = NULL;
	}
	else if( task == task_bottom ) {	/* ボトムのタスクが削除された	*/
		task_bottom = task->prev;
		task_bottom->next = NULL;
	}
	else {								/* 途中のタスクが削除された		*/
		task->prev->next = task->next;
		task->next->prev = task->prev;
	}
	
	(task_pri+pri)->task_top = task_top;
	(task_pri+pri)->task_bottom = task_bottom;

	syFree( task );

	_nj_task_cnt_ --;
}

/****************************************************************/
/*  関数名：													*/
/*  機  能：						                            */
/*  入  力：なし                                                */
/*  出  力：なし                                                */
/*  戻り値：なし                                                */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
void njuExecTask()
{
	Int		i;
	NJS_TASK	*task,*next;
	
	for( i=0; i<task_pri_cnt; i++ ) {
		task = 	(task_pri+i)->task_top;
		while( task != NULL ) {
			next = task->next;			/* 関数内でタスクが消去されるかもしれないので */
			(*task->func)(task);
			task = next;
		}
	}
}

/****************************************************************/
/*  関数名：													*/
/*  機  能：						                            */
/*  入  力：なし                                                */
/*  出  力：なし                                                */
/*  戻り値：なし                                                */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
void njuExitTask()
{
	Int		i;
	NJS_TASK	*task,*next;
	
	for( i=0; i<task_pri_cnt; i++ ) {
		task = 	(task_pri+i)->task_top;
		while( task != NULL ) {
			next = task->next;
			njuDeleteTask(task);
			task = next;
		}
	}
	syFree( task_pri );
}

static	NJS_TASK	*task_search_p;
static	Int			task_search_name;

/****************************************************************/
/*  関数名：													*/
/*  機  能：						                            */
/*  入  力：                                                    */
/*  出  力：なし                                                */
/*  戻り値：                                                    */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
NJS_TASK *njuSearchTask( Int name, Int pri )
{
	NJS_TASK	*task;

	task = 	(task_pri+pri)->task_top;

	task_search_p = task;
	task_search_name = name;

	while( task != NULL ) {
		if( task->name == name ) {
			task_search_p = task->next;
			break;
		}
		task = task->next;
	}

	return task;
}

/****************************************************************/
/*  関数名：													*/
/*  機  能：						                            */
/*  入  力：なし                                                */
/*  出  力：なし                                                */
/*  戻り値：                                                    */
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
NJS_TASK *njuSearchTaskNext( void )
{
	NJS_TASK	*task;
	Int			name;

	task = 	task_search_p;
	name = task_search_name;

	while( task != NULL ) {
		if( task->name == name ) {
			task_search_p = task->next;
			break;
		}
		task = task->next;
	}

	return task;
}
