private Process TryLoadProcessFromQueue()
        {
            if (ProcessesQueue.Count > 0)
            {
                if (Algorithm == SchedulerAlgorithm.FCFS)
                {
                    var processFromQueue = ProcessesQueue[0];


                    //Process can be loaded from queue
                    if (processFromQueue.ArrivalTime <= CurrentTime && processFromQueue.LastEnterTime == -1 ||
                        processFromQueue.LastExitTime + processFromQueue.IOTime <= CurrentTime)
                    {
                        ProcessesQueue.RemoveAt(0);
                        processFromQueue.Status        = ProcessStatus.OnCpu;
                        processFromQueue.LastEnterTime = CurrentTime;


                        return(processFromQueue);
                    }
                }
                else if (Algorithm == SchedulerAlgorithm.SJF)
                {
                    int     shortestJobAvailableDuration = int.MaxValue;
                    int     it = 0;
                    int     processFromQueuePosition = -1;
                    Process processFromQueue         = null;

                    for (; it < ProcessesQueue.Count; it++)
                    {
                        Process p = ProcessesQueue[it];
                        if (((p.ArrivalTime <= CurrentTime && p.LastEnterTime == -1) || (p.LastExitTime + p.IOTime <= CurrentTime && p.LastExitTime != -1)) &&
                            (p.BurstTime < p.RemainingDuration ? p.BurstTime : p.RemainingDuration) < shortestJobAvailableDuration)
                        {
                            processFromQueue             = CloneObject.CloneJson(p);
                            processFromQueuePosition     = it;
                            shortestJobAvailableDuration = p.BurstTime < p.RemainingDuration ? p.BurstTime : p.RemainingDuration;
                        }
                    }

                    if (processFromQueue != null)
                    {
                        ProcessesQueue.RemoveAt(processFromQueuePosition);
                        processFromQueue.Status        = ProcessStatus.OnCpu;
                        processFromQueue.LastEnterTime = CurrentTime;



                        return(processFromQueue);
                    }
                }
            }
            return(null);
        }
        private void buttonLoadFromFile_Click(object sender, EventArgs e)
        {
            string line;

            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter      = "Text files | *.txt";
            dialog.Multiselect = false;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                String path = dialog.FileName;
                using (StreamReader reader = new StreamReader(new FileStream(path, FileMode.Open), new UTF8Encoding()))
                {
                    while ((line = reader.ReadLine()) != null)
                    {
                        string[] bits = line.Split(' ');

                        var priorityString = "0";
                        int duration       = Int32.Parse(bits[1]);
                        int arrivalTime    = Int32.Parse(bits[0]);
                        int priority       = Int32.Parse(priorityString);
                        int burstTime      = Int32.Parse(bits[2]);
                        int ioTime         = Int32.Parse(bits[3]);

                        if (ioTime == 0)
                        {
                            burstTime = duration;
                            bits[2]   = bits[1];
                        }

                        Process newProcess = new Process(Global.Scheduler.ProcessesList.Count + 1, duration, arrivalTime, priority, burstTime, ioTime);
                        Global.Scheduler.ProcessesList.Add(newProcess);
                        Global.ProcessesInList.Add(CloneObject.CloneJson(newProcess));

                        Input.AddProcessToTable(dataGridViewProcessesList, newProcess.Id, bits[1], bits[0], priorityString, bits[2], bits[3]);
                    }

                    reader.Close();
                }
            }
        }
        //Add new process inside our table (list) and Scheduler memory
        private void buttonInput_Click(object sender, EventArgs e)
        {
            var durationString    = textBoxDuration.Text;
            var arrivalTimeString = textBoxArrivalTime.Text;
            var priorityString    = "0";
            //var priorityString = textBoxPriority.Text;
            var burstTimeString = textBoxBurstTime.Text;
            var ioTimeString    = textBoxIOTime.Text;

            string inputErrors = Input.CheckInputErrors(durationString, arrivalTimeString, priorityString, burstTimeString, ioTimeString);

            if (!String.IsNullOrEmpty(inputErrors))
            {
                MessageBox.Show(inputErrors);
            }
            else
            {
                int duration    = Int32.Parse(durationString);
                int arrivalTime = Int32.Parse(arrivalTimeString);
                int priority    = Int32.Parse(priorityString);
                int burstTime   = Int32.Parse(burstTimeString);
                int ioTime      = Int32.Parse(ioTimeString);

                if (ioTime == 0)
                {
                    burstTime       = duration;
                    burstTimeString = durationString;
                }

                Process newProcess = new Process(Global.Scheduler.ProcessesList.Count + 1, duration, arrivalTime, priority, burstTime, ioTime);
                Global.Scheduler.ProcessesList.Add(newProcess);
                Global.ProcessesInList.Add(CloneObject.CloneJson(newProcess));

                Input.AddProcessToTable(dataGridViewProcessesList, newProcess.Id, durationString, arrivalTimeString, priorityString, burstTimeString, ioTimeString);
            }
        }
        //SJF = Shortest Job First
        public void solveSJF()
        {
            CurrentTime = 0;
            Status      = SchedulerStatus.On;

            ProcessesQueue = ProcessesList;
            //Queue Starts with ascending order of processes by Arrival Time.
            ProcessesQueue = ProcessesQueue.OrderBy(c => c.ArrivalTime).ThenBy(c => c.BurstTime).ToList();

            //Load first Process
            while (ProcessesQueue[0].ArrivalTime > CurrentTime)
            {
                KeyTime keyTime = new KeyTime();
                keyTime.CpuOnLoad       = false;
                keyTime.Process         = null;
                keyTime.OngoingProcess  = null;
                keyTime.OutgoingProcess = null;
                keyTime.Timestamp       = CurrentTime;
                ++CurrentTime;
                KeyTimes.Add(keyTime);
            }

            //First process comes at moment zero (special scenario)
            if (CurrentTime == 0 && ProcessesQueue[0].ArrivalTime == 0)
            {
                Process firstProcess = ProcessesQueue[0];
                ProcessesQueue.RemoveAt(0); //Remove selected process from the queue
                KeyTime keyTime = new KeyTime();
                keyTime.CpuOnLoad       = true;
                keyTime.OutgoingProcess = null;
                keyTime.Timestamp       = CurrentTime;

                firstProcess.LastEnterTime = CurrentTime;
                firstProcess.Status        = ProcessStatus.OnCpu;
                keyTime.OngoingProcess     = firstProcess;
                KeyTimes.Add(keyTime);
                ++CurrentTime;
            }

            //Continue processing
            KeyTime currentKeyTime = new KeyTime();
            KeyTime lastKeyTime    = KeyTimes[CurrentTime - 1];

            while (ProcessesQueue.Count > 0 || lastKeyTime.OngoingProcess != null || currentKeyTime.OngoingProcess != null)
            {
                currentKeyTime           = new KeyTime();
                lastKeyTime              = KeyTimes[CurrentTime - 1];
                currentKeyTime.Timestamp = CurrentTime;

                //Last process action on current moment
                var lastOngoingProcessResult = CheckForProcessContinuity(CloneObject.CloneJson(lastKeyTime.OngoingProcess));

                //Process ongoing on the CPU. No replacements actions needed
                if (lastOngoingProcessResult != null && lastOngoingProcessResult.Item2 != null)
                {
                    currentKeyTime.OutgoingProcess = null;
                    currentKeyTime.OngoingProcess  = lastOngoingProcessResult.Item2;
                    currentKeyTime.CpuOnLoad       = true;
                    if (currentKeyTime.OngoingProcess.ResponseTime == 0)
                    {
                        currentKeyTime.OngoingProcess.ResponseTime = CurrentTime;
                    }
                    ++AverageCPUUtilisation;
                }
                else
                {
                    if (lastOngoingProcessResult != null)
                    {
                        currentKeyTime.OutgoingProcess = lastOngoingProcessResult.Item1;
                    }

                    currentKeyTime.OngoingProcess = TryLoadProcessFromQueue();
                    if (currentKeyTime.OngoingProcess != null)
                    {
                        ++AverageCPUUtilisation;
                        if (currentKeyTime.OngoingProcess.ResponseTime == 0)
                        {
                            currentKeyTime.OngoingProcess.ResponseTime = CurrentTime;
                        }
                    }
                }

                KeyTimes.Add(currentKeyTime);
                AverageWaitingProcesses += ProcessesQueue.Count;
                ++CurrentTime;
            }

            Status = SchedulerStatus.Off;
        }
        private void buttonStartSimulation_Click(object sender, EventArgs e)
        {
            if (Global.Scheduler.ProcessesList.Count == 0)
            {
                MessageBox.Show("Insert at least one process before starting the simulation.");
            }
            else
            {
                if (radioButtonFCFS.Checked)
                {
                    Global.Scheduler = new Scheduler();
                    if (Global.ProcessesInList.Count > 0)
                    {
                        Global.Scheduler.ProcessesList = CloneObject.CloneJson(Global.ProcessesInList);
                    }
                    Global.Scheduler.Algorithm = SchedulerAlgorithm.FCFS;
                    Global.Scheduler.solveFCFS();
                    Global.Scheduler.ComputeData();

                    buttonGanttChart.Visible = true;
                }
                else if (radioButtonSJF.Checked)
                {
                    Global.Scheduler = new Scheduler();
                    if (Global.ProcessesInList.Count > 0)
                    {
                        Global.Scheduler.ProcessesList = CloneObject.CloneJson(Global.ProcessesInList);
                    }
                    Global.Scheduler.Algorithm = SchedulerAlgorithm.SJF;
                    Global.Scheduler.solveSJF();
                    Global.Scheduler.ComputeData();

                    buttonGanttChart.Visible = true;
                }
                else if (radioButtonBoth.Checked)
                {
                    //FCFS
                    Global.Scheduler = new Scheduler();
                    if (Global.ProcessesInList.Count > 0)
                    {
                        Global.Scheduler.ProcessesList = CloneObject.CloneJson(Global.ProcessesInList);
                    }
                    Global.Scheduler.Algorithm = SchedulerAlgorithm.FCFS;
                    Global.Scheduler.solveFCFS();
                    Global.Scheduler.ComputeData();

                    cpuChart.Series["Average Response Time"].Points.AddY(Global.Scheduler.AverageResponseTime);
                    cpuChart.Series["Average Waiting Time"].Points.AddY(Global.Scheduler.AverageWaitingTime);
                    cpuChart.Series["Average Turnaround Time"].Points.AddY(Global.Scheduler.AverageTurnaroundTime);
                    cpuChart.Series["Average CPU Utilisation"].Points.AddY(Global.Scheduler.AverageCPUUtilisation);
                    cpuChart.Series["Average No of Waiting Processes"].Points.AddY(Global.Scheduler.AverageWaitingProcesses);

                    //SJF
                    Global.Scheduler = new Scheduler();
                    if (Global.ProcessesInList.Count > 0)
                    {
                        Global.Scheduler.ProcessesList = CloneObject.CloneJson(Global.ProcessesInList);
                    }
                    Global.Scheduler.Algorithm = SchedulerAlgorithm.SJF;
                    Global.Scheduler.solveSJF();
                    Global.Scheduler.ComputeData();

                    buttonGanttChart.Visible = false;
                }

                cpuChart.Series["Average Response Time"].Points.AddY(Global.Scheduler.AverageResponseTime);
                cpuChart.Series["Average Waiting Time"].Points.AddY(Global.Scheduler.AverageWaitingTime);
                cpuChart.Series["Average Turnaround Time"].Points.AddY(Global.Scheduler.AverageTurnaroundTime);
                cpuChart.Series["Average CPU Utilisation"].Points.AddY(Global.Scheduler.AverageCPUUtilisation);
                cpuChart.Series["Average No of Waiting Processes"].Points.AddY(Global.Scheduler.AverageWaitingProcesses);
            }
        }