#include "../bootpack.h"

Timer::Timer()
	: next_timer_(0), timeout_(0), flags_(FLAG_FREE), auto_close_(false),
	task_(0), fifo_data_(0)
{
}

void Timer::set_task(Task* task, int data) {
	task_ = task;
	fifo_data_ = data;
}

void Timer::send_message() {
	g_taskctl->send_message(
		task_, Message::create(MSG::TYPE::TIMER, fifo_data_)
		);
}



TimerController* g_timerctl;

TimerController::TimerController()
	: count_(0),
	timers0_(new Timer[MAX_TIMERS]),
	timer_top_(0)
{
	int i;
	for (i = 0; i < MAX_TIMERS; i++) {
		timers0_[i].release();
	}
	Timer* last_timer = alloc();
	last_timer->set_time(0xffffffff);
	timer_top_ = last_timer;
	next_timeout_ = 0xffffffff;
}

TimerController::~TimerController() {
	delete[] timers0_;
}

void TimerController::set_timer_top(Timer* tim) {
	timer_top_ = tim;
	next_timeout_ = tim->get_time();
}

Timer* TimerController::alloc() {
	Timer* tim = 0;
	for (int i = 0; i < MAX_TIMERS; i++) {
		if (timers0_[i].used() == false) {
			tim = (timers0_ + i);
			tim->use();
			tim->disable_autoclose();
			break;
		}
	}
	return tim;
}

void TimerController::free(Timer* tim) {
	if (tim != NULL) {
		tim->release();
	}
}

void TimerController::set_time(Timer* tim, dword timeout) {
	if (tim == NULL) {
		return;
	}
	Timer *p, *f; // previous and following
	tim->set_time(timeout + count_);
	int ef = eflags;
	bool end = false;
	io_cli();
	f = timer_top_;
	if (tim->get_time() <= f->get_time()) {
		// 先頭に入れる
		timer_top_ = tim;
		tim->set_nexttimer(f);
		next_timeout_ = tim->get_time();
		end = true;
	}
	
	// 入れる場所を探す
	while (!end) {
		p = f;
		f = f->get_nexttimer();
		// p < f という状態
		
		if (tim->get_time() <= f->get_time()) {
			// p < tim < f という状態
			p->set_nexttimer(tim);
			tim->set_nexttimer(f);
			end = true;
		}
	}
	eflags = ef;
}

void system::timer_settime(Timer* timer, dword timeout) {
	g_timerctl->set_time(timer, timeout);
}
