import java.util.LinkedList;

/**
 * Shortest Remaining Time
 */
public class SRT {

    private int timeStep = 0;
    private int disp;
    private int timeLastChecked = -1;

    private static LinkedList<Process> processListFromFile;   //Original List of processes from the the file
    private LinkedList<Process> waitingQueue = new LinkedList<>();  //Processes officially added to the waiting queue.
    private LinkedList<Process> newProcesses = new LinkedList<>();  //Processes that have arrived after each time point.
    //Constructors

    public SRT(int dispInput, LinkedList<Process> processListInput)
    {
        disp = dispInput;
        processListFromFile = processListInput;
    }


    private void checkForArrivals()
    {
        for(int i = 0; i< processListFromFile.size(); i++)
        {
            if((processListFromFile.get(i).getArrive()<=timeStep) && (processListFromFile.get(i).getArrive() > timeLastChecked))
            {
                newProcesses.add(processListFromFile.get(i));
            }
        }

        timeLastChecked = timeStep;

        //do any tie breaking by sorting the new processes based on name
        boolean swap = false;
        do
        {
            swap = false;
            for(int i = 0; i< newProcesses.size()-1; i++)
            {          
                if(Integer.parseInt(newProcesses.get(i).getId().substring(1))>Integer.parseInt(newProcesses.get(i+1).getId().substring(1)))
                {
                    Process temp = newProcesses.get(i);
                    newProcesses.remove(i);
                    newProcesses.add(i+1, temp);
                    swap = true;
                }
            }
        }while(swap);

        //Move the newly arrived (and organised) processes to the queue.
        for(int i =0; i < newProcesses.size(); i++)
        {
            waitingQueue.add(newProcesses.get(i));
        }
        newProcesses.clear();
    }

    public void runDispatch()
    {       
        System.out.println("SRT:");
        int processesFinished = 0;
        Process currentProcess;
        Process lastRunProcess = new Process("temp", 0, 0, 0);  //temp process for comparing the first run
        
        do
         {
            checkForArrivals(); //Check for any new processes since timestep            

            //As long as there is something in the queue
            if(waitingQueue.size()>0)
            {
                currentProcess = findShortestProcess();
                
                if(!lastRunProcess.getId().equals(currentProcess.getId()))
                {
                    timeStep = timeStep+disp;
                    System.out.println("T"+timeStep+": "+currentProcess.getId());
                    for(int i = 0; i<waitingQueue.size(); i++)
                    {
                        waitingQueue.get(i).runForOneTick(false);
                    }
                }

                runProcessTick(currentProcess);
                
                if(currentProcess.isDone())
                {
                    waitingQueue.remove(currentProcess);
                    processesFinished++;
                }

                lastRunProcess = currentProcess;
            }
            
         }while(processesFinished!=processListFromFile.size());      
    }

    private Process findShortestProcess()
    {
        int listPos = -1;
        int remaining = waitingQueue.getFirst().getRemainingTime();

        for(int i = 0; i<waitingQueue.size(); i++)
        {
            if(waitingQueue.get(i).getRemainingTime()<remaining)
            {
                listPos = i;
                remaining = waitingQueue.get(i).getRemainingTime();
            }
        }

        if(listPos==-1)
        {
            return waitingQueue.getFirst();
        }
        else
        {
            return waitingQueue.get(listPos);
        }
    }

    private void runProcessTick(Process input)
    {   
        timeStep++;
        for(int i = 0; i< waitingQueue.size(); i++)
        {
            if(!input.getId().equals(waitingQueue.get(i).getId()))
            {
                waitingQueue.get(i).runForOneTick(false);
            }
            else
            {
                waitingQueue.get(i).runForOneTick(true);
            }
        }

        if(input.isDone())
        {
            input.saveEndTime(timeStep);
            input.saveTurnTime();
        }       
    }    

    public void printResults()
    {
        for (int i = 0; i < processListFromFile.size(); i++)
        {
            //System.out.println("T"+processListFromFile.get(i).getStartTime()+": "+processListFromFile.get(i).getId());
        }
        
        System.out.println("\nProcess \tTurnaround Time \tWaiting Time");
        for (int i = 0; i < processListFromFile.size(); i++)
        {
            System.out.print(processListFromFile.get(i).getId()+"\t\t");
            System.out.print(processListFromFile.get(i).getTurnTime()+"\t\t\t");
            System.out.print(processListFromFile.get(i).getWaitTime()+"\n");
        }
    }
}