private static int Otimo(MemoryProcess process)
        {
            int index = 0, aux = 0, changesAmount = 0, pageHigherTime = 0, indexPageHigherTime = 0;

            //Página nova
            for (int i = 0; i < process.Pages.Count; ++i)
            {
                int currentPage = process.Pages[i];
                if (!process.Frames.Contains(currentPage) && (index < process.AmountOfFrames))
                {
                    process.Frames.Insert(index, currentPage);
                    ++index;
                    ++aux;
                    ++changesAmount;
                }
                else if (process.Frames.Contains(currentPage))  //Página repetida
                {
                    ++aux;
                }
                else   //Moldura preenchida
                {
                    pageHigherTime      = GetHigherTime(process, aux);
                    indexPageHigherTime = process.Frames.IndexOf(pageHigherTime);
                    process.Frames.RemoveAt(indexPageHigherTime);
                    process.Frames.Insert(indexPageHigherTime, currentPage);
                    ++aux;
                    ++changesAmount;
                }
            }
            return(changesAmount);
        }
        private static int NFU(MemoryProcess process)
        {
            int index = 0, changesAmount = 0, indexInFrame = 0, lessUsed = 0;

            int[] pagesAccess = new int[process.AmountOfPages];

            for (int i = 0; i < process.Pages.Count; ++i)
            {
                int currentPage = process.Pages[i];
                //Página nova
                if (!process.Frames.Contains(currentPage) && (index < process.AmountOfFrames))
                {
                    process.Frames.Insert(index, currentPage);
                    ++pagesAccess[currentPage - 1];
                    ++index;
                    ++changesAmount;
                }
                else if (process.Frames.Contains(currentPage))  //Página repetida
                {
                    ++pagesAccess[currentPage - 1];
                }
                else  //Verificar trocas, moldura preenchida
                {
                    lessUsed     = GetNFU(process.Frames, pagesAccess);
                    indexInFrame = process.Frames.IndexOf(lessUsed);
                    process.Frames.RemoveAt(indexInFrame);
                    process.Frames.Insert(indexInFrame, currentPage);
                    pagesAccess[lessUsed - 1] = 0;
                    ++pagesAccess[currentPage - 1];
                    ++changesAmount;
                }
            }
            return(changesAmount);
        }
        private static int MRU(MemoryProcess process)
        {
            //Para molduras que ainda não tem preenchimento
            int index = 0, aux = 0;

            //Moldura cheia
            int high = 0;

            int changesAmount = 0;

            //Tempo ocioso para cada posição
            int[] pos = new int[process.AmountOfFrames];

            for (int i = 0; i < process.Pages.Count; ++i)
            {
                int currentPage = process.Pages[i];

                //Página nova
                if (!process.Frames.Contains(currentPage) && (aux < process.AmountOfFrames))
                {
                    process.Frames.Insert(index, currentPage);
                    ++aux;
                    IncreaseTime(aux, pos);
                    pos[index] = 0;
                    ++index;
                    ++changesAmount;
                }
                else if (process.Frames.Contains(currentPage))  //Página repetida
                {
                    IncreaseTime(aux, pos);
                    pos[process.Frames.IndexOf(currentPage)] = 0;
                }
                else
                {
                    high = GetIndexMRU(pos);
                    process.Frames.RemoveAt(high);
                    process.Frames.Insert(high, currentPage);
                    IncreaseTime(aux, pos);
                    pos[high] = 0;
                    ++index;
                    ++changesAmount;
                }
            }
            return(changesAmount);
        }
        //Função auxiliar para Ótimo

        //Encontra página que vai levar mais tempo
        private static int GetHigherTime(MemoryProcess process, int start)
        {
            int time = 0;
            Dictionary <int, int> dict = new Dictionary <int, int>();

            for (int i = 0; i < process.Frames.Count; ++i)
            {
                int currentFrame = process.Frames[i];
                for (int j = 0; j < process.Pages.Count; ++j)
                {
                    ++time;
                    if (currentFrame == process.Pages[i])
                    {
                        break;
                    }
                }
                dict.Add(currentFrame, time);
                time = 0;
            }
            return(dict.Aggregate((x, y) => x.Value > y.Value ? x : y).Key);
        }
        //Algoritmos
        private static int FIFO(MemoryProcess process)
        {
            int auxIn = 0, changesAmount = 0, index = 0;

            for (int i = 0; i < process.Pages.Count; ++i)
            {
                int currentPage = process.Pages[i];

                //Se não conter a página atual na moldura, adiciona e incrementa indice
                if (process.Frames.Count < process.AmountOfFrames && !process.Frames.Contains(currentPage))
                {
                    process.Frames.Insert(index, currentPage);
                    ++index;
                    ++changesAmount;
                }
                else if (process.Frames.Contains(currentPage))  //Se conter a página na moldura atual, apenas continua
                {
                    continue;
                }
                else
                {
                    //Aplicando a lógica do primeiro que entrar, sair
                    process.Frames.RemoveAt(auxIn);
                    //Adiciona página atual na posição antiga do primeiro que entrou para ser o novo parametro
                    process.Frames.Insert(auxIn, currentPage);
                    ++auxIn;
                    index = 0;
                    ++changesAmount;
                }

                //Caso o indice do elemento para remover seja a capacidade da lista, volta pro começo
                if (auxIn == process.AmountOfFrames)
                {
                    auxIn = 0;
                }
            }

            return(changesAmount);
        }
        //Função que abre o arquivo, lê linha a linha e cria os processos conforme definido, retornando a lista de processos
        public static List <MemoryProcess> GetAndListProcesses(string filename)
        {
            List <MemoryProcess> list = new List <MemoryProcess>();

            try {
                StreamReader reader   = new StreamReader(filename);
                string[]     allLines = reader.ReadToEnd().Split('\n');
                if (allLines != null)
                {
                    foreach (string line in allLines)
                    {
                        //Número de molduras de página na memória|número de páginas do processo|sequência em que as páginas são acessadas
                        string[]      info = line.Split('|');
                        MemoryProcess mp   = new MemoryProcess(Convert.ToInt32(info[0]), Convert.ToInt32(info[1]), info[2].Replace("\r", ""));
                        list.Add(mp);
                    }
                }
                reader.Close();
            }
            catch (IOException ex) {
                Console.WriteLine(ex.Message);
            }
            return(list);
        }
        public static void Main(string[] args)
        {
            List <MemoryProcess> processes = FileManipulation.GetAndListProcesses(@"C:\dev\furg\memorypagination\processes.txt");

            PrintProcesses(processes);

            int[]  changesAmount = new int[4];
            int    min           = 0;
            string betterAlg     = string.Empty;
            bool   simpleOutput  = true;

            for (int i = 0; i < processes.Count; ++i)
            {
                MemoryProcess currentProcess = processes[i];

                changesAmount[0] = FIFO(currentProcess);
                currentProcess.Frames.Clear();
                changesAmount[1] = MRU(currentProcess);
                currentProcess.Frames.Clear();
                changesAmount[2] = NFU(currentProcess);
                currentProcess.Frames.Clear();
                changesAmount[3] = Otimo(currentProcess);
                currentProcess.Frames.Clear();

                min = changesAmount.Min();

                for (int j = 0; j < changesAmount.Length; ++j)
                {
                    if (changesAmount[j] == min)
                    {
                        switch (j)
                        {
                        case 0:
                            betterAlg += "FIFO,";
                            break;

                        case 1:
                            betterAlg += "MRU,";
                            break;

                        case 2:
                            betterAlg += "NUF,";
                            break;

                        case 3:
                            betterAlg += "Otimo,";
                            break;
                        }
                    }
                }

                betterAlg = betterAlg.Substring(0, betterAlg.Length - 1); //Remove última virgula
                if (simpleOutput)
                {
                    string aux = betterAlg;
                    if (betterAlg.Equals("FIFO,MRU,NUF,Otimo"))
                    {
                        aux = "Empate";
                    }
                    Console.WriteLine(string.Format("{0}|{1}|{2}|{3}|{4}", changesAmount[0], changesAmount[1], changesAmount[2], changesAmount[3], aux));
                }
                else
                {
                    Console.WriteLine(string.Format("Avaliação dos algoritmos (por trocas):\n--> FIFO [{0}]\n--> MRU [{1}]\n--> NFU [{2}]\n--> Ótimo [{3}]\n--> Melhor(es): [{4}]", changesAmount[0], changesAmount[1], changesAmount[2], changesAmount[3], betterAlg));
                }
                betterAlg = string.Empty;
            }

            Console.WriteLine("Fim");
        }