package pulling.availability_imposer;

/**
 * This class is a Runnable (Thread) class able to navigate the Availability Net
 * and impose availability. This thread starts from the root node and moves to
 * other nodes using the probability of Arch objects. When it reaches a node it
 * tries to impose the availability that is defined in the Nodes.
 * 
 * @author Majd Kokaly
 * 
 */
public class AvailabilityImposer implements Runnable {
	/**
	 * The net to be navigated
	 */
	private Net net;
	
	/**
	 * Thread flag 
	 */
	private volatile boolean alive = true;
	
	/**
	 * Default constructor
	 * @param net to set the net field
	 */
	public AvailabilityImposer(Net net) {
		this.setNet(net);
	}

	public Net getNet() {
		return net;
	}

	public void setNet(Net net) {
		this.net = net;
	}

	protected boolean isAlive() {
		return alive;
	}

	protected void setAlive(boolean alive) {
		this.alive = alive;
	}

	/**
	 * This method is responsible for navigation.
	 */
	public void run() {
		Node current = this.getNet().getStartNode();
		double aj = current.getAj();
		long sleepTime = current.getPeriodToStay();
		imposeAvalability(aj, sleepTime);

		while (isAlive()) {
			current = getNext(current);
			imposeAvalability(current.getAj(), current.getPeriodToStay());
		}

	}
	
	/**
	 * This method determines what node to go to next depending on the probability on the arches of the source node 
	 * @param sourceNode is the source node
	 * @return the next Node to visit
	 */
	private Node getNext(Node sourceNode) {
		double random = Math.random();
		double previousPropabilities = 0;
		for (int i = 0; i < sourceNode.getNeighboursNumber(); i++) {
			double propability = sourceNode.getPropability(i);
			if (random > previousPropabilities && random <= propability + previousPropabilities) {
				System.out.println("Random: " + random + " and next node is: " + sourceNode.getNeighbour(i).getDescription()
						+ "\n");
				return sourceNode.getNeighbour(i);
			}
			previousPropabilities += propability;
		}
		return null;
	}

	/**
	 * This method uses CPU_EatersLauncher to impose availability
	 * 
	 * @param aj the availability desired
	 * @param period the period that aj is going to last
	 */
	private void imposeAvalability(double aj, long period) {
		System.out.println("Aj: " + aj + " period: " + period);
		try {
			Thread.sleep(period);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
