/*
    OS Scheduler Simulator

** 連絡先: 琉球大学情報工学科 河野 真治  
** (E-Mail Address: kono@ie.u-ryukyu.ac.jp)
**
**    このソースのいかなる複写,改変,修正も許諾します。ただし、
**    その際には、誰が貢献したを示すこの部分を残すこと。
**    再配布や雑誌の付録などの問い合わせも必要ありません。
**    営利利用も上記に反しない範囲で許可します。
**    バイナリの配布の際にはversion messageを保存することを条件とします。
**    このプログラムについては特に何の保証もしない、悪しからず。
**
**    Everyone is permitted to do anything on this program 
**    including copying, modifying, improving,
**    as long as you don't try to pretend that you wrote it.
**    i.e., the above copyright notice has to appear in all copies.  
**    Binary distribution requires original version messages.
**    You don't have to ask before copying, redistribution or publishing.
**    THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.


  Simple Event Driven Simulator

 */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "queue.h"
#include "event.h"
#include "task.h"

static int by_period(QueuePtr q,QueuePtr r);

static char buf[BUFSIZ];

static EventPtr rate_monotonic(EventPtr task,QueuePtr *queue_ptr,int quantum);
static void simulate(EventPtr task,int limit);
static int get_quantum(EventPtr list);

static int limit = 400;

int
main()
{
    int time; char name[BUFSIZ]; int length; int priority;
    EventPtr task_list = NULL;
    QueuePtr q,queue;
    char *name1;
    char type;
    int period;

    init_queue(100);
    init_event(100);

    task_count = 0;
    while(fgets(buf,BUFSIZ,stdin)!=NULL) {
        if (buf[0]=='#') continue;
        if (buf[0]!='p') continue;
        sscanf(buf,"%c %d %s %d %d %d",
        &type,&time,name,&length,&priority,&period);
        if ((name1=malloc(strlen(name)))==0) {
            die("Can't allocate name\n");
        }
        strcpy(name1,name);
        q = new_queue(name1, length, priority);
        if (!q) {
            die("Can't allocate queue\n");
        }
    q->type = type;
    q->period = period;
    q->task_length = length;
    q->length = 0; /* not missed at first time */
        queue = append_queue(queue,q);
        task_count++;
    }
    queue = sort_queue(queue,by_period);
    task_list = new_event(0, rate_monotonic, &queue);
    if (!task_list) {
    die("Can't allocate task\n");
    }
    simulate(task_list,limit);
    printf("%d\tend:\n",task_clock);
    return 0;
}


static void
simulate(EventPtr task,int limit)
{
    EventPtr e;
    int quantum;

    while(task) {
    task=get_event(task,&e);
    task_clock = e->time;
    if (limit && task_clock>limit) {
        break;
    }
    quantum = get_quantum(task);
    task = e->event(task,e->param,quantum);
    free_event(e);
    }
}

int
get_quantum(EventPtr list)
{
    if (!list) {
        return 0;
    } else {
        return list->time - task_clock;
    }
}

static EventPtr
rate_monotonic(EventPtr task,QueuePtr *queue_ptr,int quantum)
{
    QueuePtr q;

    // task が優先度順に並んでいるとする
    // 再投入を先にチェックして、一番短いquantumを見つける

    for(q= *queue_ptr;q;q=q->next) {
    if (q->type!='p') continue;
    // もし、再投入時間ならば再投入する
    if (q->next_time==task_clock) {
        q->next_time=task_clock+q->period;
        task = insert_event1(task,
        new_event(q->next_time, rate_monotonic, queue_ptr));
        if (quantum==0 || quantum > q->period) quantum = q->period;
        if (q->length>0) {
        report_dead_line_miss(q);
        }
        q->length = q->task_length;
    }
    }
    for(q= *queue_ptr;q;q=q->next) {
    if (q->type!='p') continue;
    // 一番優先順位が高いものを実行する
    if (q->length) {
        quantum -= exec_task(q,quantum);
        if (quantum <= 0)
        return task;
    }
    }
    /* other task (may be non-periodic one ) */
    return task;
}

static int by_period(QueuePtr q,QueuePtr r)
{
    return q->period > r->period;
}


/* end */