#ifndef MTASK_H_
#define MTASK_H_

namespace system {
	/*
	 * tss
	 */
	struct Tss32 {
		/*
		 * 32ビット境界に合わせるため2バイトの空きスペースを作ってある
		 */
		word backlink;	word f1;
		dword esp0;
		word ss0;		word f2;
		dword esp1;
		word ss1;		word f3;
		dword esp2;
		word ss2;		word f4;
		dword cr3;
		dword eip;
		dword eflags;
		dword eax;
		dword ecx;
		dword edx;
		dword ebx;
		dword esp;
		dword ebp;
		dword esi;
		dword edi;
		word es;		word f5;
		word cs;		word f6;
		word ss;		word f7;
		word ds;		word f8;
		word fs;		word f9;
		word gs;		word f10;
		word ldtr;		word f11; // ローカルディスクリプタテーブルのセレクタ値
		word t; // 最下位ビットが1なら、タスク切り替え時にINT1のフォールト発生
		word iobase;
	};
	
	const int TASK_KERNEL = 0;
	const int TASK_IDLE = 1;
	const int TASK_KEYBOARD = 2;
	const int TASK_MOUSE = 3;
	const int TASK_TASKBAR = 4;
	
	// タスクスイッチ用タイマー
	extern Timer* g_task_timer;
	
	/*
	 * タスク
	 */
	class Task {
		// 定数
		static const int FLAG_FREE = 0;
		static const int FLAG_ALLOC = 1;
		static const int FLAG_ACTIVE = 2;
		int selector_, flags_;
		int level_, priority_;
		std::queue<Message> fifo_;
		Tss32 tss_;
		SegmentDescriptor ldt_[2];
		int ds_base_;
	public:
		explicit Task();
		
		void init();
		
		// 使用マークを付ける
		void use() { flags_ = FLAG_ALLOC; }
		
		// 未使用マークを付ける
		void release() { flags_ = FLAG_FREE; }
		
		// タスクが使用中かどうか
		bool used() const { return flags_ >= FLAG_ALLOC; }
		
		// 動作マークを付ける
		void run() { flags_ = FLAG_ACTIVE; }
		
		// 停止マークを付ける
		void stop() { flags_ = FLAG_ALLOC; }
		
		// 動作中かどうか
		bool running() { return flags_ == FLAG_ACTIVE; }
		
		// レベルを設定する
		void set_level(int level) { level_ = level; }
		
		// レベルを取得する
		int get_level() { return level_; }
		
		// 優先度を設定する
		void set_priority(int priority) { priority_ = priority; }
		
		// 優先度を取得する
		int get_priority() { return priority_; }
		
		// セレクタ値を設定する
		void set_selector(int sel) { selector_ = sel; }
		
		// セレクタ値を取得する
		int get_selector() { return selector_; }
		
		// fifoにデータを送る
		void send_message(Message& msg) { fifo_.push(msg); }
		
		// fifoバッファを取得
		std::queue<Message>* fifo() { return &fifo_; }
		
		// TSS用のセグメント設定
		void set_segmtss(int sel);
		
		// LDT用のセグメント設定
		void set_segmldt(int sel);
		
		void set_tss_ldtr(word ldtr) { tss_.ldtr = ldtr; }
		void set_tss_esp(dword esp) { tss_.esp = esp; }
		void set_tss_eip(dword eip) { tss_.eip = eip; }
		void set_tss_es(word es) { tss_.es = es; }
		void set_tss_cs(word cs) { tss_.cs = cs; }
		void set_tss_ss(word ss) { tss_.ss = ss; }
		void set_tss_ds(word ds) { tss_.ds = ds; }
		void set_tss_fs(word fs) { tss_.fs = fs; }
		void set_tss_gs(word gs) { tss_.gs = gs; }
	};
	
	namespace TaskDefinitions {
		const int MAX_TASKS_LV = 256;
		const int MAX_LEVELS = 8;
		const int MAX_TASKS = MAX_TASKS_LV * MAX_LEVELS;
		const int TASK_GDT0 = 3; // TSSをGDTの何番から割り当てるのか
	}
	
	class TaskLevel {
		static Task* current_task_;
		int running_;
		int current_;
		Task *tasks_[TaskDefinitions::MAX_TASKS_LV];
		
		Task* reset_current_task() { return current_task_ = tasks_[current_]; }
	public:
		explicit TaskLevel();
		
		// タスクを動作リストに加える
		void add(Task* task);
		
		// タスクを動作リストから削除する
		void remove(Task* task);
		
		// 動作中タスクの数を取得する
		int get_running() { return running_; }
		
		// current_を一つすすめる
		void nexttask();
		
		// タスクを切り替える
		void task_switch();
		
		// タスクを切り替える
		void task_switch2();
		
		Task* get_current_task() {
			return reset_current_task();
			//return current_task_;
		}
		
		Task* get_task(int index) { return tasks_[index]; }
	};
	
	/*
	 * タスクコントローラー
	 */
	class TaskController {
		Task* tasks0_;
		TaskLevel* level_;
		bool level_changed_;
		int current_level_;
		
		// タスクスイッチの補助関数
		void task_switchsub();
	public:
		explicit TaskController();
		~TaskController();
		
		Task* init();
		
		// タスクを１個生成
		Task* alloc(int level = 4, int priority = 2);
		
		// タスクを動作リストに加える
		void add(Task* task) { level_[task->get_level()].add(task); }
		
		// タスクを動作リストから削除する
		void remove(Task* task) { level_[task->get_level()].remove(task); }
		
		// タスクを走らせる
		void run(Task* task, int level = -1, int priority = -1);
		
		// タスクを停止（スリープ）させる
		void sleep(Task* task);
		
		// タスクスイッチ
		void task_switch();
		
		// タスクにメッセージを送る
		void send_message(int to, Message& msg);
		
		// タスクにメッセージを送る
		void send_message(Task* task, Message& msg);
		
		Task* get_current_task() {
			return level_[current_level_].get_current_task();
		}
		
		// タスクIDを取得する
		int get_taskid(const Task* task) const { return task - tasks0_; }
	};
	
}

#endif /*MTASK_H_*/
