package mapping;

import mapping.data.IDsQueue;
import mapping.data.Job;

/**
 * This is the implementation of the FCFS scheduling policy.
 * 
 * @author Majd Kokaly
 * 
 */
public class FCFS_MS extends MappingScheme {

	/**
	 * The serialVersionUID is used to universally identify this version of this
	 * class.
	 */
	private static final long serialVersionUID = 6935102166481580800L;

	/**
	 * This queue is the queue of jobs. It is the essence of this policy since
	 * the jobs are served on FCFS basis.
	 */
	private IDsQueue<Long> serviceQueue;

	/**
	 * The helper thread.
	 */
	private FCFS_MS_Thread fifo_ms_thread;

	/**
	 * This final integer is used to notify the helper when there is no jobs in the
	 * queue.
	 */
	final static int NO_JOBS = -100;

	/**
	 * A default constructor.
	 * 
	 * @param mapper
	 *            The mapper object
	 */
	public FCFS_MS(Mapper mapper) {
		super(mapper);
		this.setDescription("FCFS");

	}

	/**
	 * 
	 * In this method the queue is constructed and the FCFS_MS_Thread is
	 * initialized and started.
	 * 
	 * @see MappingScheme#startMappingScheme()
	 */
	public void startMappingScheme() {
		serviceQueue = new IDsQueue<Long>();
		fifo_ms_thread = new FCFS_MS_Thread(this);
		fifo_ms_thread.startThread();

	}

	/**
	 * The FCFS_MS_Thread is stopped.
	 * 
	 * @see MappingScheme#stopMappingScheme()
	 */
	public void stopMappingScheme() {
		fifo_ms_thread.stopThread();
	}

	/**
	 * This method is invoked by the mapper. The job is enqueued in the service
	 * queue. It will be assigned to a server when it reaches the head of that
	 * queue.
	 * 
	 * @see MappingScheme#mapJob(Job)
	 */
	protected void mapJob(Job job) {
		serviceQueue.enqueue(job.getIndex());
	}

	/**
	 * The job is resubmitted when a timeout happens.
	 * 
	 * @see MappingScheme#handleJobTimeOut(long)
	 */
	public void handleJobTimeOut(long jobID) {
		this.getMapper().getJobsTable().setTimedOut(jobID, true);
		this.getMapper().getJobsTable().setJobServer(jobID, null);
		this.getMapper().resubmitJob(this.getMapper().getJobsTable().get(jobID));
	}

	/**
	 * FCFS policy is not sensitive for availability/unavailability events, thus
	 * this method is not implemented.
	 * 
	 * @see MappingScheme#serverIsDown(int)
	 */
	public void serverIsDown(int serverID) {

	}

	/**
	 * FCFS policy is not sensitive. FCFS policy is not sensitive for
	 * availability/unavailability events, thus this method is not implemented.
	 * 
	 * @see MappingScheme#handleJobTimeOut(long)
	 */
	public void serverIsUp(int serverID) {

	}

	/**
	 * This method is invoked by the FCFS_MS_Thread object. In this method a job
	 * is sought to map it for the server with ID "serverID"
	 * 
	 * @param serverID
	 *            The available server id.
	 * 
	 * @return -1 when a failure happens, 1 otherwise.
	 */
	protected int sendJobForServer(int serverID) {
		long jobID;

		if (this.serviceQueue.isEmpty())
			return NO_JOBS;

		jobID = this.serviceQueue.peak();
		long result = this.getMapper().sendJob(jobID, serverID);
		if (result >= 0) { // Could be sent
			System.out.println("FCFS.sendJobForServer(): WAS sent " + jobID);
			this.serviceQueue.dequeue();
			
			return 1;
		} else {
			return -1;
		}
	}
}
