package mapping;

import mapping.data.Server;
import mapping.data.IDsQueue;

/**
 * This Thread is a helper thread for the FCFS_MS objects. It is a thread that
 * iterates over the AvailableServers Queue and then it asks the FCFS_MS object to map a
 * job for two servers in the queue
 * 
 * @author Majd Kokaly & Ben Kybartas
 */
public class TWOREP_MS_Thread implements Runnable 
{
	/**
	 * This flag tells the thread if it is alive or should kill itself
	 */
	private boolean alive = true;
	
	private int[] serverIDs = new int[2];
	
	private Server[] server = new Server[2];
	
	private int[] results = new int[2];
	
	/**
	 * A Thread object that runs this Runnable class
	 */
	private Thread thisThread;
	
	/**
	 * The SLQ_MS that this thread helps
	 */
	private FCFS_MS fcfs_ms;
	
	/**
	 * A default constructor
	 */
	public TWOREP_MS_Thread(FCFS_MS fcfs_ms)
	{
		this.setAlive(true);
		this.setFCFS_MS(fcfs_ms);
	}
	
	public synchronized boolean isAlive()
	{
	return alive;	
	}
	
	public synchronized void setAlive(boolean alive) 
	{
		this.alive = alive;
	}
	
	public FCFS_MS getFCFS_MS()
	{
		return fcfs_ms;
	}
	
	public void setFCFS_MS(FCFS_MS Fcfs_ms)
	{
		this.fcfs_ms = Fcfs_ms;
	}
	
	/**
	 * This method starts the thread
	 */
	public void startThread() 
	{
		System.out.println("Two Replication Thread started");
		thisThread = new Thread(this);
		thisThread.start();
	}
	
	/**
	 * This method stops the thread
	 */
	public void stopThread()
	{
		this.setAlive(false);
		thisThread.interrupt();
		thisThread = null;
	}
	
	public boolean arrayisFull(int[] array)
	{
		boolean Full = true;
		for (int i = 0; i < array.length; i++)
		{
			if (array[i]==0)
			{
				Full = false;
			}
		}
		return Full;
	}
	
	public boolean failuresOccur()
	{
		boolean Fail = false;
		for (int i = 0; i < results.length; i++)
		{
			if (results[i]<0)
			{
				Fail = true;
			}
		}
		return Fail;
	}
	
	public boolean readyforJobSubmission()
	{
		boolean ready = true;
		
		if (!arrayisFull(serverIDs))
		{
			ready = false;
		}
		
		for (int i = 0; i < server.length; i++)
		{
			if (!(server[i].getNumberOfActiveJobs() == 0) || this.getFCFS_MS().getMapper().getServersTable().isServerDown(serverIDs[i]))
					{
						ready = false;
					}
		}
		return ready;
	}
	
	public void run() {
		
		
		int i = 0;
		IDsQueue<Integer> q = this.getFCFS_MS().getMapper().getAvailableServersQueue();
		
		while (this.isAlive()) 
		{
			if (!q.isEmpty())
			{
				
				if (i < serverIDs.length)
				{
				serverIDs[i] = q.getVal((int)(Math.random()*q.getRowCount()));
				i++;
				}
				
				if  (arrayisFull(serverIDs))
				{
					for (i = 0; i < serverIDs.length; i++ )
					{
						server[i] = this.getFCFS_MS().getMapper().getServersTable().get(serverIDs[i]);
					}
				}
				
				/**
				 * Any server in the available server queue should satisfy this
				 * condition. Just to be sure that the server is not busy nor is
				 * it down
				 */
				if (readyforJobSubmission())
				{
					for (i = 0; i < results.length; i ++)
					{
					results[i] = this.getFCFS_MS().sendJobForServer(serverIDs[i]);
					}
					
					if (failuresOccur()) 
					{
						try
						{
							Thread.sleep(50);
						}
						catch (InterruptedException e)
						{
							if (!isAlive())
								return;
						}
					}
				}
				else
				{//is empty
					try
					{
						Thread.sleep(30);
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
					
				}
			}
		}
	}
}

