/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program 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.

**********************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include "lock_level.h"
#include "machine/msequence.h"
#include "machine/gb_windows.h"
#include "task.h"
#include "pri_level.h"
#include "utils.h"


int mseq_flag=0;

SEM mseq_que_lock;
HANDLE user_interface_thread_finished_event;

MS_INFO * ms_info_head[PRI_MAX];
MS_INFO * ms_info_tail[PRI_MAX];

int user_interface_task_id;

void (*ms_put_call_back)(int (*func)(), void * arg, char str[]) = 0;

void init_app_window();

void
init_msequence()
{
extern int get_tid();
int i;

	/* The thread who call init_msequence() is main thread */
	user_interface_task_id = get_tid();
	mseq_que_lock = new_lock(LL_MSEQUENCE);
	for ( i = 0; i < PRI_MAX ; i ++ ) {
		ms_info_head[i] = 0;
		ms_info_tail[i] = 0;
	}
	mseq_flag = 1;
}

int
ms_loop_1()
{
MS_INFO * ms;
int pri;
int cnt = 0;
static tid = -1;

	if ( tid == -1 )
		tid = get_tid();
	if ( tid != get_tid() )
		er_panic("ms_loop_1");

	for ( ; ; ) {
		Sleep(0);
		
		lock_task(mseq_que_lock);
		for ( pri = PRI_MAX-1 ; pri >= 0 ; pri -- )
			if ( ms_info_head[pri] )
				break;
		if ( pri < 0 ) {
			unlock_task(mseq_que_lock, "ms_loop");
			break;
		}
		ms = ms_info_head[pri];
		ms_info_head[pri] = ms->next;
		if ( ms_info_head[pri] == 0 )
			ms_info_tail[pri] = 0;
		unlock_task(mseq_que_lock, "ms_loop");
/*
printf("do1 %s\n",ms->str);
*/
		ms->result = (*ms->func)(ms->arg);

		wakeup_task((unsigned int)ms);
		cnt++;

/*
printf("do1 %s end\n",ms->str);
*/
	}
	return cnt;
}

void
ms_loop()
{
	for ( ; ; )
		ms_loop_1();
}


static void
ms_put_func(MS_INFO * ms)
{
int pri;
extern int get_pri(int tid);

	pri = get_pri(0);
	ms->next = 0;
	if ( ms_info_tail[pri] == 0 ) {
		ms_info_tail[pri] = ms_info_head[pri] = ms;
	}
	else {
		ms_info_tail[pri]->next = ms;
		ms_info_tail[pri] = ms;
	}
}


int
ms_do(int (*func)(void *param), void * arg, char str[])
{
MS_INFO ms;

	if ( mseq_flag == 0 ) {
		printf("????\n");
		exit(1);
	}
	if ( user_interface_task_id == get_tid() )
		return  (*func)(arg);
	ms.func = func;
	ms.arg = arg;
	strcpy(ms.str,str);

	lock_task(mseq_que_lock);
	ms_put_func(&ms);
	if ( ms_put_call_back )
		(*ms_put_call_back)(func,arg,str);

	PostThreadMessage(get_userinterface_tid(), WM_MSEQUENCE, 0, 0);
	sleep_task((unsigned int)&ms,mseq_que_lock);

	return ms.result;
}


int get_userinterface_tid()
{
	return user_interface_task_id;
}


