#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>



//模拟进程转换

//模拟PCB
struct PCB {
    int name; // 进程名
    int priority ; //优先级
    char statu; //状态
    int run_time; //运行时间
    int arrive_time; //到达时间
};


//按照时间来排序
struct PCB * sort_PCB(struct PCB * a,const int * len) {
    for (int i = 0; i < *len; i++) {
        for (int j = i + 1; j < *len; j++) {
            //比较两个数谁先到达,数字越小越先到达,
            if (a[i].arrive_time > a[j].arrive_time) {
                struct PCB temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
                //如果进程到达时间一样就比较优先级的大小
            else if (a[i].arrive_time == a[j].arrive_time) {
                //优先级大的先进去
                if (a[i].priority < a[j].priority) {
                    struct PCB temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
                //如果到达时间和优先级一样则看剩余时间剩余运行时间少的先运行
                else if (a[i].priority == a[j].priority) {
                    if (a[i].run_time > a[j].run_time) {
                        struct PCB temp = a[i];
                        a[i] = a[j];
                        a[j] = temp;
                    }
                }
            }
            //printf("%d %d\n",i,a[i].name);
        }
    }
    return a;
}

//检测名字是否重复
struct PCB * check_name(int * i,struct PCB * a){
    if(*i>=1){
        //j小于i,也就是检测现在名字索引前的是否相同
        for (int j = 0 ;j < *i;++j) {
            if (a[j].name == a[*i].name) {
                printf("PCB name err: Name repetition ");
                exit(1);
            }
        }
    }
    return 0;
}


//创建PCB
struct PCB * create_PCB(int * len){
    struct PCB * a = (struct PCB *) malloc(*len * sizeof(struct  PCB)); //创建PCB动态列表
    //依照输入的程序个数来for循环
    for (int i = 0;i< *len;++i){
        printf("Please input in sequence name,priority,arrive_time,run_time:\n");
        scanf("%d %d %d %d",&(a[i].name),&(a[i].priority),&(a[i].arrive_time),&(a[i].run_time));
        //判断名字是否重复
        check_name(&i,a);
        //printf("%d %d %d\n",a[i].name,a[i].priority,a[i].arrive_time);
    }
    //排序,谁先到排前面
    return sort_PCB(a,len);
}

//struct PCB * move_PCB(int * i,struct PCB * a,int * len){
//    //将运行阻塞的进程移动到末尾
//    struct PCB temp = a[*i];
//    for (int x = *i+i ; x<*len; x++)
//    {
//        a[x - 1] = a[*i];
//    }
//    a[*len - 1] = temp;
//    return  0;
//}

//等待队列

struct PCB * wait_queue(int * i , int * len , struct PCB *a) {
    for (int j = *i+1 ; j <= *len; j++) {
        //判断j是等于len的长度如果不是则输入j的信息
        if(j != *len){
            if (a[j].run_time > 0) {
                printf("wait process is %d\n", a[j].name);
                printf("It priority is %d\n", a[j].priority);
                strcpy(&a[j].statu, "W");
                printf("It status is %c\n", a[j].statu);
                printf("It Remaining running time is %d\n", a[j].run_time);
                printf("----------------------------------------\n");
            }
        }
        //如果是,说明j已经运行到最后一个值了,就需要讲当前运行的值加入队列后面
        else if (j == *len ) {
            //判断i是不是最后一个值
            if (*i == *len - 1) {
                //循环执行,如果是最后一个值,那就按照顺序遍历列表,这样就相当于吧当前值加入到队列最后面了
                for (int x = 0; x < *i; x++) {
                    //如果运行完成了就不遍历
                    if (a[x].run_time > 0) {
                        printf("wait process is %d\n", a[x].name);
                        printf("It priority is %d\n", a[x].priority);
                        strcpy(&a[x].statu, "W");
                        printf("It status is %c\n", a[x].statu);
                        printf("It Remaining running time is %d\n", a[x].run_time);
                        printf("-----------------i-----------------------\n");
                    }
                }
            }
            else {
                for (int x = *i - 1; x <= *i; x++) {
                    if (a[x].run_time > 0) {
                        printf("wait process is %d\n", a[x].name);
                        printf("It priority is %d\n", a[x].priority);
                        strcpy(&a[x].statu, "W");
                        printf("It status is %c\n", a[x].statu);
                        printf("It Remaining running time is %d\n", a[x].run_time);
                        printf("----------------------------------------\n");
                    }
                }
            }
        }
    }
    return 0;
}


//运行
struct PCB * run_queue(int  * i,struct PCB * a,int * time){
    //直接输入当前队列顶部的值
    printf("running process is %d\n", a[*i].name);
    printf("It priority is %d\n", a[*i].priority);
    strcpy(&a[*i].statu, "R");
    printf("It status is %c\n", a[*i].statu);
    a[*i].run_time -= *time;
    //判断如果time时间小于0就直接为0
    if (a[*i].run_time < 0) a[*i].run_time = 0;
    printf("It Remaining running time is %d\n", a[*i].run_time);
    //没有剩余运行时间则程序直接结束
    if (a[*i].run_time == 0) {
        printf("-----------------over-------------------\n");
        printf("%d running time is over\n", a[*i].name);
        //将运行阻塞的进程移动到末尾(遗弃)
        //move_PCB(&i,a,&len);
    } else {
        printf("---------------add wait-----------------\n");
        //printf("process %d adds blocking queue\n", a[i].name);
        strcpy(&a[*i].statu, "W");
        printf("process statu is %c\n", a[*i].statu);
        //将运行阻塞的进程移动到末尾(遗弃)
        //move_PCB(&i,a,&len);
    }
    return NULL;
}


void run_program();

void check_continue(int * len,struct PCB * a){
    char x;
    //询问是否继续
    printf("all process is run over\n");
    printf("Do you want to continue?(y or n)");
    scanf("%c",&x);
    //输入n程序直接结束
    if (x == 'n') {
        exit(2);
    }
    //输入y则继续运行函数
    else if(x == 'y') {
        free(a);
        run_program();
    }
}


//判断队列run_time是否为0,如果有不为0的就返回false;
bool pan(struct  PCB * a,int * len) {
    for (int i = 0; i < *len; i++) {
        if (a[i].run_time != 0) {
            return false;
        }
    }
    return true;
}


//运行函数
struct PCB * run_process(struct PCB * a,int * len,int * time) {
    //定义一个为true就一直执行
    while (1) {
        //遍历阻塞队列中的值
        for (int i = 0; i < *len; i++) {
            //如果还有运行时间就遍历,
            if (a[i].run_time > 0) {
                //输出运行程序
                printf("----------------running----------------\n");
                run_queue(&i,a,time);
                //输出等待队列
                printf("----------------wait queue--------------\n");
                wait_queue(&i,len,a);
            }
            //判断如果队列内run_time都为0则执行,也就是判断队列内程序是否都执行完毕
            else if (pan(a,len)) {
                check_continue(len,a);
            }
        }
    }
}


//输入程序个数
int input_num(){
    int len; //进程数量
    printf("input process number:");
    scanf("%d", &len);
    if (len == 0) printf("program over\n");
    return len;
}


void run_program(){
    int time = 10; //时间片
    int len; //进程数量
    len = input_num();
    //阻塞队列
    struct PCB * r = (struct PCB *) malloc(len * sizeof(struct PCB));
    free(r);
    //struct PCB *w = (struct PCB *) malloc(len * sizeof(struct PCB));
    //创建运行队列
    r = create_PCB(&len);
    //printf("%d",r[1].name);
    //运行程序
    run_process(r, &len, &time);
    //printf("%d",b[0].name);
}


int main(void) {
    run_program();
}