/// <summary>
 /// Default constructor
 /// </summary>
 public VM_PageReplacment()
 {
     InputString   = string.Empty;
     FramesCount   = 0;
     AlgorithmType = VMAlgorithmType.FIFO;
 }
 /// <summary>
 /// Parameterized constructor with input string and frames count to work-on
 /// </summary>
 /// <param name="inputString">The input string</param>
 /// <param name="framesCount">The frames count</param>
 public VM_PageReplacment(string inputString, int framesCount, VMAlgorithmType type)
 {
     InputString   = inputString;
     FramesCount   = framesCount;
     AlgorithmType = type;
 }
        private int ObjectToRemoveIndex(List <OSASVMObject> objects, OSASVMObject vmObj, int current, string input, VMAlgorithmType type)
        {
            int ObjToRemoveIndex = -1;

            if (type == VMAlgorithmType.FIFO)
            {
                var lastFObjects = objects.Where(a => a.Index < current && !a.Hit).ToList();

                var objToRemoveValue = lastFObjects[lastFObjects.Count - FramesCount].InputObject;

                return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(objToRemoveValue)));
            }
            else if (type == VMAlgorithmType.LRU)
            {
                var lastFObjects = objects.AsEnumerable().Reverse().Distinct().ToList();

                var objToRemoveValue = lastFObjects[FramesCount - 1].InputObject;

                return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(objToRemoveValue)));
            }
            else if (type == VMAlgorithmType.Optimal)
            {
                var rightString = input.Substring(current, input.Length - current);

                var rightUsed = rightString.Where(a => vmObj.Frames.Exists(b => b.Equals(a))).ToList();

                if (rightUsed.Count == 0)
                {
                    return(ObjToRemoveIndex = 0);
                }

                var grouped = rightUsed.GroupBy(a => a).ToList();

                if (grouped.Count < vmObj.Frames.Count)
                {
                    var notExists = vmObj.Frames.Where(a => !grouped.Exists(b => a.Equals(b.Key))).ToList();

                    var objToRemoveValue = notExists.FirstOrDefault();

                    return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(objToRemoveValue)));
                }

                grouped = grouped.OrderByDescending(a => a.Count()).ToList();

                var objToRemoveValuee = grouped.LastOrDefault().Key;

                return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(objToRemoveValuee)));
            }
            else if (type == VMAlgorithmType.MFU)
            {
                var groupedObjects = vmObj.Frames.Select(a => new
                {
                    obj   = a,
                    count = input.Substring(0, current).Where(b => b.Equals(a.Value)).Count()
                });

                var max = groupedObjects.Max(a => a.count);

                // Now get the objects with this max count value
                var maxCountObjects = groupedObjects.Where(a => a.count == max);

                return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(maxCountObjects.FirstOrDefault().obj.Value)));
            }
            else if (type == VMAlgorithmType.SecondChance)
            {
                //var orderedObjects = objects.SelectMany(a => a.Frames).
                //	Where(e=>vmObj.Frames.Exists(f=>f.Equals(e))).
                //	GroupBy(b => b).
                //	OrderByDescending(c => c.Count());

                var orderedObjects = GetValuesCounts(objects, vmObj).OrderBy(a => a.Value);

point:

                foreach (var obj in orderedObjects.Reverse())
                {
                    var frameObj = vmObj.Frames.Find(a => a.Equals(obj.Key));

                    if (frameObj == null)
                    {
                        continue;
                    }

                    if (frameObj.SecondChance)
                    {
                        frameObj.SecondChance = false;
                        continue;
                    }
                    else
                    {
                        return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(obj.Key)));
                    }
                }

                goto point;
            }
            else if (type == VMAlgorithmType.LFU)
            {
                var groupedObjects = vmObj.Frames.Select(a => new
                {
                    obj         = a,
                    count       = input.Substring(0, current).Where(b => b.Equals(a.Value)).Count(),
                    stringIndex = input.Substring(0, current).IndexOf((char)a.Value),
                });

                var min = groupedObjects.Min(a => a.count);

                // Now get the objects with this min count value ordered by input string index
                var minCountObjects = groupedObjects.Where(a => a.count == min).OrderBy(a => a.stringIndex);

                return(ObjToRemoveIndex = vmObj.Frames.FindIndex(a => a.Equals(minCountObjects.FirstOrDefault().obj.Value)));
            }

            return(ObjToRemoveIndex);
        }