/* 
 * SSTF.java (Implements SSTF Algorithm).
 *
 * Written by : Nitin  Motgi (nmotgi@cs.ucf.edu)
 * 
 *
 * ASSUMPTIONS :
 *
 * 1. Request time is always in seconds.
 * 2. The request will be in the order of arrival time.
 *
 * Portions copyright(c) 2001 to School of Electrical Engineering and 
 * Computer Science, UCF, Orlando.                   
 *                                    
 * Use and distribution of this source code are strictly governed by 
 * terms and conditions set by the authors.
 * 
 * $Id : SSTF.java, 04/10/2001. $
 *            
 * Revision History:
 *
 * 1. Created basic structure           Nitin,        v1.0.0  04/12/2001.
 * 2. Added Documentation.              Nitin,        v1.0.1  04/12/2001.
*/
import java.io.*;
import java.util.*;

public class SSTF
{
	private Vector requested;
	private Vector requests;
	private int heads;
	private int tracks;
	private int sectors;
	private int RPM;
	private int seekRate;
	private boolean debug;
	static Access preAcc;
	public SSTF(Vector access,int head,int track,int sector,int rpm,int seekrate,boolean deb)
	{
		requests=new Vector();
		requests=access;
		requested=new Vector();
		heads=head;
		tracks=track;
		sectors=sector;
		RPM=rpm;
		seekRate=seekrate;
		debug=deb;
		preAcc=new Access();    
	}
	private boolean valid(Access acc)
	{
		if (acc.track>=tracks||acc.sector>=sectors||acc.head>=heads)
			return(false);                       
		if(preAcc!=null&&preAcc.requestTime>acc.requestTime)
			return(false);
		return(true);   
	}
	public void simulate()
	{
		float curTime=0;
		int curTrack=0;
		int curSector=0;
		int distance=0;
		int reads=0;
		float latency=0;
		float readTime=0;
			
		System.out.println("Using Shortest Seek Time First");
		if(debug)
			System.out.println("Starting heads at <0,0>");
		int index=0;
		int ic;
		Access acc=new Access();
		while (!requested.isEmpty()||index<requests.size())
		{
			if (requested.isEmpty())
			{
				acc=(Access)requests.elementAt(index);
				curTime=acc.requestTime;
				index++;
				if (valid(acc))
				{
					preAcc=acc;
					requested.addElement(acc);
					if(debug)
						System.out.println("Read request: <"+acc.track+","+acc.sector+","+acc.head+">");
				}       
				else
					if(debug)
						System.out.println("Read request: <"+acc.track+","+acc.sector+","+acc.head+"> Invalid request");                
				
				while (index<requests.size())
				{
					acc=(Access)requests.elementAt(index);
					if(acc.requestTime>curTime)
						break;
					else
					{
						index++;
						if (valid(acc))
						{
							preAcc=acc;
							requested.addElement(acc);
							if(debug)
								System.out.println("Read request: <"+acc.track+","+acc.sector+","+acc.head+">");
						}       
						else
							if(debug)
								System.out.println("Read request: <"+acc.track+","+acc.sector+","+acc.head+"> Invalid request");                
					}               
				}
			}
			else
			{
				reads++;
				int minTrack=tracks;
				int tempIndex=0;
				for(ic=0;ic<requested.size();ic++)
				{
					acc=(Access)requested.elementAt(ic);
					if (Math.abs(acc.track-curTrack)<minTrack)
					{
						minTrack=Math.abs(acc.track-curTrack);
						tempIndex=ic;
					}
				}
				acc=(Access)requested.remove(tempIndex);
				if(debug)
					System.out.println("Move heads to: <"+acc.track+","+acc.sector+","+acc.head+">");
				float seekTime=(float)Math.abs(curTrack-acc.track);
				distance+=seekTime;
				curTrack=acc.track;
				curTime+=(float)seekTime/seekRate;
				curSector=(int)(sectors*RPM/60*seekTime/seekRate+curSector)%sectors;
				if (curSector>acc.sector)
				{
					latency+=(float)(sectors-curSector+acc.sector)*60/sectors/RPM;
					curTime+=(float)(sectors-curSector+acc.sector)*60/sectors/RPM;
				}
				else
				{
					latency+=(float)(acc.sector-curSector)*60/sectors/RPM;  
					curTime+=(float)(acc.sector-curSector)*60/sectors/RPM;
				}
				readTime+=curTime-acc.requestTime;
				curSector=acc.sector;
				if(debug)
					System.out.println("Read <"+acc.track+","+acc.sector+","+acc.head+">");
				while (index<requests.size())
				{
					acc=(Access)requests.elementAt(index);
					if(acc.requestTime>curTime)
						break;
					else
					{
						index++;
						if (valid(acc))
						{
							preAcc=acc;
							requested.addElement(acc);
							if(debug)
								System.out.println("Read request: <"+acc.track+","+acc.sector+","+acc.head+">");
						}       
						else
							if(debug)
								System.out.println("Read request: <"+acc.track+","+acc.sector+","+acc.head+"> Invalid request");                
					}               
				}
			}
		}
		System.out.println("Total number of Reads:"+reads);
		System.out.println("Total distance traveled:"+distance);
		if(reads==0)
			System.out.println("No read at all");
		else
		{               
			System.out.println("Average Seek time:"+(float)distance/seekRate/reads+" seconds");
			System.out.println("Average latency:"+latency/reads+" seconds");
			System.out.println("Average total read time:"+readTime/reads+" seconds");
		}
		System.out.println("Press any key to continue...");
		try
		{
			System.in.read();
			System.in.skip(1);
		}
		catch (IOException exce)
		{
		}
	}
}


