/* 
 * SCAN.java (Implements SCAN Algorithm for disk access).
 *
 * 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 : SCAN.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 SCAN
{
	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 SCAN(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 SCAN");
		if(debug)
			System.out.println("Starting heads at <0,0>");
		int index=0;
		int ic;
		boolean forward=true;
		Access acc=new Access();
		while (true)
		{
			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");                
				}               
			}
			boolean exist=true;
			while (exist)
			{
				exist=false;
				for(ic=0;ic<requested.size();ic++)
				{
					acc=(Access)requested.elementAt(ic);
					if (acc.track==curTrack)
					{
						exist=true;
						break;
					}
				}
				if (exist)
				{
					reads++;
					requested.remove(acc);
					if(debug)
						System.out.println("Move heads to: <"+acc.track+","+acc.sector+","+acc.head+">");
					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");                
						}               
					}
				}       
			}
			if (requested.isEmpty()&&index==requests.size())
				break;
			curTime+=(float)1/seekRate;
			distance++;
			if (forward)
				if (curTrack==(tracks-1))
				{
					curTrack--;
					forward=false;
				}
				else
					curTrack++;
			else
				if (curTrack==0)
				{
					curTrack++;
					forward=true;
				}
				else
					curTrack--;     
			curSector=(int)(sectors*RPM/60/seekRate+curSector)%sectors;
		}
		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)
		{
		}
	}
}

