package mapping.data;

import java.io.Serializable;
import java.util.Hashtable;

/**
 * This class represents the collection of servers in the system. It was
 * implemented as a Hashtable. This class is thread safe.
 * 
 * @author Majd Kokaly
 */
public class ServersTable extends Hashtable<Integer, Server> implements Serializable {
	/**
	 * The serialVersionUID is used to universally identify this version of this
	 * class.
	 */
	private static final long serialVersionUID = 7932816264838278275L;

	/**
	 * A counter to give each server a unique ID. It starts with one.
	 */
	private int serverIndex = 1;

	/**
	 * This objects listens to changes on this object and act accordingly.
	 */
	transient private ServersTableListener listener;

	public ServersTable() {

	}

	public ServersTable(int initialCapacity) {
		super(initialCapacity);
	}

	public ServersTable(int initialCapacity, float loadFactor) {
		super(initialCapacity, loadFactor);
	}
	
	/**
	 * Adds a listener to this object.
	 * @param listener The listener to be added.
	 */
	public void addServersListener(ServersTableListener listener) {
		this.listener = listener;
	}
	
	public void printAll() {
		System.out.print(this.toString());
	}

	/**
	 * This method adds a Server object to the table and gives it its unique ID.
	 * 
	 * @param server
	 *            the server to be added.
	 */
	public void addServer(Server server) {
		server.setIndex(serverIndex++);
		this.put(server.getIndex(), server);
	}

	/**
	 * 
	 * @param hostname
	 *            The hostname of the machine being sought.
	 * @return The Server object that has the host name hostname. It returns
	 *         null if server is not found.
	 */
	public Server getServer(String hostname) {
		for (int i = 1; i <= this.size(); i++) {
			if (this.get(i).getHostName().equalsIgnoreCase(hostname.trim())) {
				return this.get(i);
			}
		}
		return null;
	}


	/**
	 * This method removes a server with ID id and reorders the servers. It is
	 * always true that if there is N servers in the system that the IDs of the
	 * server are in the set {1 , 2, .. N}.
	 * 
	 * @param id The id of the server to be deleted.
	 */
	public void removeServer(int id) {
		this.remove(id);
		Server server = null;
		serverIndex = id;
		for (int i = id + 1; i <= this.size() + 1; i++) {
			server = this.remove(i);
			this.addServer(server);
		}
	}

	/**
	 * @param serverID The ID of the server in subject.
	 * @return true if the server with serverID is down, false otherwise.
	 */
	public boolean isServerDown(int serverID) {
		return this.get(serverID).isDown();
	}

	/**
	 * This method set the server of ID serverID to down.
	 * 
	 * @param serverID The ID of the server in subject.
	 * @param down A boolean value determining whether the server is down or not.
	 */
	public void setServerDown(int serverID, boolean down) {
		this.get(serverID).setDown(down);
		if (this.listener != null)
			listener.upDownStatusChanged(serverID, down);
	}


	/**
	 * 
	 * @param serverID The ID of the server in subject.
	 */
	public void clearServerActiveJobsNumber(int serverID) {
		this.get(serverID).clearActiveJobsNumber();
	}

	/**
	 * 
	 * @return The failure periods mean of all servers in minutes.
	 * @see Server#clearActiveJobsNumber()
	 * 
	 */
	public double getFailurePeriodsMeanOfAllServersInMinutes() {
		double sum = 0;
		double count = 0;
		for (int i = 1; i <= this.size(); i++) {
			if (this.get(i) != null) {
				if (this.get(i).getFailureTrace() != null) {
					sum += this.get(i).getFailureTrace().getMeanOfPeriodsInMinutes();
					count++;
				}
			}
		}
		if (count == 0)
			return 0;
		else
			return sum / count;
	}

	/**
	 * @return The up-time mean of all servers in minutes
	 */
	public double getUpTimeMeanOfAllServersInMinutes() {
		double sum = 0;
		double count = 0;
		for (int i = 1; i <= this.size(); i++) {
			if (this.get(i) != null) {
				if (this.get(i).getFailureTrace() != null) {
					sum += this.get(i).getFailureTrace().getMeanIfInterPeriodsInMinutes();
					count++;
				}
			}
		}
		if (count == 0)
			return 0;
		else
			return sum / count;
	}
}
