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 a certain number of servers in the queue
 * 
 * @author Majd Kokaly & Ben Kybartas
 */
public class NREP_MS_Thread implements Runnable 
{
	/**
	 * This flag tells the thread if it is alive or should kill itself
	 */
	private boolean alive = true;
	
	/**
	 * The number of servers that each job will be sent to
	 */
	private int repetitions;
	
	private int[] serverIDs;
	
	private Server[] server;
	
	private int result;
	
	/**
	 * A Thread object that runs this Runnable class
	 */
	private Thread thisThread;
	
	/**
	 * The REP_MS that this thread helps
	 */
	private NREP_MS rep_ms;
	
	/**
	 * A default constructor
	 */
	public NREP_MS_Thread(NREP_MS rep_ms)
	{
		repetitions = 5;
		serverIDs = new int[repetitions];
		server = new Server[repetitions];
		this.setAlive(true);
		this.setNREP_MS(rep_ms);
	}
	
	public synchronized boolean isAlive()
	{
	return alive;	
	}
	
	public synchronized void setAlive(boolean alive) 
	{
		this.alive = alive;
	}
	
	public NREP_MS getNREP_MS()
	{
		return rep_ms;
	}
	
	public void setNREP_MS(NREP_MS Rep_ms)
	{
		this.rep_ms = Rep_ms;
	}
	
	/**
	 * This method starts the thread
	 */
	public void startThread() 
	{
		System.out.println(repetitions + " 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 readyforJobSubmission()
	{
		boolean ready = true;
		
		if (!arrayisFull(serverIDs))
		{
			ready = false;
		}
		
		for (int i = 0; i < server.length; i++)
		{
			if (!(server[i].getNumberOfActiveJobs() == 0) || this.getNREP_MS().getMapper().getServersTable().isServerDown(serverIDs[i]))
					{
						ready = false;
					}
		}
		return ready;
	}
	
	public void run() {
		
		
		int i = 0;
		IDsQueue<Integer> q = this.getNREP_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.getNREP_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())
				{

					result = this.getNREP_MS().sendJobForServer(serverIDs);
					
					if (result < 0) 
					{
						try
						{
							Thread.sleep(50);
						}
						catch (InterruptedException e)
						{
							if (!isAlive())
								return;
						}
					}
				}
				else
				{//is empty
					try
					{
						Thread.sleep(30);
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
					
				}
			}
		}
	}
}

