// @Title ProcessSimulator
// @Description  模拟进程调用算法
// @Author  Shellmiao
// @Update  2021.10.21

package main

import (
	"fmt"
	"sort"
	"strconv"
)

// PrintProcessQueue 用于最终输出结果
func PrintProcessQueue(processQueue ProcessQueue) {
	processQueue.typeOfAl = 5
	sort.Sort(processQueue)
	fmt.Println("[-]进程ID\t进程名称\t到达时间\t服务时间\t开始时间\t结束时间\t周转时间\t带权周转时间")
	for i := 0; i < len(processQueue.ProcessQueue); i++ {
		fmt.Println("[-]" + strconv.Itoa(i) + "\t\t" + processQueue.ProcessQueue[i].name + "\t\t" + strconv.Itoa(processQueue.ProcessQueue[i].arriveTime) + "\t\t" + strconv.Itoa(processQueue.ProcessQueue[i].serveTime) + "\t\t" + strconv.Itoa(processQueue.ProcessQueue[i].beginTime) + "\t\t" + strconv.Itoa(processQueue.ProcessQueue[i].finishTime) + "\t\t" + strconv.Itoa(processQueue.ProcessQueue[i].roundTime) + "\t\t" + strconv.FormatFloat(processQueue.ProcessQueue[i].aveRoundTime, 'f', 2, 64))
	}
}

// CompleteProcess 完成一个进程
func CompleteProcess(process *Process, time *int) {
	process.beginTime = *time
	*time += process.serveTime
	process.isFinished = true
	process.finishTime = *time
	process.roundTime = process.finishTime - process.arriveTime
	process.aveRoundTime = float64(process.roundTime) / float64(process.serveTime)
}

// WaitTillProcessArrive 在当前时间没有进程工作时，等待直到有新的进程工作加入
func WaitTillProcessArrive(processQueue ProcessQueue, time int) int {
	for i := 0; i < len(processQueue.ProcessQueue); i++ {
		if !processQueue.ProcessQueue[i].isFinished {
			if processQueue.ProcessQueue[i].arriveTime > time {
				return processQueue.ProcessQueue[i].arriveTime
			} else {
				return time
			}
		}
	}
	return time
}

// FCFS FCFS算法
func FCFS(processQueue ProcessQueue) {
	time := 0
	for i := 0; i < len(processQueue.ProcessQueue); i++ {
		time = WaitTillProcessArrive(processQueue, time)
		if !processQueue.ProcessQueue[i].isFinished {
			CompleteProcess(processQueue.ProcessQueue[i], &time)
		}
	}
	PrintProcessQueue(processQueue)
}

// SJF_and_HRRF_and_HPF 同时实现SJF,HRRF,HPF算法，通过flag区分
func SJF_and_HRRF_and_HPF(processQueue ProcessQueue, flag int) {
	time := 0
	length := len(processQueue.ProcessQueue)
	for {
		var tempQueue ProcessQueue
		tempQueue.typeOfAl = flag
		tempQueue.time = time
		for i := 0; i < length; i++ {
			if processQueue.ProcessQueue[i].arriveTime > time {
				break
			}
			if !processQueue.ProcessQueue[i].isFinished {
				tempQueue.ProcessQueue = append(tempQueue.ProcessQueue, processQueue.ProcessQueue[i])
			}
		}
		if len(tempQueue.ProcessQueue) == 0 {
			temp := WaitTillProcessArrive(processQueue, time)
			if temp == time {
				break
			} else {
				time = temp
				tempQueue.time = time
				continue
			}
		}
		sort.Sort(tempQueue)
		CompleteProcess(tempQueue.ProcessQueue[0], &time)
		tempQueue.time = time
	}
	PrintProcessQueue(processQueue)
}

func main() {
	fmt.Println("[-]开始模拟调度算法...")
	var processQueue = initProcessQueue()
	processQueue.typeOfAl = 1
	sort.Sort(processQueue)
	fmt.Print("[-]请输入需要的调度算法(1[FCFS]、2[SJF]、3[HRRF]、4[HPF]): ")
	var choose int
	fmt.Scan(&choose)
	switch choose {
	case 1:
		FCFS(processQueue)
	case 2:
		SJF_and_HRRF_and_HPF(processQueue, 2)
	case 3:
		SJF_and_HRRF_and_HPF(processQueue, 3)
	case 4:
		for i := 0; i < len(processQueue.ProcessQueue); i++ {
			var temp int
			fmt.Print("[+]请输入第" + strconv.Itoa(i) + "个进程的信息(优先值): ")
			fmt.Scan(&temp)
			processQueue.ProcessQueue[i].priority = temp
		}
		SJF_and_HRRF_and_HPF(processQueue, 4)
	}
}
