public abstract class Timed implements Comparable<Timed> {

	/**
	 * The main container for all recurring events in the system
	 */
	private static final PriorityQueue<Timed> timedlist = new PriorityQueue<Timed>();
	/**
	 * If set to true, the event loop is processing this object at the moment.
	 */
	private boolean underProcessing = false;
	/**
	 * The actual time in the system. This is maintained in ticks!
	 */
	private static long fireCounter = 0;

	/**
	 * Determines if the actual timed object is going to receive recurring events
	 * (through the tick() function).
	 */
	private boolean activeSubscription = false;
	/**
	 * Specifies the next time (in ticks) when the recurring event should be fired.
	 * This is used to order the elements in the timedList event list.
	 */
	private long nextEvent = 0;
	/**
	 * The number of ticks that should pass between two tick() calls.
	 * 
	 * This field is usually a positive number, if it is -1 then the frequency is
	 * not yet initialized by the class.
	 */
	private long frequency = -1;
	/**
	 * Should two timed events occur on the same time instance this marker allows
	 * Timed to determine which ones should be notified first.
	 * 
	 * if this is true then all timed events (except other backpreferred ones) on
	 * the same time instance will be fired first before this one is called. Just
	 * like regular events, the notification order of backpreferred events is not
	 * fixed!
	 */
	private boolean backPreference = false;

	/**
	 * Allows to determine if a particular timed object is receiving notifications
	 * from the system
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if this object will receive recurrign events in the
	 *         future
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	public final boolean isSubscribed() {
		return activeSubscription;
	}

	/**
	 * Allows Timed objects to subscribe for recurring events with a particular
	 * frequency. This function is protected so no external entities should be able
	 * to modify the subscription for a timed object.
	 * 
	 * @param freq the event frequency with which the tick() function should be
	 *             called on the particular implementation of timed.
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the subscription succeeded
	 *         <li><i>false</i> otherwise (i.e. when there was already a
	 *         subscription). Please note that if you receive false, then the tick()
	 *         function will not be called with the frequency defined here!
	 *         </ul>
	 */
	protected final boolean subscribe(final long freq) {
		if (activeSubscription) {
			return false;
		}
		realSubscribe(freq);
		return true;
	}

	/**
	 * The actual subscription function that is behind updateFreq or subcribe
	 * 
	 * @param freq the event frequency with which the tick() function should be
	 *             called on the particular implementation of timed.
	 */
	private void realSubscribe(final long freq) {
		activeSubscription = true;
		updateEvent(freq);
		timedlist.offer(this);
	}

	/**
	 * Cancels the future recurrance of this event.
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the unsubscription succeeded
	 *         <li><i>false</i> otherwise (i.e., this timed object was already
	 *         cancelled)
	 *         </ul>
	 */
	protected final boolean unsubscribe() {
		if (activeSubscription) {
			activeSubscription = false;
			if (underProcessing) {
				// because of the poll during the fire function there is nothing
				// to remove from the list
				return true;
			}
			timedlist.remove(this);
			return true;
		}
		return false;
	}

	/**
	 * Allows the alteration of the event frequency independently from subscription.
	 * If the Timed object is not subscribed then the update function will ensure
	 * the subscription happens
	 * 
	 * @param freq the event frequency with which the tick() function should be
	 *             called on the particular implementation of timed.
	 * @return the earilest time instance (in ticks) when the tick() function will
	 *         be called.
	 */
	protected final long updateFrequency(final long freq) {
		if (activeSubscription) {
			final long oldNE = nextEvent;
			updateEvent(freq);
			if (!underProcessing && oldNE != nextEvent) {
				timedlist.remove(this);
				timedlist.offer(this);
			}
		} else {
			realSubscribe(freq);
		}
		return nextEvent;
	}

	/**
	 * A core function that actually manages the frequency and nextevent fields. It
	 * contains several checks to reveal inproper handling of the Timed object.
	 * 
	 * @param freq the event frequency with which the tick() function should be
	 *             called on the particular implementation of timed.
	 * @throws IllegalStateException if the frequency specified is negative, or if
	 *                               the next event would be in the indefinite
	 *                               future
	 */
	private void updateEvent(final long freq) {
		if (freq < 0) {
			throw new IllegalStateException("ERROR: Negative event frequency cannot simulate further!");
		} else {
			frequency = freq;
			nextEvent = calcTimeJump(freq);
			if (nextEvent == Long.MAX_VALUE) {
				throw new IllegalStateException("Event to never occur: " + freq);
			}
		}
	}

	/**
	 * Allows the query of the next event at which the tick() function will be
	 * called for this object
	 * 
	 * @return the next event's time instance in ticks.
	 */
	public long getNextEvent() {
		return nextEvent;
	}

	/**
	 * Determines the time distance (in ticks) between two tick() calls.
	 * 
	 * If this object is unsubscribed then this call returns with the last
	 * frequency.
	 * 
	 * @return the frequency in ticks.
	 */
	public long getFrequency() {
		return frequency;
	}

	/**
	 * Determines the next event at which point this object will receive a tick()
	 * call.
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>if subscribed</i> the number of ticks till the next tick()
	 *         call arrives
	 *         <li><i>if not subscribed</i> Long.MAX_VALUE.
	 *         </ul>
	 */
	public long nextEventDistance() {
		return activeSubscription ? nextEvent - fireCounter : Long.MAX_VALUE;
	}

	/**
	 * a comparator for timed objects based on next events and back preference
	 * (those objects will be specified smaller that have an earlier next event - if
	 * nextevents are the same then backpreference decides betwen events)
	 */
	@Override
	public int compareTo(final Timed o) {
		return nextEvent < o.nextEvent ? -1
				: nextEvent == o.nextEvent ? ((backPreference ^ o.backPreference) ? (backPreference ? 1 : -1) : 0) : 1;
	}

	/**
	 * Enables to set the back preference of a particular timed object.
	 * 
	 * @param backPreference
	 *                       <ul>
	 *                       <li><i>true</i> if this event should be processed
	 *                       amongst the last events at any given time instance
	 *                       <li><i>false</i> if the event should be processed
	 *                       before the backpreferred events - this is the default
	 *                       case for all events before calling this function!
	 *                       </ul>
	 */
	protected void setBackPreference(final boolean backPreference) {
		this.backPreference = backPreference;
	}

	/**
	 * This function allows the manual operation of the event handling mechanism. It
	 * is used to send out events that should occur at a particular time instance.
	 * After the events are sent out the time will be advanced by 1 tick. If there
	 * are no events due at the particular time instance then this function just
	 * advances the time by one tick.
	 */
	public static final void fire() {
		while (!timedlist.isEmpty() && timedlist.peek().nextEvent == fireCounter) {
			final Timed t = timedlist.poll();
			t.underProcessing = true;
			t.tick(fireCounter);
			if (t.activeSubscription) {
				t.updateEvent(t.frequency);
				timedlist.offer(t);
			}
			t.underProcessing = false;
		}
		fireCounter++;
	}

	/**
	 * A simple approach to calculate time advances in the system
	 * 
	 * @param jump the time (in ticks) to be advanced with
	 * @return the time (in ticks) at which point the particular jump will be
	 *         complete
	 */
	public static long calcTimeJump(long jump) {
		final long targettime = fireCounter + jump;
		return targettime < 0 ? Long.MAX_VALUE : targettime;
	}

	/**
	 * Increases the time with a specific amount of ticks. If there are some events
	 * that would need to be called before the specific amount of ticks happen, then
	 * the time is advanced to just the time instance before the next event should
	 * be fired.
	 * 
	 * This function allows a more manual handling of the simulation. But it is also
	 * used by the simulateUntil* functions.
	 * 
	 * @param desiredJump the amount of time to be jumped ahead.
	 * @return the amount of time that still remains until desiredjump.
	 */
	public static final long jumpTime(long desiredJump) {
		final long targettime = calcTimeJump(desiredJump);
		final long nextFire = getNextFire();
		if (targettime <= nextFire) {
			fireCounter = targettime;
			return 0;
		} else {
			fireCounter = nextFire < 0 ? targettime : nextFire;
			return targettime - fireCounter;
		}
	}

	/**
	 * Jumps the time until the time given by the user. If some events supposed to
	 * happen during the jumped time period, then this function cancels them. If
	 * some events should be recurring during the period, then the first recurrence
	 * of the event will be after the given time instance. If the given time
	 * instance has already occurred then this function does nothing!
	 * 
	 * @param desiredTime the time at which the simulation should continue after
	 *                    this call. If the time given here already happened then
	 *                    this function will have no effect.
	 */
	public static final void skipEventsTill(final long desiredTime) {
		final long distance = desiredTime - fireCounter;
		if (distance > 0) {
			if (timedlist.peek() != null) {
				while (timedlist.peek().nextEvent < desiredTime) {
					final Timed t = timedlist.poll();
					t.skip();
					final long oldfreq = t.frequency;
					long tempFreq = distance;
					if (oldfreq != 0) {
						tempFreq += oldfreq - distance % oldfreq;
					}
					t.updateFrequency(tempFreq);
					t.frequency = oldfreq;
				}
			}
			fireCounter = desiredTime;
		}
	}

	/**
	 * Determines the simulated time that has already passed since the beginning of
	 * the simulation (0).
	 * 
	 * @return The number of ticks that has passed since the beginning of time.
	 */
	public static final long getFireCount() {
		return fireCounter;
	}

	/**
	 * Determines the earliest time instance when there is any event in the system
	 * to be performed.
	 * 
	 * @return the time instance in ticks
	 */
	public static final long getNextFire() {
		final Timed head = timedlist.peek();
		return head == null ? -1 : head.nextEvent;
	}

	/**
	 * Automatically advances the time in the simulation until there are no events
	 * remaining in the event queue.
	 * 
	 * This function is useful when the simulation is completely set up and there is
	 * no user interaction expected before the simulation completes.
	 * 
	 * The function is ensuring that all events are fired during its operation.
	 * 
	 * <b>WARNING:</b> Please note calling this function could lead to infinite
	 * loops if at least one of the timed objects in the system does not call its
	 * unsubscribe() function.
	 */
	public static final void simulateUntilLastEvent() {
		long pnf = -1;
		long cnf = 0;
		while ((cnf = getNextFire()) >= 0 && (cnf > pnf)) {
			jumpTime(Long.MAX_VALUE);
			fire();
			pnf = cnf;
		}
	}

	/**
	 * Automatically advances the time in the simulation until the specific time
	 * instance.
	 * 
	 * The function is ensuring that all events are fired during its operation.
	 * 
	 * @param time the time instance that should not happen but the time should
	 *             advance to this point.
	 */
	public static final void simulateUntil(final long time) {
		while (timedlist.peek() != null && fireCounter < time) {
			jumpTime(time - fireCounter);
			if (getNextFire() == fireCounter) {
				fire();
			}
		}
	}

	/**
	 * Cancels all timed events and sets back the time to 0.
	 */
	public static final void resetTimed() {
		timedlist.clear();
		DeferredEvent.reset();
		fireCounter = 0;
	}

	/**
	 * Prints out basic information about this timed object. Enables easy debugging
	 * of complex simulations.
	 */
	@Override
	public String toString() {
		return new StringBuilder("Timed(Freq: ").append(frequency).append(" NE:").append(nextEvent).append(")")
				.toString();
	}

	/**
	 * This function will be called on all timed objects which asked for a recurring
	 * event notification at a given time instance.
	 * 
	 * @param fires The particular time instance when the function was called. The
	 *              time instance is passed so the tick functions will not need to
	 *              call getFireCount() if they need to operate on the actual time.
	 */
	public abstract void tick(long fires);

	/**
	 * Allows actions to be taken if the particular event is ignored
	 * 
	 * This tells the user of the function that the tick function will not be called
	 * at the time instance identified by nextEvent.
	 * 
	 * The function does nothing by default
	 * 
	 */
	protected void skip() {
	}
} public abstract class EnergyMeter extends Timed {

	/**
	 * the currently collected totalConsumption in all metering sessions so far.
	 */
	private double totalConsumption = 0;
	/**
	 * determines the time instance when the current metering session has
	 * started. This does not actually specify the time instance when the first
	 * metering session starts if there are gaps between metering sessions.
	 * instead it gives the time instance when a continuous metering session
	 * would start.
	 */
	private long meteringStarted;
	/**
	 * when was the last metering result collected.
	 */
	protected long lastMetered;
	/**
	 * when did the metering stopped reported in absolute time.
	 */
	private long meteringStopped = 0;

	/**
	 * Initiates an energy metering session.
	 * 
	 * @param interval
	 *            The meter refresh frequency.
	 * @param dropPriorReading
	 *            <ul>
	 *            <it>False: the totalConsumption values will accumulate from a
	 *            previous metering session <it>True: the totalconsumption
	 *            values will start from 0 after the completion of this
	 *            function.
	 *            </ul>
	 * @return <ul>
	 *         <li>False: if a metering session is already underway
	 *         <li>True: if the metering session was successfully initiated
	 *         </ul>
	 * 
	 */
	public boolean startMeter(final long interval, boolean dropPriorReading) {
		if (meteringStopped == -1) {
			return false;
		}
		subscribe(interval);
		lastMetered = Timed.getFireCount();
		if (dropPriorReading) {
			totalConsumption = 0;
		}
		if (totalConsumption == 0) {
			meteringStarted = lastMetered;
		} else {
			meteringStarted += lastMetered - meteringStopped;
		}
		meteringStopped = -1;
		return true;
	}

	/**
	 * Terminates the metering session, the totalconsumption values will no
	 * longer be updated!
	 */
	public void stopMeter() {
		if (unsubscribe()) {
			final long now = getFireCount();
			if (now != lastMetered) {
				tick(now);
			}
			meteringStopped = lastMetered;
		}
	}

	/**
	 * Allows the reading of the meter's current consumption report.
	 * 
	 * @return the total consumption collected during the metering sessions
	 */
	public double getTotalConsumption() {
		return totalConsumption;
	}

	/**
	 * Allows the reading of the beginning time instance of the metering session
	 * 
	 * If there were several metering sessions done by this meter, then this
	 * function reports the time instance when a hypothetical single continuous
	 * metering session would have started
	 * 
	 * @return The time instance when the metering session started
	 */
	public long getMeteringStarted() {
		return meteringStarted;
	}

	/**
	 * Enables access to the time when the last reading was stored for the last
	 * stopped metering session.
	 * 
	 * @return Three values are possible:
	 *         <ul>
	 *         <li>-1: The metering session is ongoing it is not yet terminated
	 *         <li>0: There was no metering session so far with this meter
	 *         <li>arbitrary positive number: The last reading time of the last
	 *         stopped session.
	 *         </ul>
	 */
	public long getMeteringStopped() {
		return meteringStopped;
	}

	/**
	 * increases the total consumption value with the specified amount. this is
	 * one of the main functions to be used by energy meters. Ensures that
	 * metering values are continuously increasing from a particular meter.
	 * 
	 * @param amount
	 *            the amount of additional energy consumed to be reported in
	 *            this meter
	 */
	protected void increaseTotalConsumption(final double amount) {
		totalConsumption += amount;
	}

	/**
	 * Allows internal realignment to new metering situations that need an
	 * immediate utilization reading
	 */
	protected void readjustMeter() {
		stopMeter();
		startMeter(getFrequency(), false);
	}
} public class MonitorConsumption extends Timed {
	/**
	 * the collected totalprocessed data with timestamps to allow seeing the
	 * temporal behavior of totalprocessed
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University of Innsbruck (c) 2013"
	 *
	 */
	private static class SpreadingRecord implements Comparable<SpreadingRecord> {
		/**
		 * the time in ticks when this record was acquired
		 */
		public long timestamp;
		/**
		 * the totalprocessed value at the particular time instance
		 */
		public double totalProcessed;

		/**
		 * a comparator to allow easy ordering of the records based on
		 * timestamps.
		 */
		@Override
		public int compareTo(SpreadingRecord o) {
			return Long.signum(timestamp - o.timestamp);
		}
	}

	/**
	 * what resource spreader to collect the totalprocessed values from
	 */
	final ResourceSpreader toMonitor;
	/**
	 * all spreading records that were collected during the past hour
	 */
	private PriorityQueue<SpreadingRecord> subHourRecords = new PriorityQueue<SpreadingRecord>();
	/**
	 * all spreading records collected during the past day
	 */
	private PriorityQueue<SpreadingRecord> subDayRecords = new PriorityQueue<SpreadingRecord>();
	/**
	 * the total processing accomplished in the last hour
	 */
	private double subHourProcessing = 0;
	/**
	 * the total processing accomplished in the last day
	 */
	private double subDayProcessing = 0;
	/**
	 * the totalprocessed value of the spreader during the last collection
	 */
	private double totalProcessed;
	/**
	 * the amount of processing done in the last second
	 */
	private double subSecondProcessing = 0;

	/**
	 * the amount of ticks it takes for a single second to pass in the simulated
	 * time
	 */
	private final long aSecond;

	/**
	 * Initiates a monitoring session for the resource consumptions of a
	 * particular resource spreader
	 * 
	 * @param toMonitor
	 *            the resource spreader to be monitored
	 * @param aSecond
	 *            the amount of ticks it takes to get to one second in the
	 *            current configuration of the simulation, if this should be
	 *            below 1 then the monitor consumption class should not be used
	 */
	public MonitorConsumption(final ResourceSpreader toMonitor, final long aSecond) {
		this.toMonitor = toMonitor;
		totalProcessed = toMonitor.getTotalProcessed();
		this.aSecond = aSecond;
		subscribe(aSecond);
	}

	/**
	 * the amount of processing done in a the past day (this is a rolling day
	 * always assumed to start a day before this function was called)
	 * 
	 * @return the processing done in the past day
	 */
	public double getSubDayProcessing() {
		return subDayProcessing;
	}

	/**
	 * the amount of processing done in a the past hour (this is a rolling hour
	 * always assumed to start a hour before this function was called)
	 * 
	 * @return the processing done in the past hour
	 */
	public double getSubHourProcessing() {
		return subHourProcessing;
	}

	/**
	 * the amount of processing done in a the past second (this is a rolling
	 * second always assumed to start a second before this function was called)
	 * 
	 * @return the processing done in the past second
	 */
	public double getSubSecondProcessing() {
		return subSecondProcessing;
	}

	/**
	 * Data collector function that updates all processing data records and
	 * throws out the too old records as well.
	 */
	@Override
	public void tick(final long fires) {
		final SpreadingRecord current = new SpreadingRecord();
		current.timestamp = fires;
		current.totalProcessed = toMonitor.getTotalProcessed();
		subSecondProcessing = current.totalProcessed - totalProcessed;
		totalProcessed = current.totalProcessed;
		subHourRecords.add(current);
		while (subHourRecords.peek().timestamp + 3600 * aSecond < fires) {
			// 60*60*1000
			// Over the past hour
			subDayRecords.add(subHourRecords.poll());
			while (subDayRecords.peek().timestamp + 86400 * aSecond < fires) {
				// Over the past day
				subDayRecords.poll();
			}
		}
		subHourProcessing = totalProcessed - subHourRecords.peek().totalProcessed;
		try {
			subDayProcessing = totalProcessed - subDayRecords.peek().totalProcessed;
		} catch (NullPointerException ne) {
			// No records over an hour
			subDayProcessing = subHourProcessing;
		}
	}

	/**
	 * allows the monitoring to be terminated at any arbitrary point of time.
	 * The processing data reports are not going to be update anymore and they
	 * are going to be always valid for the time instance where the cancel
	 * operation was called.
	 */
	public void cancelMonitoring() {
		unsubscribe();
	}
} public class ConstantConsumptionModel extends PowerState.ConsumptionModel {
	@Override
	protected double evaluateConsumption(final double load) {
		return myPowerState.getMinConsumption();
	}
} public class PowerState {
	/**
	 * By sub-classing this class one can define arbitrary consumption models.
	 * 
	 * @author "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems, MTA SZTAKI (c) 2014"
	 *
	 */
	public static abstract class ConsumptionModel {
		/**
		 * backlink to the power state with useful data to determine the
		 * consumption model
		 */
		protected final PowerState myPowerState = null;

		/**
		 * calculates the instantaneous power draw of a resource spreader under
		 * a particular load.
		 * 
		 * @param load
		 *            the load in the range of [0..1] of the resource spreader
		 * @return the estimated instantaneous power draw of the spreader in W.
		 */
		protected abstract double evaluateConsumption(final double load);
	}

	/**
	 * allows notifications before the consumption characteristics would change.
	 * Useful to update instantaneous power draw values before a power
	 * characteristic change (like going from turboboost-&gt;using all cpu cores in
	 * modern processors)
	 * 
	 * @author "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems, MTA SZTAKI (c) 2014"
	 *
	 */
	public interface PowerCharacteristicsChange {
		/**
		 * this function is called when there is a powerstate characteristic
		 * change on the powerstate onMe.
		 * 
		 * @param onMe
		 *            with this parameter the change event propagates the power
		 *            state for which the change is happening
		 */
		void prePowerChangeEvent(final PowerState onMe);
	}

	/**
	 * The minimum instantaneous power draw in W
	 */
	private double minConsumption;
	/**
	 * The power draw range in Watts (the maximum possible offset from minimum
	 * power draw)
	 */
	private double consumptionRange;
	/**
	 * Records the last time in ticks when the power characteristics change was
	 * propagated to listeners
	 */
	private long pastNotification = -1;
	/**
	 * The current consumption model (which transforms the load to wattage based
	 * on the power state's charactheristics (e.g., mincons/range)
	 */
	private final ConsumptionModel model;
	/**
	 * the list of those objects who are prepared to handle power state changes
	 */
	private final ArrayList<PowerCharacteristicsChange> listeners = new ArrayList<PowerState.PowerCharacteristicsChange>();

	/**
	 * Allow the creation of a new power state object with initial power state
	 * characteristics.
	 * 
	 * @param minConsumption
	 *            The minimum consumption that could be reported by this
	 *            powerstate (e.g. idle power if we define a Physical Machine's
	 *            powerstate) - in watts
	 * @param consumptionRange
	 *            The maximum offset of the consumption that could be still
	 *            reported by this power state object. (e.g., the max-idle power
	 *            if we define a Physical Machine) - in watts
	 * @param modelclass
	 *            Defines the consumption model which transforms a load value
	 *            and is capable of outputting arbitrary instantaneous power
	 *            draw estimates between minConsumption and
	 *            minConsumption+consumptionRange
	 * @throws InstantiationException
	 *             if the modelclass is not existent
	 * @throws IllegalAccessException
	 *             if the modelclass is not accessible
	 * @throws NoSuchFieldException
	 *             if the modelclass does not have a myPowerState field (this is
	 *             most likely impossible as all subclasses will have that field
	 *             because of the baseclass)
	 * @throws SecurityException
	 *             if visibility changes are not possible to do on the
	 *             myPowerState field
	 */
	public PowerState(final double minConsumption, final double consumptionRange,
			Class<? extends ConsumptionModel> modelclass)
					throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
		this.minConsumption = minConsumption;
		this.consumptionRange = consumptionRange;
		model = modelclass.newInstance();
		Field f = ConsumptionModel.class.getDeclaredField("myPowerState");
		f.setAccessible(true);
		f.set(model, this);
		f.setAccessible(false);
	}

	/**
	 * determines the current power draw of the system given that it has the
	 * load specified in the parameter
	 * 
	 * @param load
	 *            for which load value should we use the consumption model to
	 *            determine the instantaneous power draw of the system. the load
	 *            value is expected to be within the range of [0..1]
	 * @return the estimated instantaneous power draw value in watts
	 */
	public double getCurrentPower(final double load) {
		if (load > 1.01 || load < -0.01) {
			throw new IllegalStateException("Received an out of range load evaluation request:" + load);
		}
		return model.evaluateConsumption(load);
	}

	/**
	 * allows read access to the minconsumption field
	 * 
	 * @return the minconsumption of this power state
	 */
	public double getMinConsumption() {
		return minConsumption;
	}

	/**
	 * Allows read access to the consumption range field
	 * 
	 * @return the consumption range of this power state
	 */
	public double getConsumptionRange() {
		return consumptionRange;
	}

	/**
	 * used to send out notifications before any of the power state
	 * characteristics change
	 */
	private void notifyCharacteristisListeners() {
		final long currentTime = Timed.getFireCount();
		if (currentTime != pastNotification) {
			for (PowerCharacteristicsChange l : listeners) {
				l.prePowerChangeEvent(this);
			}
			pastNotification = currentTime;
		}
	}

	/**
	 * Allows to set the minimum consumption for this power state (good for DVFS
	 * and similar behavior). Before the change the power state change listeners
	 * are notified.
	 * 
	 * @param minConsumption
	 *            the new consumption value to be set in W
	 */
	public void setMinConsumption(final double minConsumption) {
		notifyCharacteristisListeners();
		this.minConsumption = minConsumption;
	}

	/**
	 * Allows to set the consumption range for this power state (good for DVFS
	 * and similar behavior). Before the change the power state change listeners
	 * are notified.
	 * 
	 * @param cr
	 *            the new consumption range value to be set in W
	 */
	public void setConsumptionRange(final double cr) {
		notifyCharacteristisListeners();
		this.consumptionRange = cr;
	}

	/**
	 * allows users of this powerstate object to get notifications about power
	 * state characteristics changes
	 * 
	 * @param listener
	 *            the object where the events should be sent
	 */
	public void subscribePowerCharacteristicsChanges(PowerCharacteristicsChange listener) {
		listeners.add(listener);
	}

	/**
	 * if some pary gets uninterested in power state changes this is the way to
	 * cancel event notifications about them
	 * 
	 * @param listener
	 *            the object which no longer needs notification event
	 */
	public void unsubscribePowerCharacteristicsChanges(PowerCharacteristicsChange listener) {
		listeners.remove(listener);
	}

	/**
	 * A convenient and compact way to represent the main characteristics of
	 * this power state. Good for debugging and tracing
	 */
	@Override
	public String toString() {
		return "PowSt(I: " + minConsumption + " C: " + consumptionRange + " " + model.getClass().getName() + ")";
	}
} public class IaaSEnergyMeter extends AggregatedEnergyMeter implements VMManager.CapacityChangeEvent<PhysicalMachine> {
	/**
	 * The IaaSService to be observed with this meter
	 */
	private final IaaSService observed;
	/**
	 * record of the past capacity on the observed IaaSservice (used to
	 * determine in which direction did its capacity change).
	 */
	private ResourceConstraints oldCapacity;

	/**
	 * Allows the construction of a new metering object building on top of the
	 * generic aggregated energy meter concept
	 * 
	 * @param iaas
	 *            the IaaS to be monitored energywise
	 */
	public IaaSEnergyMeter(IaaSService iaas) {
		super(subMeterCreator(iaas.machines));
		observed = iaas;
		observed.subscribeToCapacityChanges(this);
		oldCapacity = observed.getCapacities();
	}

	/**
	 * This function creates a list of PhysicalMachineMeters from a list of
	 * physical machines.
	 * 
	 * @param machines
	 *            the list of machines from which the meter set must be crearted
	 * @return the list of meters
	 */
	private static List<EnergyMeter> subMeterCreator(List<PhysicalMachine> machines) {
		final int machineCount = machines.size();
		ArrayList<EnergyMeter> meters = new ArrayList<EnergyMeter>(machineCount);
		for (int i = 0; i < machineCount; i++) {
			meters.add(new PhysicalMachineEnergyMeter(machines.get(i)));
		}
		return meters;
	}

	/**
	 * manages the changes in size of the infrastructure (e.g. PM additions or
	 * removals) this is important to support dynamic IaaS systems where the
	 * metering results are still properly recorded
	 */
	@Override
	public void capacityChanged(ResourceConstraints newCapacity, List<PhysicalMachine> affectedCapacity) {
		long freq = -1;
		if (isSubscribed()) {
			freq = getFrequency();
			stopMeter();
		}
		if (newCapacity.compareTo(oldCapacity) < 0) {
			// Decreased
			Iterator<? extends EnergyMeter> meters = supervised.iterator();
			while (meters.hasNext()) {
				PhysicalMachineEnergyMeter m = (PhysicalMachineEnergyMeter) meters.next();
				if (affectedCapacity.remove(m.getObserved())) {
					meters.remove();
				}
			}
		} else {
			// Increased
			supervised.addAll(subMeterCreator(affectedCapacity));
		}
		oldCapacity = newCapacity;
		if (freq != -1) {
			startMeter(freq, false);
		}
	}

	/**
	 * Allows to determine what is the
	 * 
	 * @return the observed IaaS system
	 */
	public IaaSService getObserved() {
		return observed;
	}
} public class PhysicalMachineEnergyMeter extends AggregatedEnergyMeter
		implements VMManager.CapacityChangeEvent<ResourceConstraints> {

	/**
	 * The physical machine that is under monitoring
	 */
	private final PhysicalMachine observed;

	/**
	 * instantiates a physical machine meter based on the meter aggregator
	 * concept of DISSECT-CF
	 * 
	 * @param pm
	 *            the physical machine to be metered
	 */
	public PhysicalMachineEnergyMeter(final PhysicalMachine pm) {
		super(Arrays.asList(new EnergyMeter[] { new DirectEnergyMeter(pm),
				new DirectEnergyMeter(pm.localDisk.diskinbws), new DirectEnergyMeter(pm.localDisk.diskoutbws),
				new DirectEnergyMeter(pm.localDisk.inbws), new DirectEnergyMeter(pm.localDisk.outbws) }));
		observed = pm;
	}

	/**
	 * ensures the newly started metering will consider capacity changes in the
	 * PM (e.g. DVFS like behavior)
	 */
	@Override
	public boolean startMeter(long interval, boolean dropPriorReading) {
		boolean returner = super.startMeter(interval, dropPriorReading);
		observed.subscribeToCapacityChanges(this);
		return returner;
	}

	/**
	 * terminates the metering session for the aggregation and ensures that we
	 * no longer consider capacity changes for the PM as they don't need to be
	 * reflected in the metering results anymore
	 */
	@Override
	public void stopMeter() {
		super.stopMeter();
		observed.unsubscribeFromCapacityChanges(this);
	}

	/**
	 * readjusts the meter (and thus evaluate actual consumption values) if the
	 * capacity of the metered physical machine changes
	 */
	@Override
	public void capacityChanged(ResourceConstraints newCapacity, List<ResourceConstraints> affectedCapacity) {
		readjustMeter();
	}

	/**
	 * allows determining which PM is under observation
	 * 
	 * @return the metered pm
	 */
	public PhysicalMachine getObserved() {
		return observed;
	}
} public class SimpleVMEnergyMeter extends PhysicalMachineEnergyMeter {
	/**
	 * Cannot be created for unallocated VMs!
	 * 
	 * @param vm
	 */
	public SimpleVMEnergyMeter(final VirtualMachine vm) {
		super(vm.getResourceAllocation().getHost());
	}

	/**
	 * cons(PM)/NumVMs(PM)
	 */
	@Override
	public double getTotalConsumption() {
		return super.getTotalConsumption() / getObserved().numofCurrentVMs();
	}
} public class IaaSService implements VMManager<IaaSService, PhysicalMachine>, PhysicalMachine.StateChangeListener {

	/**
	 * This class represents a generic error that occurred during the operation of
	 * the IaaS service.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	public static class IaaSHandlingException extends Exception {

		private static final long serialVersionUID = 2580735547805541590L;

		/**
		 * Only a generic constructor is defined so a textual message can be propagated
		 * around the system
		 * 
		 * @param s
		 *            the reason this exception was raised
		 */
		public IaaSHandlingException(final String s) {
			super(s);
		}

		public IaaSHandlingException(final String s, final Throwable ex) {
			super(s, ex);
		}
	}

	/**
	 * The actual writable list of the machine set maintained behind this
	 * IaaSService
	 * 
	 * WARNING: The order of internal machines is not guaranteed
	 */
	private final ArrayList<PhysicalMachine> internalMachines = new ArrayList<PhysicalMachine>();
	/**
	 * The actual writable list of the running machine set maintained behind this
	 * IaaSService
	 * 
	 * WARNING: The order of internal running machines is not guaranteed
	 */
	private final ArrayList<PhysicalMachine> internalRunningMachines = new ArrayList<PhysicalMachine>();

	/**
	 * publicly available read only version of the internal machines field
	 */
	public final List<PhysicalMachine> machines = Collections.unmodifiableList(internalMachines);
	/**
	 * publicly available read only version of the internal running machines field
	 */
	public final List<PhysicalMachine> runningMachines = Collections.unmodifiableList(internalRunningMachines);

	/**
	 * the total capacity of all machines in this iaas service, for use only
	 * internally in the IaaS service class
	 */
	private AlterableResourceConstraints totalCapacity = AlterableResourceConstraints.getNoResources();
	/**
	 * the total capacity to be reported for external users. This field propagates
	 * the totalCapacity field. Keep in mind that the capacity reported by this
	 * field could change without notification.
	 */
	private ResourceConstraints publicTCap = new UnalterableConstraintsPropagator(totalCapacity);
	/**
	 * the capacity of the machines that are actually running in the system - this
	 * is for internal use only again
	 */
	private AlterableResourceConstraints runningCapacity = AlterableResourceConstraints.getNoResources();
	/**
	 * The capacity of the running machines to be reported externally. This is
	 * implemented with a propagator thus changes in runningcapacity will be
	 * immediately reflected here as well without notification.
	 */
	private ResourceConstraints publicRCap = new UnalterableConstraintsPropagator(runningCapacity);

	/**
	 * event handler for capacity changes in terms of added/removed physical
	 * machines
	 */
	private final StateDependentEventHandler<CapacityChangeEvent<PhysicalMachine>, List<PhysicalMachine>> capacityListenerManager = new StateDependentEventHandler<CapacityChangeEvent<PhysicalMachine>, List<PhysicalMachine>>(
			new SingleNotificationHandler<CapacityChangeEvent<PhysicalMachine>, List<PhysicalMachine>>() {
				@Override
				public void sendNotification(CapacityChangeEvent<PhysicalMachine> onObject,
						List<PhysicalMachine> pmsetchange) {
					onObject.capacityChanged(totalCapacity, pmsetchange);
				}
			});

	/**
	 * The list of repositories under direct control of this IaaS service - this is
	 * for internal purposes the list is writeable
	 * 
	 * The order of internal repositories is not guaranteed
	 */
	private final ArrayList<Repository> internalRepositories = new ArrayList<Repository>();
	/**
	 * the read only list of all repositories in the system
	 */
	public final List<Repository> repositories = Collections.unmodifiableList(internalRepositories);

	/**
	 * the VM scheduler applied by this IaaSservice object
	 */
	public final Scheduler sched;
	/**
	 * the PM scheduler applied by this IaaSService object
	 */
	public final PhysicalMachineController pmcontroller;

	/**
	 * Constructs an IaaS service object directly. The VM and PM schedulers for this
	 * IaaS service will be created during the creation of the IaaSService itself.
	 * This ensures that users cannot alter the link between the IaaSService and the
	 * various schedulers. The <i>exceptions</i> are thrown because reflection is
	 * used to create the scheduler objects.
	 * 
	 * @param s
	 *            class of the VM scheduler to be used
	 * @param c
	 *            class of the PM scheduler to be used
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	public IaaSService(Class<? extends Scheduler> s, Class<? extends PhysicalMachineController> c)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
			NoSuchMethodException, SecurityException {
		sched = s.getConstructor(IaaSService.class).newInstance(this);
		pmcontroller = c.getConstructor(IaaSService.class).newInstance(this);
	}

	/**
	 * Not implemented! Will allow migrating VMs across IaaSServices.
	 */
	@Override
	public void migrateVM(final VirtualMachine vm, final IaaSService target) {
	}

	/**
	 * Determines if the VM is hosted locally in one of the physical machines of
	 * this IaaSServie
	 * 
	 * @param vm
	 *            the VM to be checked
	 * @return the PM that hosts the VM
	 * @throws NoSuchVMException
	 *             if the VM is not hosted by any of the PMs in the system
	 */
	private PhysicalMachine checkVMHost(final VirtualMachine vm) throws NoSuchVMException {
		ResourceAllocation ra = vm.getResourceAllocation();
		PhysicalMachine host;
		if (!(ra != null && runningMachines.contains(host = ra.getHost()))) {
			throw new NoSuchVMException("This VM is not run by any of the managed PMs in this IaaS service");
		}
		return host;
	}

	/**
	 * NOT IMPLEMENTED! Reallocates the VM's resources according to the newresources
	 * on the host of the VM.
	 */
	@Override
	public void reallocateResources(VirtualMachine vm, ResourceConstraints newresources)
			throws NoSuchVMException, VMManagementException {
		checkVMHost(vm).reallocateResources(vm, newresources);
	}

	/**
	 * Allows the request of multiple VMs without propagating any scheduling
	 * constraints.
	 * 
	 * @param va
	 *            the VA to be used as the disk of the VM
	 * @param rc
	 *            the resource requirements of the future VM
	 * @param vaSource
	 *            the repository that currently stores the VA
	 * @param count
	 *            the number of VMs that this request should be returning with
	 * @return the list of VMs created by the call (please note the VMs returned
	 *         might never actually get running, if the PMs are always blocked by
	 *         some other activities, or if they go to NONSERVABLE state)
	 * @throws VMManagementException
	 *             if there are no pms that could run the VMs. or if the request is
	 *             too big to be hosted across the complete infrastructure
	 * @throws NetworkNode.NetworkException
	 *             if there are network connectivity problems within the
	 *             infrastructure
	 */
	public VirtualMachine[] requestVM(final VirtualAppliance va, final ResourceConstraints rc,
			final Repository vaSource, final int count) throws VMManagementException, NetworkNode.NetworkException {
		return requestVM(va, rc, vaSource, count, null);
	}

	/**
	 * Allows the request of multiple VMs.
	 * 
	 * @param va
	 *            the VA to be used as the disk of the VM
	 * @param rc
	 *            the resource requirements of the future VM
	 * @param vaSource
	 *            the repository that currently stores the VA
	 * @param count
	 *            the number of VMs that this request should be returning with
	 * @param schedulingConstraints
	 *            The VM scheduler dependent additional requirements for the newly
	 *            requested VMs (e.g. please go for a specific host etc.) For
	 *            understanding what you can send here please have a look at the
	 *            documentation of the particular VM scheduler in question.
	 * @return the list of VMs created by the call (please note the VMs returned
	 *         might never actually get running, if the PMs are always blocked by
	 *         some other activities, or if they go to NONSERVABLE state)
	 * @throws VMManagementException
	 *             if there are no pms that could run the VMs. or if the request is
	 *             too big to be hosted across the complete infrastructure
	 * @throws NetworkNode.NetworkException
	 *             if there are network connectivity problems within the
	 *             infrastructure
	 */
	@Override
	public VirtualMachine[] requestVM(VirtualAppliance va, ResourceConstraints rc, Repository vaSource, int count,
			HashMap<String, Object> schedulingConstraints)
			throws hu.mta.sztaki.lpds.cloud.simulator.iaas.VMManager.VMManagementException, NetworkException {
		if (machines.isEmpty()) {
			throw new VMManagementException("There are no phyisical machines that can run VMs!");
		}
		VirtualMachine[] vms = new VirtualMachine[count];
		for (int i = 0; i < count; i++) {
			vms[i] = new VirtualMachine(va);
		}
		sched.scheduleVMrequest(vms, rc, vaSource, schedulingConstraints);
		return vms;
	}

	/**
	 * Requesting the destruction of a VM in a DESTROYED state will dequeue the VM
	 * from the scheduler's request queue. If the VM was not requested from this
	 * IaaSService then a nosuchvmexception is thrown.
	 */
	@Override
	public void terminateVM(final VirtualMachine vm, final boolean killTasks)
			throws NoSuchVMException, VMManagementException {
		if (VirtualMachine.State.DESTROYED.equals(vm.getState())) {
			// The VM is still under scheduling, the queue needs to be cleared
			if (!sched.dropVMrequest(vm)) {
				throw new NoSuchVMException("This VM is not queued in this IaaS service");
			}
			return;
		}
		checkVMHost(vm).terminateVM(vm, killTasks);
	}

	/**
	 * lists all VMs running or requested (and queued at a VM scheduler) from the
	 * IaaSservice
	 */
	@Override
	public Collection<VirtualMachine> listVMs() {
		final ArrayList<VirtualMachine> completeList = new ArrayList<VirtualMachine>();
		int imLen = internalMachines.size();
		for (int i = 0; i < imLen; i++) {
			completeList.addAll(internalMachines.get(i).listVMs());
		}
		completeList.addAll(sched.getQueuedVMs());
		return completeList;
	}

	/**
	 * This function allows the IaaS to grow in size with a single PM
	 * 
	 * @param pm
	 *            the new physical machine to be utilized within the system
	 */
	public void registerHost(final PhysicalMachine pm) {
		bulkHostRegistration(Collections.singletonList(pm));
	}

	/**
	 * This function allows rapid registration of several PMs
	 * 
	 * @param newPMs
	 *            the list of PMs to be registered
	 */
	public void bulkHostRegistration(final List<PhysicalMachine> newPMs) {
		internalMachines.addAll(newPMs);
		final int size = newPMs.size();
		final ResourceConstraints[] caps = new ResourceConstraints[size];
		double maxPcPP = totalCapacity.getRequiredProcessingPower();
		for (int i = 0; i < size; i++) {
			final PhysicalMachine pm = newPMs.get(i);
			if (PhysicalMachine.State.RUNNING.equals(pm.getState())) {
				stateChanged(pm, PhysicalMachine.State.RUNNING, PhysicalMachine.State.RUNNING);
			}
			pm.subscribeStateChangeEvents(this);
			caps[i] = pm.getCapacities();
			maxPcPP = Math.max(caps[i].getRequiredProcessingPower(), maxPcPP);
		}
		totalCapacity.add(caps);
		totalCapacity.scaleProcessingPower(maxPcPP / totalCapacity.getRequiredProcessingPower());
		capacityListenerManager.notifyListeners(newPMs);
	}

	/**
	 * Really deregisters a PM from the list of PMs.
	 * 
	 * @param pm
	 *            the PM to be deregistered
	 */
	private void realDeregistration(PhysicalMachine pm) {
		pm.unsubscribeStateChangeEvents(this);
		ResourceConstraints caps = pm.getCapacities();
		final double suspectedmax = caps.getRequiredProcessingPower();
		totalCapacity.subtract(caps);
		if (totalCapacity.getRequiredProcessingPower() == suspectedmax) {
			final int pms = internalMachines.size();
			double maxPcPP = 0;
			for (int i = 0; i < pms; i++) {
				maxPcPP = Math.max(maxPcPP, internalMachines.get(i).getCapacities().getRequiredProcessingPower());
			}
			totalCapacity.scaleProcessingPower(maxPcPP / suspectedmax);
		}
		capacityListenerManager.notifyListeners(Collections.singletonList(pm));
	}

	/**
	 * This function allows the IaaS to reduce in size. <br/>
	 * This function might migrate VMs from the deregistered host to ones remaining
	 * in the system. If the deregistered host contains VMs that cannot be migrated,
	 * or there is nowhere to migrate the VMs then the function throws an exception.
	 * 
	 * Currently there is no migration implemented!
	 * 
	 * @param pm
	 *            the physical machine to be dropped from the control of the system
	 */
	public void deregisterHost(final PhysicalMachine pm) throws IaaSHandlingException {
		if (ArrayHandler.removeAndReplaceWithLast(internalMachines, pm)) {
			if (pm.isRunning()) {
				ArrayHandler.removeAndReplaceWithLast(internalRunningMachines, pm);
				if (pm.isHostingVMs()) {
					AlterableResourceConstraints needed = new AlterableResourceConstraints(pm.getCapacities());
					needed.subtract(pm.freeCapacities);
					PhysicalMachine receiver = null;
					for (PhysicalMachine curr : machines) {
						if (needed.compareTo(curr.freeCapacities) <= 0) {
							receiver = curr;
							break;
						}
					}
					if (receiver == null) {
						throw new IaaSHandlingException(
								"You cannot deregister the host before all its VMs are terminated, or if all VMs can be migrated to somewhere else");
					}
					try {
						pm.subscribeStateChangeEvents(new PhysicalMachine.StateChangeListener() {
							@Override
							public void stateChanged(PhysicalMachine pm, State oldState, State newState) {
								if (newState.equals(PhysicalMachine.State.OFF)) {
									realDeregistration(pm);
								}
							}
						});
						if (receiver.isRunning()) {
							pm.switchoff(receiver);
						} else {
							final PhysicalMachine rcopy = receiver;
							receiver.subscribeStateChangeEvents(new PhysicalMachine.StateChangeListener() {
								@Override
								public void stateChanged(PhysicalMachine pm, State oldState, State newState) {
									try {
										if (newState.equals(PhysicalMachine.State.RUNNING)) {
											pm.switchoff(rcopy);
										}
									} catch (VMManagementException e) {
										e.printStackTrace();
									} catch (NetworkNode.NetworkException e) {
										e.printStackTrace();
									}
								}
							});
							receiver.turnon();
						}
					} catch (VMManagementException e) {
						throw new IaaSHandlingException("Some error has happened during the switchoff procedure", e);
					} catch (NetworkNode.NetworkException e) {
						throw new IaaSHandlingException("All PMs should be able to connect to each other in the IaaS",
								e);
					}
					return;
				}
			}
			realDeregistration(pm);
		} else {
			throw new IaaSHandlingException("No such registered physical machine");
		}
	}

	/**
	 * This function allows the IaaS to grow its storage capacities
	 * 
	 * @param r
	 *            the new repository to be utilized within the system
	 */
	public void registerRepository(final Repository r) {
		internalRepositories.add(r);
		try {
			r.setState(NetworkNode.State.RUNNING);
		} catch (NetworkException e) {
			// Should not happen
		}
	}

	/**
	 * This function allows the IaaS to reduce its storage capacities.
	 * 
	 * This function might transfer contents from the deregistered repository to
	 * ones remaining in the system. If the deregistered repository contains storage
	 * objects that cannot be transferred, or there is nowhere to transfer a few
	 * storage objects then the function throws an exception.
	 * 
	 * Currently there is no transfer implemented!
	 * 
	 * @param r
	 *            the repository to be dropped from the control of the system
	 */
	public void deregisterRepository(final Repository r) throws IaaSHandlingException {
		ArrayHandler.removeAndReplaceWithLast(internalRepositories, r);
	}

	/**
	 * returns with the total capacities of this service (cumulative value for all
	 * its PMs)
	 */
	public ResourceConstraints getCapacities() {
		return publicTCap;
	}

	/**
	 * returns with the total running capacities of this service (cumulative value
	 * for all its PMs that are in a running state)
	 */
	public ResourceConstraints getRunningCapacities() {
		return publicRCap;
	}

	/**
	 * get notified about capacity changes (PM additions/removals)
	 * 
	 * This call is propagated to StateDependentEventHandler.
	 */
	@Override
	public void subscribeToCapacityChanges(final CapacityChangeEvent<PhysicalMachine> e) {
		capacityListenerManager.subscribeToEvents(e);
	}

	/**
	 * cancel the notifications about capacity changes (PM additions/removals)
	 * 
	 * This call is propagated to StateDependentEventHandler.
	 */
	@Override
	public void unsubscribeFromCapacityChanges(final CapacityChangeEvent<PhysicalMachine> e) {
		capacityListenerManager.unsubscribeFromEvents(e);
	}

	/**
	 * A function to determine if a host is within the premises of this IaaSService.
	 * 
	 * @param pm
	 *            the host in question
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the host is part of the IaaS
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	public boolean isRegisteredHost(PhysicalMachine pm) {
		return internalMachines.contains(pm);
	}

	/**
	 * Provides a convenient way to debug the IaaS.
	 */
	@Override
	public String toString() {
		return "IaaS(Machines(" + machines + "), Repositories(" + repositories + "))";
	}

	/**
	 * Implements the PhysicalMachine's state change listener to manage the
	 * internalRunningMachines list.
	 */
	@Override
	public void stateChanged(PhysicalMachine pm, State oldState, State newState) {
		switch (newState) {
		case RUNNING:
			internalRunningMachines.add(pm);
			runningCapacity.singleAdd(pm.getCapacities());
			return;
		default:
			if (oldState.equals(PhysicalMachine.State.RUNNING)) {
				internalRunningMachines.remove(pm);
				runningCapacity.subtract(pm.getCapacities());
			}
		}
	}
} public class PhysicalMachine extends MaxMinProvider implements VMManager<PhysicalMachine, ResourceConstraints> {

	/**
	 * This is the default length for how long a resource allocation will be kept
	 * before it becomes invalid.
	 * 
	 * It is specified in ticks.
	 */
	public static final int defaultAllocLen = 1000;
	/**
	 * This is the recommended length for how long a resource allocation will be
	 * kept before it becomes invalid in case the allocation is made for a VM
	 * migration.
	 * 
	 * It is specified in ticks.
	 */
	public static final int migrationAllocLen = 1000000;
	/**
	 * Amount of processing to be done if the PM need to be underutilized. This
	 * constant is used for calculating the emulation of on and off operations if
	 * they are specified with single delays in the PM's constructor.
	 */
	public static final double smallUtilization = 0.001;

	/**
	 * Represents the possible states of the physical machines modeled in the system
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	public static enum State {
		/**
		 * The machine is completely switched off, minimal consumption is recorded.
		 */
		OFF,
		/**
		 * The machine is under preparation to serve VMs. Some consumption is recorded
		 * already.
		 */
		SWITCHINGON,
		/**
		 * The machine is currently serving VMs. The machine and its VMs are consuming
		 * energy.
		 */
		RUNNING,
		/**
		 * The machine is about to be switched off. It no longer accepts VM requests but
		 * it still consumes energy.
		 */
		SWITCHINGOFF
	};

	/**
	 * These are the PM states which are either leading to running or already
	 * running.
	 */
	public static final EnumSet<State> ToOnorRunning = EnumSet.of(State.SWITCHINGON, State.RUNNING);
	/**
	 * These are the PM states which are either leading to off or already off.
	 */
	public static final EnumSet<State> ToOfforOff = EnumSet.of(State.SWITCHINGOFF, State.OFF);
	/**
	 * This is the list of PM states that mostly consume energy
	 */
	public static final EnumSet<State> StatesOfHighEnergyConsumption = EnumSet.of(State.SWITCHINGON, State.RUNNING,
			State.SWITCHINGOFF);

	/**
	 * Defines the minimal interface for listeners on PM state changes.
	 * 
	 * @author "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems,
	 *         MTA SZTAKI (c) 2012"
	 *
	 */
	public interface StateChangeListener {
		/**
		 * This function is called by the PM on subscribed objects when a PM's state
		 * changes. To simplify the implementation of the receiver objects, this state
		 * changed function actually propagates all state infromation (pre and post) as
		 * well as the physical machine's reference which just went through the state
		 * change.
		 * 
		 * @param pm
		 *            the physical machine that is involved in the state change
		 * @param oldState
		 *            the state the PM was in before this state change event was
		 *            delivered
		 * @param newState
		 *            the new state the PM will be in after the event is complete
		 */
		void stateChanged(PhysicalMachine pm, State oldState, State newState);
	}

	/**
	 * This class is strongly connected with the physical machine's class, the two
	 * are collaborating to allow a fluid and minimal hassle operation of allocating
	 * resources on a PM. This allocation is then later on expected to be used by
	 * virtual machines to use.
	 * 
	 * Before resource allocations are used they are allocated for a fixed amount of
	 * time. Thus if a user forgets about the allocation, the PMs resources are not
	 * occupied forever.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013" "Gabor Kecskemeti, Laboratory of Parallel and
	 *         Distributed Systems, MTA SZTAKI (c) 2012"
	 */
	public class ResourceAllocation extends DeferredEvent {
		/**
		 * The resource set that is virtually offered to the VM that uses this
		 * allocation.
		 */
		public final ResourceConstraints allocated;
		/**
		 * The resource set that is actually reserved on the PM. If
		 * allocated&gt;realAllocated, then the VM might get resources up to allocated but
		 * only when the PM is not over-committed.
		 */
		private final ResourceConstraints realAllocated;
		/**
		 * The VM that utilizes the allocation in question
		 */
		private VirtualMachine user = null;
		/**
		 * The index of this allocation in the allocation list located in the PM. Allows
		 * rapid cleaning of the allocation list.
		 */
		private final int myPromisedIndex;
		/**
		 * If the resource allocation is not used before its expiry time then this is
		 * going to be true!
		 */
		private boolean swept = false;

		/**
		 * The constructor of the resource allocation to be used by the physical machine
		 * only!
		 * 
		 * @param realAlloc
		 *            defines the actually reserved resources with the allocation
		 * @param alloc
		 *            defines the promised resources for the user
		 * @param until
		 *            defines the duration in ticks for which the allocation will be
		 *            kept for the user. This period is useful to allow advanced
		 *            scheduling operations where some resources are occupied in advance
		 *            in order to ensure rapid VM creation.
		 */
		private ResourceAllocation(final ResourceConstraints realAlloc, final ResourceConstraints alloc,
				final int until) {
			super(until);
			allocated = alloc;
			realAllocated = realAlloc;
			int prLen = promisedResources.length;
			int i = 0;
			for (i = 0; i < prLen && promisedResources[i] != null; i++)
				;
			if (i == prLen) {
				ResourceAllocation[] alls = new ResourceAllocation[prLen * 2];
				System.arraycopy(promisedResources, 0, alls, 0, prLen);
				promisedResources = alls;
				promisedResources[prLen] = this;
				myPromisedIndex = prLen;
			} else {
				promisedResources[i] = this;
				myPromisedIndex = i;
			}
			promisedCapacities.singleAdd(realAllocated);
			internalReallyFreeCaps.subtract(realAllocated);
			promisedAllocationsCount++;
		}

		/**
		 * This function is called by deferred event when the allocation is expired. The
		 * allocation expiry event is only happening if there are no VMs that use the
		 * allocation by the time the expiry period is over.
		 * 
		 * <i>REMARK:</i> As expiry is considered a problem in most systems, this is
		 * actually printing out to standard error - as the error is not critical and
		 * there would be no way to propagate the error to the entity who issued the
		 * allocation.
		 */
		@Override
		protected void eventAction() {
			System.err.println("Warning! Expiring resource allocation.");
			swept = true;
			promisedCapacityUpdater();
		}

		/**
		 * updates the PM's respective fields about resource availability
		 */
		private void promisedCapacityUpdater() {
			promisedResources[myPromisedIndex] = null;
			promisedAllocationsCount--;
			if (promisedAllocationsCount == 0) {
				promisedCapacities.subtract(promisedCapacities);
			} else {
				promisedCapacities.subtract(realAllocated);
			}
			if (isUnUsed()) {
				internalReallyFreeCaps.singleAdd(realAllocated);
			}
		}

		/**
		 * if a resource allocation is no longer needed (e.g. because another allocation
		 * was used for the same VM), then this way one can not only cancel the
		 * allocation but also ensure that the expiry event is not fired.
		 */
		public void cancel() {
			if (!isCancelled()) {
				super.cancel();
				promisedCapacityUpdater();
			}
		}

		/**
		 * To complete the allocation process the VM must be told to use a particular
		 * allocation (e.g. in its migration or starup calls). The VM then automatically
		 * tells this resource allocation object to finalize the allocation process by
		 * calling this use function.
		 * 
		 * This function subscribes to the VM's state change events in order to ensure
		 * that VMs that are not running are not really using resources from the PM.
		 * 
		 * <i>WARNING:</i> this function is to be used by the VM only as the VM knows
		 * for what operation it needs to use the allocation.
		 * 
		 * @param vm
		 *            the virtual machine that will use the allocated resources in the
		 *            future
		 * @throws VMManagementException
		 *             if the allocation passed to the VM is already expired or if the
		 *             allocation is already used by some VM.
		 */
		void use(final VirtualMachine vm) throws VMManagementException {
			if (swept) {
				throw new VMManagementException("Tried to use an already expired allocation");
			}
			if (user == null) {
				user = vm;
				internalAvailableCaps.subtract(realAllocated);
				vms.add(vm);
				decreasingFreeCapacityListenerManager.notifyListeners(Collections.singletonList(realAllocated));
				cancel();
			} else {
				throw new VMManagementException("Tried to use a resource allocation more than once!");
			}
		}

		/**
		 * If a VM no longer needs the resources then this function must be called. As a
		 * result, the PM ensures that the relesed resources are again available to all
		 * interested parties.
		 */
		void release() {
			if (user != null) {
				vms.remove(user);
				completedVMs++;
				internalAvailableCaps.singleAdd(realAllocated);
				internalReallyFreeCaps.singleAdd(realAllocated);
				increasingFreeCapacityListenerManager.notifyListeners(Collections.singletonList(realAllocated));
				user = null;
				swept = true;
			}
		}

		/**
		 * Allows users to determine if the allocation is already taken by a VM.
		 * 
		 * @return
		 *         <ul>
		 *         <li><i>true</i> if there is a VM that is using the resource
		 *         allocation
		 *         <li><i>false</i> otherwise
		 *         </ul>
		 */
		public boolean isUnUsed() {
			return user == null;
		}

		/**
		 * Determines if the allocation is still available to use
		 * 
		 * @return
		 *         <ul>
		 *         <li><i>true</i> if the allocation is still ok to use
		 *         <li><i>false</i>otherwise
		 *         </ul>
		 */
		public boolean isAvailable() {
			return isUnUsed() && !swept;
		}

		/**
		 * Shows basic information about the allocation useful for debugging
		 */
		@Override
		public String toString() {
			return "RA(Canc:" + swept + " " + allocated + ")";
		}

		/**
		 * Allows to determine the Physical Machine the particular allocation is bound
		 * to.
		 * 
		 * @return the physical machine which offers this allocation.
		 */
		public PhysicalMachine getHost() {
			return PhysicalMachine.this;
		}
	}

	/**
	 * This class handles the delays and activites during the power state change
	 * procedures (e.g., switching off/turning on)
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013" "Gabor Kecskemeti, Laboratory of Parallel and
	 *         Distributed Systems, MTA SZTAKI (c) 2014-"
	 */
	public class PowerStateDelayer extends ConsumptionEventAdapter {
		/**
		 * The state that the delayer must switch to after the power state change has
		 * finished its activites.
		 */
		private State newState;
		/**
		 * The list of tasks to do for the particular power state change. These tasks
		 * are expected to represent activities like the boot process.
		 * 
		 * IMPORTANT: For performance reasons, the list is handled from its tailing:
		 * <ul>
		 * <li>The last item is always the amount processing to be done in the upcoming
		 * task of the power change
		 * <li>the penultimate item is always the maximum amount of processing to be
		 * done in a single tick for the above task.
		 * </ul>
		 */
		final TDoubleLinkedList tasksDue;
		/**
		 * when did the particular power state transition start
		 */
		public final long transitionStart;
		/**
		 * What is the actual resource consumption (task) that is executed on the PM's
		 * direct consumer (i.e. the pure machine)
		 */
		ResourceConsumption currentConsumption = null;

		/**
		 * The constructor of the delayer, it allows the specification of the tasks
		 * (that represent the boot/shutdown or similar operations) to be done before
		 * the power state can be achieved.
		 * 
		 * @param tasklist
		 *            the tasks to execute in a serial order before the the specific
		 *            power state can be set.
		 * 
		 *            IMPORTANT: For performance reasons, the list is handled from its
		 *            tailing:
		 *            <ul>
		 *            <li>The last item is always the amount processing to be done in
		 *            the upcoming task of the power change
		 *            <li>the penultimate item is always the maximum amount of
		 *            processing to be done in a single tick for the above task.
		 *            </ul>
		 * @param newPowerState
		 *            the power state to be set after completing all the above tasks.
		 */
		public PowerStateDelayer(final double[] tasklist, final State newPowerState) {
			onOffEvent = this;
			newState = newPowerState;
			tasksDue = new TDoubleLinkedList();
			tasksDue.add(tasklist);
			sendTask();
			transitionStart = Timed.getFireCount();
		}

		/**
		 * this function picks the next item (i.e. always the very last members of the
		 * list) from the tasklist and executes it, the function also ensures that the
		 * powerstatedelayer object will receive a notification once the task is
		 * completed.
		 * 
		 * if there are no further tasks to execute this function even sets the new
		 * power state of the physical machine with the PM's corresponding function.
		 */
		private void sendTask() {
			// Did we finish all the tasks for the state change?
			if (tasksDue.size() == 0) {
				// Mark the completion of the state change
				onOffEvent = null;
				class NetworkCausedStateDelay extends Timed {
					int infiniteLoopTest = 0;

					public NetworkCausedStateDelay() {
						tick(Timed.getFireCount());
					}

					@Override
					public void tick(long fires) {
						try {
							setState(newState);
							// Everything is fine we are good to go.
							unsubscribe();
						} catch (NetworkException nex) {
							// Some network activities stop the transition
							if (infiniteLoopTest++ > 10000) {
								throw new RuntimeException("Unsettling amount of network activity...");
							}
							long whenToCheckNext = localDisk.getLastEvent();
							if (whenToCheckNext > 0) {
								updateFrequency(whenToCheckNext + 1 - fires);
							}
						}
					}
				}
				new NetworkCausedStateDelay();
				return;
			}

			// No we did not, lets send some more to our direct consumer
			final double totalConsumption = tasksDue.removeAt(0);
			final double limit = tasksDue.removeAt(0);
			currentConsumption = new ResourceConsumption(totalConsumption, limit, directConsumer, PhysicalMachine.this,
					this);
			if (!currentConsumption.registerConsumption()) {
				throw new IllegalStateException(
						"PowerStateChange was not successful because resource consumption could not be registered");
			}
		}

		/**
		 * the notification handler when a task from the tasklist is complete
		 * 
		 * this handler actually sends the next task in.
		 */
		@Override
		public void conComplete() {
			sendTask();
		}

		/**
		 * if we receive a cancelled event we consider it as an unexpected behavior and
		 * throw an exception. When enabling faults in the system this behavior might
		 * need to change.
		 * 
		 * @param problematic
		 *            the task that did not succeed
		 */
		@Override
		public void conCancelled(ResourceConsumption problematic) {
			throw new IllegalStateException("Unexpected termination of one of the state changing tasks");
		}

		/**
		 * if there seems to be further operations needed before the particular power
		 * state can be achieved then this function should be called.
		 * 
		 * This function is especially useful to model cases when one state change has
		 * already started but then the user opts for another one before the previous
		 * state change can complete
		 * 
		 * @param tasklist
		 *            the new tasks to be included
		 */
		public void addFurtherTasks(final double[] tasklist) {
			tasksDue.add(tasklist);
		}

		/**
		 * if after the list of tasks are completed we need to reach a different power
		 * state than initially planned then this is the function to go for.
		 * 
		 * This is an optional operation, you only need to call it if the PM started to
		 * go for some other state beforehand that you don't like.
		 * 
		 * @param newState
		 *            the new power state to switch to after all tasks complete
		 */
		public void setNewState(State newState) {
			this.newState = newState;
		}
	}

	/**
	 * the complete resouce set of the pm
	 */
	private final ConstantConstraints totalCapacities;
	/**
	 * the resource set that does not have a VM running on it
	 * 
	 * avaiableCapacities = freeCapacities + promisedCapacities
	 */
	private final AlterableResourceConstraints internalAvailableCaps;
	/**
	 * This is the publicly disclosed set of those resources that are not having a
	 * VM running on them. This field is <b>read only</b>!
	 * 
	 * This field can automatically update between two checks! If you need unaltered
	 * data please make a copy (e.g., new ConstantConstraints(pm.freeCapacities)).
	 */
	public final UnalterableConstraintsPropagator availableCapacities;
	/**
	 * the amount of resources currently allocated but that have no VM assigned to
	 * them
	 */
	private AlterableResourceConstraints promisedCapacities = AlterableResourceConstraints.getNoResources();
	/**
	 * the amount of resources that are not running a VM or not allocated by some
	 * resource allocation
	 */
	private final AlterableResourceConstraints internalReallyFreeCaps;
	/**
	 * This is the publicly disclosed set of those resources that are not even
	 * having an allocation. This field is <b>read only</b>!
	 * 
	 * This field can automatically update between two checks! If you need unaltered
	 * data please make a copy (e.g., new ConstantConstraints(pm.freeCapacities)).
	 */
	public final UnalterableConstraintsPropagator freeCapacities;
	/**
	 * the internal disk of the physical machine. this field is also used to
	 * represent the PM's network connections as the disk is represented with the
	 * repository interface.
	 */
	public final Repository localDisk;
	/**
	 * this is the array of resource allocations which contain all not yet
	 * used/expired resource allocations.
	 * 
	 * This array might contain null values in between two resourceallocation
	 * objects.
	 */
	private ResourceAllocation[] promisedResources = new ResourceAllocation[2];
	/**
	 * the amount of resource allocations in the promisedResources array.
	 */
	private int promisedAllocationsCount = 0;

	/**
	 * The current state of the PM
	 */
	private State currentState = null;
	/**
	 * the tasks to do when turning the PM on. The format of the array is documented
	 * in the powerstatedelayer class.
	 */
	private final double[] onTransition;
	/**
	 * the tasks to do when switching the PM off. The format of the array is
	 * documented in the powerstatedelayer class.
	 */
	private final double[] offTransition;
	/**
	 * around how many ticks the PM is estimated to run the tasks in the
	 * onTransition array.
	 */
	private final long onDelayEstimate;
	/**
	 * around how many ticks the PM is estimated to run the tasks in the
	 * offTransition array.
	 */
	private final long offDelayEstimate;

	/**
	 * Mapping between the various PM states and its representative CPU/memory power
	 * behaviors.
	 */
	private final Map<String, PowerState> hostPowerBehavior;
	/**
	 * the manager of the PM's state change notifications.
	 */
	private final StateDependentEventHandler<StateChangeListener, Pair<State, State>> stateListenerManager = new StateDependentEventHandler<PhysicalMachine.StateChangeListener, Pair<State, State>>(
			new SingleNotificationHandler<StateChangeListener, Pair<State, State>>() {
				@Override
				public void sendNotification(final StateChangeListener onObject, final Pair<State, State> states) {
					onObject.stateChanged(PhysicalMachine.this, states.getLeft(), states.getRight());
				}
			});

	/**
	 * the set of currently running virtual machines on this PM
	 */
	private final HashSet<VirtualMachine> vms = new HashSet<VirtualMachine>(); // current
	/**
	 * the publicly available, read only set of currently running virtual machines
	 * on this PM
	 */
	public final Set<VirtualMachine> publicVms = Collections.unmodifiableSet(vms);
	/**
	 * the number of VMs that were using resources from this PM at any time of the
	 * PM's existence
	 */
	private long completedVMs = 0; // Past
	/**
	 * The currently operating state change handler - this field actually shows if a
	 * state change is on the way.
	 * 
	 * in order to be really consistent, the field is directly managed by the
	 * powerstatedelayer class.
	 */
	private PowerStateDelayer onOffEvent = null;
	/**
	 * this notification handler is used to send out events when some of the PM's
	 * resources are getting available for others to use
	 */
	private final StateDependentEventHandler<CapacityChangeEvent<ResourceConstraints>, List<ResourceConstraints>> increasingFreeCapacityListenerManager = new StateDependentEventHandler<VMManager.CapacityChangeEvent<ResourceConstraints>, List<ResourceConstraints>>(
			new SingleNotificationHandler<CapacityChangeEvent<ResourceConstraints>, List<ResourceConstraints>>() {
				@Override
				public void sendNotification(final CapacityChangeEvent<ResourceConstraints> onObject,
						final List<ResourceConstraints> recentlyFreedUpResources) {
					onObject.capacityChanged(freeCapacities, recentlyFreedUpResources);
				}
			});
	/**
	 * this notification handler is used to send out events when some of the PM's
	 * resources are getting used
	 */
	private final StateDependentEventHandler<CapacityChangeEvent<ResourceConstraints>, List<ResourceConstraints>> decreasingFreeCapacityListenerManager = new StateDependentEventHandler<VMManager.CapacityChangeEvent<ResourceConstraints>, List<ResourceConstraints>>(
			new SingleNotificationHandler<CapacityChangeEvent<ResourceConstraints>, List<ResourceConstraints>>() {
				@Override
				public void sendNotification(final CapacityChangeEvent<ResourceConstraints> onObject,
						final List<ResourceConstraints> recentlyUsedResources) {
					onObject.capacityChanged(freeCapacities, recentlyUsedResources);
				}
			});

	/**
	 * This consumer is added to the PM help simulate the pure (VM less) operations
	 * on the PM. E.g., the VMM's operations can be resourceconsumptions registered
	 * between this consumer and the PM.
	 */
	public final MaxMinConsumer directConsumer;
	/**
	 * shows when the PM's direct consumer cannot be used as a consumer for tasks
	 * (in general it is only usable for external users when the PM is running)
	 */
	private boolean directConsumerUsageMoratory = true;

	private boolean secureExtensions = false;

	/**
	 * Defines a new physical machine, ensures that there are no VMs running so far
	 * 
	 * @param cores
	 *            defines the number of CPU cores this machine has under control
	 * @param perCorePocessing
	 *            defines the processing capabilities of a single CPU core in this
	 *            machine (in instructions/tick)
	 * @param memory
	 *            defines the total physical memory this machine has under control
	 *            (in bytes)
	 * @param disk
	 *            defines the local physical disk &amp; networking this machine has
	 *            under control
	 * @param onD
	 *            defines the time delay between the machine's switch on and the
	 *            first time it can serve VM requests
	 * @param offD
	 *            defines the time delay the machine needs to shut down all of its
	 *            operations while it does not serve any more VMs
	 * @param cpuPowerTransitions
	 *            determines the applied power state transitions while the physical
	 *            machine state changes. This is the principal way to alter a PM's
	 *            energy consumption behaviour.
	 */
	public PhysicalMachine(double cores, double perCorePocessing, long memory, Repository disk, int onD, int offD,
			Map<String, PowerState> cpuPowerTransitions) {
		this(cores, perCorePocessing, memory, disk,
				new double[] { onD * perCorePocessing * smallUtilization, perCorePocessing * smallUtilization },
				new double[] { offD * perCorePocessing * smallUtilization, perCorePocessing * smallUtilization },
				cpuPowerTransitions);
	}

	/**
	 * Makes a copy of the given array to the correct target (on/offTransition), and
	 * calculates the estimates for the on/offDelay
	 * 
	 * @param on
	 *            which taskset needs to be prepared
	 * @param array
	 *            the task array - for format see powerstatedelayer
	 * @return the estimated runtime of all tasks in the array
	 */
	private long prepareTransitionalTasks(boolean on, double[] array) {
		final double[] writeHere = on ? onTransition : offTransition;
		System.arraycopy(array, 0, writeHere, 0, array.length);
		long odSum = 0;
		for (int i = 0; i < array.length; i += 2) {
			odSum += (long) (array[i] / array[i + 1]);
		}
		return odSum;
	}

	/**
	 * Defines a new physical machine, ensures that there are no VMs running so far
	 * 
	 * @param cores
	 *            defines the number of CPU cores this machine has under control
	 * @param perCorePocessing
	 *            defines the processing capabilities of a single CPU core in this
	 *            machine (in instructions/tick)
	 * @param memory
	 *            defines the total physical memory this machine has under control
	 *            (in bytes)
	 * @param disk
	 *            defines the local physical disk &amp; networking this machine has
	 *            under control
	 * @param turnonOperations
	 *            defines the tasks to execute before the PM can be turned on - this
	 *            can be considered as the simulation of the boot process. for the
	 *            complete definition of this array have a look at the
	 *            powerstatedelayer class.
	 * @param switchoffOperations
	 *            defines the tasks to execute before the PM can be switched off -
	 *            this can be considered as the simulation of the shutdown process.
	 *            for the complete definition of this array have a look at the
	 *            powerstatedelayer class.
	 * @param cpuPowerTransitions
	 *            determines the applied power state transitions while the physical
	 *            machine state changes. This is the principal way to alter a PM's
	 *            energy consumption behaviour.
	 */

	public PhysicalMachine(double cores, double perCorePocessing, long memory, Repository disk,
			double[] turnonOperations, double[] switchoffOperations, Map<String, PowerState> cpuPowerTransitions) {
		super(cores * perCorePocessing);
		if (cpuPowerTransitions == null) {
			throw new IllegalStateException("Cannot initialize physical machine without a complete power behavior set");
		}

		// Init resources:
		totalCapacities = new ConstantConstraints(cores, perCorePocessing, memory);
		internalAvailableCaps = new AlterableResourceConstraints(totalCapacities);
		availableCapacities = new UnalterableConstraintsPropagator(internalAvailableCaps);
		internalReallyFreeCaps = new AlterableResourceConstraints(totalCapacities);
		freeCapacities = new UnalterableConstraintsPropagator(internalReallyFreeCaps);
		localDisk = disk;

		hostPowerBehavior = Collections.unmodifiableMap(cpuPowerTransitions);
		onTransition = new double[turnonOperations.length];
		onDelayEstimate = prepareTransitionalTasks(true, turnonOperations);
		offTransition = new double[switchoffOperations.length];
		offDelayEstimate = prepareTransitionalTasks(false, switchoffOperations);

		try {
			setState(State.OFF);
		} catch (NetworkException e) {
			// This should never happen
			throw new RuntimeException(e);
		}
		directConsumer = new MaxMinConsumer(getPerTickProcessingPower());
	}

	/**
	 * Starts the turn off procedure for the physical machine so it no longer
	 * accepts VM requests but it does not consume anymore
	 * 
	 * @param migrateHere
	 *            the physical machine where the currently hosted VMs of this VM
	 *            should go before the actual switch off operation will happen
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the switch off procedure has started
	 *         <li><i>false</i> if there are still VMs running and migration target
	 *         was not specified thus the switch off is not possible
	 *         </ul>
	 * @throws NetworkException
	 *             if the migration would need to use network connections that are
	 *             not set up correctly.
	 * @throws VMManager.VMManagementException
	 *             if the migration fails because the VM is not in correct state or
	 *             the PM does not have enough storage for the memory/disk state
	 */
	public boolean switchoff(final PhysicalMachine migrateHere) throws VMManagementException, NetworkException {
		if (migrateHere != null) {
			final VirtualMachine[] vmarr = vms.toArray(new VirtualMachine[vms.size()]);
			class MultiMigrate implements VirtualMachine.StateChange {
				private int counter = 0;

				@Override
				public void stateChanged(VirtualMachine vm, VirtualMachine.State oldState,
						VirtualMachine.State newState) {
					switch (newState) {
					case RUNNING:
						counter++;
						break;
					case SUSPENDED_MIG:
						// There is a problem but we cannot do here anything
						// right now...
					default:
					}
					if (counter == vmarr.length) {
						for (int i = 0; i < vmarr.length; i++) {
							vmarr[i].unsubscribeStateChange(this);
						}
						actualSwitchOff();
					}
				}
			}
			MultiMigrate mm = new MultiMigrate();
			for (int i = 0; i < vmarr.length; i++) {
				vmarr[i].subscribeStateChange(mm);
				migrateVM(vmarr[i], migrateHere);
			}
		} else {
			if (vms.size() + promisedAllocationsCount > 0) {
				return false;
			}
			actualSwitchOff();
		}
		return true;
	}

	/**
	 * does the actual switchoff, expected to be run only when there are no VMs
	 * running on the PM
	 */
	private void actualSwitchOff() {
		try {
			switch (currentState) {
			case SWITCHINGON:
				setState(State.SWITCHINGOFF);
				onOffEvent.addFurtherTasks(offTransition);
				onOffEvent.setNewState(State.OFF);
				break;
			case RUNNING:
				setState(State.SWITCHINGOFF);
				new Timed() {
					@Override
					public void tick(final long fires) {
						if (State.SWITCHINGOFF.equals(currentState)) {
							ResourceSpreader.FreqSyncer syncer = getSyncer();
							// Ensures that the switching off activities are only
							// started once all runtime activities complete for the
							// directConsumer
							if (syncer != null && syncer.isSubscribed()
									&& (underProcessing.size() + toBeAdded.size() - toBeRemoved.size() > 0)) {
								updateFrequency(syncer.getNextEvent() - fires + 1);
							} else {
								unsubscribe();
								new PowerStateDelayer(offTransition, State.OFF);
							}
						}
						// else: Another transition dropped the switchoff task. do
						// nothing
					}
				}.tick(Timed.getFireCount());
				break;
			case OFF:
			case SWITCHINGOFF:
				// Nothing to do
				System.err.println("WARNING: an already off PM was tasked to switch off!");
			}
		} catch (NetworkException nex) {
			// Should not happen as long as the network node don't have a SWITCHINGOFF state
			throw new RuntimeException(nex);
		}

	}

	/**
	 * Determines if the machine can be used for VM instantiation.
	 * 
	 * @return
	 *         <ul>
	 *         <li>true if the machine is ready to accept VM requests
	 *         <li>false otherwise
	 *         </ul>
	 */
	public boolean isRunning() {
		return currentState.equals(State.RUNNING);
	}

	/**
	 * retrieves the current state of the PM
	 * 
	 * @return the current state
	 */
	public State getState() {
		return currentState;
	}

	/**
	 * Turns on the physical machine so it allows energy and resource consumption
	 * (i.e. compute tasks) and opens the possibility to receive VM requests.
	 */
	public void turnon() {
		switch (currentState) {
		case SWITCHINGOFF:
		case OFF:
			try {
				setState(State.SWITCHINGON);
			} catch (NetworkException nex) {
				// Should not happen as long as the networknode don't have a switchingon state
				throw new RuntimeException(nex);
			}

			if (onOffEvent == null) {
				new PowerStateDelayer(onTransition, State.RUNNING);
			} else {
				onOffEvent.addFurtherTasks(onTransition);
				onOffEvent.setNewState(State.RUNNING);
			}

			break;
		case RUNNING:
		case SWITCHINGON:
			// Nothing to do
			System.err.println("WARNING: an already running PM was tasked to switch on!");
		}
	}

	/**
	 * Initiates the migration of a VM to another PM.
	 * 
	 * @param vm
	 *            the VM to be migrated
	 * @param target
	 *            the PM to be used by the VM after the migration completes
	 */
	@Override
	public void migrateVM(final VirtualMachine vm, final PhysicalMachine target)
			throws VMManagementException, NetworkNode.NetworkException {
		vm.migrate(prepareMigration(vm, target));
	}

	private ResourceAllocation prepareMigration(final VirtualMachine vm, final PhysicalMachine target)
			throws VMManagementException, NetworkNode.NetworkException {
		if (vms.contains(vm)) {
			ResourceAllocation ra = target.allocateResources(vm.getResourceAllocation().allocated, true,
					migrationAllocLen);
			if (ra == null) {
				throw new VMManagementException("Not enough resources on target host for migration");
			}
			return ra;
		} else {
			throw new VMManagementException("VM not hosted on source PM");
		}

	}

	public void migrateVMLive(final VirtualMachine vm, final PhysicalMachine target)
			throws VMManagementException, NetworkNode.NetworkException {
		vm.migrateLive(prepareMigration(vm, target));
	}

	/**
	 * Not implemented, would allow VMs to receive more resources in the future
	 */
	@Override
	public void reallocateResources(final VirtualMachine vm, final ResourceConstraints newresources) {

	}

	/**
	 * Ensures the requested amount of resources are going to be available in the
	 * foreseeable future on this physical machine.
	 * 
	 * @param requested
	 *            The amount of resources needed by the caller
	 * @param strict
	 *            if the PM should not return an allocation if it cannot completely
	 *            meet the request.
	 * @param allocationValidityLength
	 *            for how long the PM should keep the allocation in place. Depending
	 *            on the purpose of the allocation, it is recommended to use either
	 *            the defaultAllocLen or the migrationAllocLen constants of the PM
	 *            for this field.
	 * @return With a time limited offer on the requested resources. If the
	 *         requested resourceconstraints cannot be met by the function then it
	 *         returns with the maximum amount of resources it can serve. If there
	 *         are no available resources it returns with <i>null</i>! If the
	 *         requested resources can be exactly met then the original requested
	 *         resourceconstraints object is stored in the returned resource
	 *         allocation. If the resourceconstraints only specified a minimum
	 *         resource limit, then a new resourceconstraints object is returned
	 *         with details of the maximum possible resource constraints that can
	 *         fit into the machine.
	 */
	public ResourceAllocation allocateResources(final ResourceConstraints requested, final boolean strict,
			final int allocationValidityLength) throws VMManagementException {
		if (!currentState.equals(State.RUNNING)) {
			throw new VMManagementException("The PM is not running and thus cannot offer resources yet");
		}
		// Basic tests for resource availability for the host
		if (internalReallyFreeCaps.getRequiredCPUs() == 0 || internalReallyFreeCaps.getRequiredMemory() == 0
				|| requested.getRequiredProcessingPower() > internalReallyFreeCaps.getRequiredProcessingPower()) {
			return null;
		}
		// Allocation type test (i.e. do we allow underprovisioning?)
		for (int i = 0; i < promisedResources.length; i++) {
			ResourceAllocation olderAllocation = promisedResources[i];
			if (olderAllocation != null) {
				if (olderAllocation.allocated.isRequiredProcessingIsMinimum() == requested
						.isRequiredProcessingIsMinimum()) {
					break;
				} else {
					return null;
				}
			}
		}
		// Promised resources for the virtual machine
		double vmCPU = requested.getRequiredCPUs();
		long vmMem = requested.getRequiredMemory();
		final double vmPrPow = requested.isRequiredProcessingIsMinimum() ? totalCapacities.getRequiredProcessingPower()
				: requested.getRequiredProcessingPower();

		// Actually allocated resources (memory is equivalent in both cases)
		final double allocPrPow = totalCapacities.getRequiredProcessingPower();
		final double allocCPU = vmCPU * requested.getRequiredProcessingPower() / allocPrPow;
		if (0 <= internalReallyFreeCaps.getRequiredCPUs() - allocCPU) {
			if (0 <= internalReallyFreeCaps.getRequiredMemory() - requested.getRequiredMemory()) {
				return new ResourceAllocation(new ConstantConstraints(allocCPU, allocPrPow, vmMem),
						requested.isRequiredProcessingIsMinimum() ? new ConstantConstraints(vmCPU, vmPrPow, true, vmMem)
								: requested,
						allocationValidityLength);
			} else {
				vmMem = internalReallyFreeCaps.getRequiredMemory();
			}
		} else if (0 <= internalReallyFreeCaps.getRequiredMemory() - requested.getRequiredMemory()) {
			vmCPU = internalReallyFreeCaps.getRequiredCPUs();
		} else {
			vmCPU = internalReallyFreeCaps.getRequiredCPUs();
			vmMem = internalReallyFreeCaps.getRequiredMemory();
		}
		if (strict) {
			return null;
		} else {
			final ResourceConstraints updatedConstraints = new ConstantConstraints(vmCPU, vmPrPow,
					requested.isRequiredProcessingIsMinimum(), vmMem);
			return new ResourceAllocation(updatedConstraints, updatedConstraints, allocationValidityLength);
		}
	}

	/**
	 * check if a particular resource allocation is really issued by this pm.
	 * 
	 * @param allocation
	 *            the untrusted allocation
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the PM issued the allocation
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	private boolean checkAllocationsPresence(final ResourceAllocation allocation) {
		return promisedResources.length > allocation.myPromisedIndex
				&& promisedResources[allocation.myPromisedIndex] == allocation;
	}

	/**
	 * Terminate a resource allocation through the PM's interfaces
	 * 
	 * @param allocation
	 *            the resource allocation to terminate
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the allocation was cancelled
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	public boolean cancelAllocation(final ResourceAllocation allocation) {
		if (checkAllocationsPresence(allocation)) {
			allocation.cancel();
			return true;
		}
		return false;
	}

	/**
	 * checks if at least in theory the requested resources could be hosted on the
	 * PM (i.e., when there are no other VMs hosted on the PM).
	 * 
	 * @param requested
	 *            the resource set to be checked for hostability
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the such resource request has a chance of
	 *         acceptance
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	public boolean isHostableRequest(final ResourceConstraints requested) {
		return requested.compareTo(totalCapacities) <= 0;
	}

	/**
	 * Bounds a VM to a particular PM on a previously agreed allocation
	 * 
	 * @param vm
	 *            the VM to be deployed on the PM
	 * @param ra
	 *            the resource allocation to be uesed for the VM
	 * @param vaSource
	 *            the repository that stores the virtual appliance of the VM
	 * @throws VMManagementException
	 *             if the VA is not present on the source, or if the allocation
	 *             specified is already expired/used, or if the VM cannot be
	 *             switched on for some reason
	 * @throws NetworkNode.NetworkException
	 *             if the VA is not transferrable from the vaSource to its
	 *             destination
	 */
	public void deployVM(final VirtualMachine vm, final ResourceAllocation ra, final Repository vaSource)
			throws VMManagementException, NetworkNode.NetworkException {
		if (checkAllocationsPresence(ra)) {
			final VirtualAppliance va = vm.getVa();
			final StorageObject foundLocal = localDisk.lookup(va.id);
			final StorageObject foundRemote = vaSource == null ? null : vaSource.lookup(va.id);
			if (foundLocal != null || foundRemote != null) {
				vm.switchOn(ra, vaSource);
			} else {
				throw new VMManagementException("No VA available!");
			}
		} else {
			throw new VMManagementException("Tried to deploy VM with an expired resource allocation");
		}
	}

	/**
	 * Initiates a VM on this physical machine. If the physical machine cannot host
	 * VMs for some reason an exception is thrown, if the machine cannot host this
	 * particular VA then a null VM is returned.
	 * 
	 * @param va
	 *            The appliance for the VM to be created.
	 * @param rc
	 *            The resource requirements of the VM
	 * @param vaSource
	 *            The storage where the VA resides.
	 * @param count
	 *            The number of VMs to be created with the above specification
	 * @return The virtual machine(s) that will be instantiated on the PM. Null if
	 *         the constraints specify VMs that cannot fit the available resources
	 *         of the machine.
	 * 
	 * @throws VMManagementException
	 *             If the machine is not accepting requests currently.<br>
	 *             If the VM startup has failed.
	 */
	public VirtualMachine[] requestVM(final VirtualAppliance va, final ResourceConstraints rc,
			final Repository vaSource, final int count) throws VMManagementException, NetworkException {
		final VirtualMachine[] vms = new VirtualMachine[count];
		final ResourceAllocation[] ras = new ResourceAllocation[count];
		boolean canDeployAll = true;
		for (int i = 0; i < count && canDeployAll; i++) {
			ras[i] = allocateResources(rc, true, defaultAllocLen);
			vms[i] = null;
			canDeployAll &= ras[i] != null && ras[i].allocated == rc;
		}
		if (canDeployAll) {
			for (int i = 0; i < count; i++) {
				vms[i] = new VirtualMachine(va);
				deployVM(vms[i], ras[i], vaSource);
			}
		} else {
			for (int i = 0; i < count && ras[i] != null; i++) {
				ras[i].cancel();
			}
		}
		return vms;
	}

	/**
	 * Requests a few VMs just as before. Scheduling constraints are ignored
	 * currently! As this is too low level to handle them in the current state of
	 * the simulator.
	 */
	@Override
	public VirtualMachine[] requestVM(VirtualAppliance va, ResourceConstraints rc, Repository vaSource, int count,
			HashMap<String, Object> schedulingConstraints) throws VMManagementException, NetworkException {
		return requestVM(va, rc, vaSource, count);
	}

	/**
	 * Switches off the VM in question if the VM is hosted by this particular PM.
	 * 
	 * @param vm
	 *            to be switched off
	 * @param killTasks
	 *            if the VM must be switched off without caring about its tasks then
	 *            this should be true. if this is false, then the VM can only be
	 *            instructed to be switched off if there are no tasks currently
	 *            running on it.
	 * @throws NoSuchVMException
	 *             if the VM is not hosted on this PM
	 * @throws VMManagementException
	 *             if the VM is not in a state to be switched off
	 */
	@Override
	public void terminateVM(final VirtualMachine vm, final boolean killTasks)
			throws NoSuchVMException, VMManagementException {
		if (!vms.contains(vm)) {
			throw new NoSuchVMException("Termination request was received for an unknown VM");

		}
		vm.switchoff(killTasks);
	}

	/**
	 * a method to query the currently running VMs (this can also be accessed
	 * through the public field of publicVms).
	 */
	@Override
	public Collection<VirtualMachine> listVMs() {
		return publicVms;
	}

	/**
	 * a method to determine the number of VMs currently hosted by the PM.
	 * 
	 * @return the number of VMs on the PM at the current time instance.
	 */
	public int numofCurrentVMs() {
		return vms.size();
	}

	/**
	 * Determines if a resource consumption (i.e., a compute task utilizing the CPU
	 * of the PM) can be registered on the PM for execution.
	 * 
	 * Registration is only allowed if (i.e. the return value is true only if):
	 * <ul>
	 * <li>the PM is running
	 * <li>the consumer of the consumption is either a VM or the directconsumer of
	 * the PM
	 * <li>the consumption is coming from the powerstatedelayer.
	 * </ul>
	 */
	@Override
	protected boolean isAcceptableConsumption(final ResourceConsumption con) {
		final ResourceSpreader consumer = con.getConsumer();
		final boolean internalConsumer = (consumer == directConsumer)
				&& (directConsumerUsageMoratory ? (onOffEvent == null ? false : onOffEvent.currentConsumption == con)
						: true);
		final boolean runningVirtualMachine;
		if (internalConsumer) {
			runningVirtualMachine = false;
		} else {
			if (consumer instanceof VirtualMachine) {
				runningVirtualMachine = vms.contains((VirtualMachine) consumer);
			} else {
				runningVirtualMachine = false;
			}
		}
		return internalConsumer || runningVirtualMachine ? super.isAcceptableConsumption(con) : false;
	}

	/**
	 * determines if there are any VMs on the PM or not.
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if there are some VMs hosted on the PM.
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	public boolean isHostingVMs() {
		return !vms.isEmpty();
	}

	/**
	 * gets the number of VMs that have already left the PM but that were running on
	 * it once
	 * 
	 * @return the number of past VMs related to this PM
	 */
	public long getCompletedVMs() {
		return completedVMs;
	}

	/**
	 * Gets an estimate for the duration (in ticks) of the poweron/off operation in
	 * progress.
	 * 
	 * @return the estimated complete duration of the power state changing operation
	 * @throws IllegalStateException
	 *             if there is no power state change in progress
	 */
	public long getCurrentOnOffDelay() {
		if (onOffEvent == null) {
			switch (currentState) {
			case OFF:
				return onDelayEstimate;
			case RUNNING:
				return offDelayEstimate;
			default:
				throw new IllegalStateException("The onOffEvent is null while doing switchon/off");
			}
		} else {
			long remainingTime = onOffEvent.transitionStart - Timed.getFireCount();
			switch (currentState) {
			case SWITCHINGOFF:
				remainingTime += offDelayEstimate;
				break;
			case SWITCHINGON:
				remainingTime += onDelayEstimate;
				break;
			default:
				throw new IllegalStateException("The onOffEvent is not null while not in switchon/off mode");
			}
			return remainingTime;

		}
	}

	/**
	 * offers a nice single line format summary of the properties of this PM - good
	 * for debugging and tracing.
	 */
	@Override
	public String toString() {
		return "Machine(S:" + currentState + " C:" + internalReallyFreeCaps.getRequiredCPUs() + " M:"
				+ internalReallyFreeCaps.getRequiredMemory() + " " + localDisk.toString() + " " + super.toString()
				+ ")";
	}

	/**
	 * manages the subscriptions for state change events
	 * 
	 * @param sl
	 *            the listener object which expects state change events
	 */
	public void subscribeStateChangeEvents(final StateChangeListener sl) {
		stateListenerManager.subscribeToEvents(sl);
	}

	/**
	 * manages the subscriptions for state change events
	 * 
	 * @param sl
	 *            the listener object that no longer expects state change events
	 */
	public void unsubscribeStateChangeEvents(final StateChangeListener sl) {
		stateListenerManager.unsubscribeFromEvents(sl);
	}

	/**
	 * manages the state change operation of the PM.
	 * 
	 * Notifies the state change observers.
	 * 
	 * With the state change it also handles the power state changes according to
	 * the hostPowerBehavior, networkPowerBehavior and storagePowerBehavior maps.
	 * 
	 * @param newState
	 *            the new PM state to be set.
	 */
	private void setState(final State newState) throws NetworkException {
		try {
			localDisk.setState(NetworkNode.State.valueOf(newState.name()));
			// Behaviour change propagated
		} catch (IllegalArgumentException e) {
			// No need to propagate behaviour change
		}
		final State pastState = currentState;
		currentState = newState;
		directConsumerUsageMoratory = newState != State.RUNNING;
		stateListenerManager.notifyListeners(Pair.of(pastState, newState));

		// Power state management:
		setCurrentPowerBehavior(PowerTransitionGenerator.getPowerStateFromMap(hostPowerBehavior, newState.toString()));
	}

	/**
	 * collects the total resource capacity of the PM
	 */
	public ResourceConstraints getCapacities() {
		return totalCapacities;
	}

	/**
	 * not implemented
	 */
	@Override
	public void subscribeToCapacityChanges(final CapacityChangeEvent<ResourceConstraints> e) {
		// FIXME: not important yet
	}

	/**
	 * not implemented
	 */
	@Override
	public void unsubscribeFromCapacityChanges(final CapacityChangeEvent<ResourceConstraints> e) {
		// FIXME: not important yet
	}

	/**
	 * manages the subscriptions for free capacity events (i.e. those cases when
	 * there are some resources that are either not allocated anymore or when there
	 * is a VM that terminates on the PM)
	 * 
	 * @param e
	 *            the listener object which expects free capacity events
	 */
	public void subscribeToIncreasingFreeapacityChanges(final CapacityChangeEvent<ResourceConstraints> e) {
		increasingFreeCapacityListenerManager.subscribeToEvents(e);
	}

	/**
	 * manages the subscriptions for free capacity events (i.e. those cases when
	 * there are some resources that are either not allocated anymore or when there
	 * is a VM that terminates on the PM)
	 * 
	 * @param e
	 *            the listener object that no longer expects free capacity events
	 */
	public void unsubscribeFromDecreasingFreeCapacityChanges(final CapacityChangeEvent<ResourceConstraints> e) {
		decreasingFreeCapacityListenerManager.unsubscribeFromEvents(e);
	}

	/**
	 * manages the subscriptions for free capacity events (i.e. those cases when
	 * there are some resources that are either not allocated anymore or when there
	 * is a VM that terminates on the PM)
	 * 
	 * @param e
	 *            the listener object which expects free capacity events
	 */
	public void subscribeToDecreasingFreeapacityChanges(final CapacityChangeEvent<ResourceConstraints> e) {
		decreasingFreeCapacityListenerManager.subscribeToEvents(e);
	}

	/**
	 * manages the subscriptions for free capacity events (i.e. those cases when
	 * there are some resources that are either not allocated anymore or when there
	 * is a VM that terminates on the PM)
	 * 
	 * @param e
	 *            the listener object that no longer expects free capacity events
	 */
	public void unsubscribeFromIncreasingFreeCapacityChanges(final CapacityChangeEvent<ResourceConstraints> e) {
		increasingFreeCapacityListenerManager.unsubscribeFromEvents(e);
	}

	/**
	 * determines if the direct consumer accepts compute tasks to be registered
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if new tasks can be set up between the direct
	 *         consumer and the PM
	 *         <li><i>false</i> otherwise
	 *         </ul>
	 */
	public boolean isDirectConsumerUsageMoratory() {
		return directConsumerUsageMoratory;
	}

	/**
	 * Rudimentary api to query security related behaviour of the PM
	 * 
	 * @return if the PM supports secure VMs (e.g., via Intel SGX) then this returns
	 *         true
	 */
	public boolean isSecure() {
		return secureExtensions;
	}

	/**
	 * Allows PM's secure behavior to be set. This is only recommended to be used
	 * during PM setup.
	 * 
	 * @param secureExtensions
	 */
	public void setSecure(boolean secureExtensions) {
		this.secureExtensions = secureExtensions;
	}
} public static enum State {
	/**
	 * The machine is completely switched off, minimal consumption is recorded.
	 */
	OFF,
	/**
	 * The machine is under preparation to serve VMs. Some consumption is recorded
	 * already.
	 */
	SWITCHINGON,
	/**
	 * The machine is currently serving VMs. The machine and its VMs are consuming
	 * energy.
	 */
	RUNNING,
	/**
	 * The machine is about to be switched off. It no longer accepts VM requests but
	 * it still consumes energy.
	 */
	SWITCHINGOFF
}; class VMManagementException extends Exception {

	private static final long serialVersionUID = 4420666848803005233L;

	public VMManagementException(final String message) {
		super(message);
	}

	public VMManagementException(final String message, final Throwable ex) {
		super(message, ex);
	}
} public abstract class ResourceConstraints implements Comparable<ResourceConstraints> {

	/**
	 * provides a simple one line representation of resource constraints listing
	 * all its inherent properties. good for debugging and tracing.
	 */
	@Override
	public String toString() {
		return "ResourceConstraints(C:" + getRequiredCPUs() + " P:" + getRequiredProcessingPower() + " M:"
				+ getRequiredMemory() + ")";
	}

	/**
	 * offers a comparator between two constraints objects.
	 */
	@Override
	public int compareTo(ResourceConstraints o) {
		return ((Double) (this.getTotalProcessingPower() * this.getRequiredMemory()))
				.compareTo(o.getTotalProcessingPower() * o.getRequiredMemory());
	}

	/**
	 * Allows to query how many CPUs this constraints object represent
	 * 
	 * @return the amount of CPU cores represented by the object
	 */
	public abstract double getRequiredCPUs();

	/**
	 * Allows to query the performance of a single CPU core represented by this
	 * constraints object represent
	 * 
	 * @return the performance of a CPU core in instructions/tick
	 */
	public abstract double getRequiredProcessingPower();

	/**
	 * Determines if the specified amounts of resources are minimally or exactly
	 * required.
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the specified amount of resources could be
	 *         over-fulfilled
	 *         <li><i>false</i> if the object represents an exact amount of
	 *         resources
	 *         </ul>
	 */
	public abstract boolean isRequiredProcessingIsMinimum();

	/**
	 * Allows to query how much memory this constraints object represent
	 * 
	 * @return the amount in bytes
	 */
	public abstract long getRequiredMemory();

	/**
	 * The total processing power of all cores represented by this constraints
	 * object:
	 * 
	 * total=cpus*processingpower
	 * 
	 * @return the total processing power in instructions/tick
	 */
	public abstract double getTotalProcessingPower();

} public class VirtualMachine extends MaxMinConsumer {
	/**
	 * This class is defined to ensure one can differentiate errors that were caused
	 * because the functions on the VM class are called in an improper order. E.g.
	 * migration cannot be done if the VM is not running already.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	public static class StateChangeException extends VMManagementException {
		private static final long serialVersionUID = 2950595344006507672L;

		/**
		 * The constructor allows a textual message so users of this class can see the
		 * reason of the exception more clearly without debugging.
		 * 
		 * @param e
		 *            the message to be sent for the users of the simulator
		 */
		public StateChangeException(final String e) {
			super(e);
		}

	}

	/**
	 * This interface helps to receive events on status changes in virtual machines.
	 * One can subscribe to these events by calling the subscribeStateChange
	 * function. Afterwards whenever the VM changes its state it will automatically
	 * notify the subscribed entities.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	public interface StateChange {
		/**
		 * If the state of a VM is changed this function is called on all subscribing
		 * implementations.
		 * 
		 * @param oldState
		 *            the state before the change was issued
		 * @param newState
		 *            the state after the change took effect
		 */
		void stateChanged(VirtualMachine vm, State oldState, State newState);
	}

	/**
	 * This internal interface is used to customize internal state change actions in
	 * the VM class.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	private static class EventSetup {

		/**
		 * the state that the VM needs to be after the eventsetup completes
		 */
		public final State expectedState;

		public EventSetup(final State eState) {
			expectedState = eState;
		}

		/**
		 * Implementing this function allows the implementor to provide a custom VM
		 * state change function
		 */
		public void changeEvents(final VirtualMachine onMe) {
			onMe.setState(expectedState);
		}
	}

	/**
	 * Provides an implementation of the eventsetup class for the startup procedure
	 * which is modelled with a single taks that utilizes a single core of the VM
	 * for a specified amount of time (in ticks)
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	private static class StartupProcedure extends EventSetup {
		/**
		 * initiates the class and remarks that the modeled state should be startup
		 */
		public StartupProcedure() {
			super(State.STARTUP);
		}

		/**
		 * Once the startup state is reached, the VM's boot process is imitated with a
		 * single core process which runs on the VM for a given amount of ticks.
		 */
		@Override
		public void changeEvents(final VirtualMachine onMe) {
			final State preEventState = onMe.currState;
			super.changeEvents(onMe);
			if (onMe.ra != null) {
				try {
					onMe.newComputeTask(onMe.va.getStartupProcessing(), onMe.ra.allocated.getRequiredProcessingPower(),
							new ConsumptionEventAdapter() {
								/**
								 * Once the startup process is complete we set the VM's state to running
								 */
								@Override
								public void conComplete() {
									super.conComplete();
									onMe.setState(State.RUNNING);
								}
							});
					return;
				} catch (NetworkException e) {
					// Ignore and allow state to be changed back
				}
			}
			if (expectedState.equals(onMe.currState)) {
				// If the failure is caused by us we set the state back
				onMe.setState(preEventState);
				// Otherwise we leave it as any other part of the simulation required it
			}
		}
	};

	/**
	 * The operations to do on shutdown
	 */
	private static final EventSetup sdEvent = new EventSetup(State.SHUTDOWN);
	/**
	 * The operations to do on switchon
	 */
	private static final EventSetup switchonEvent = new StartupProcedure();

	/**
	 * the virtual appliance that this VM is using for its disk
	 */
	private VirtualAppliance va;
	/**
	 * the resource allocation of this VM (this is only not null when the VM is
	 * actually running on a pm, or about to run)
	 */
	private PhysicalMachine.ResourceAllocation ra = null;
	/**
	 * the VM's disk that is stored on the vatarget. if the VM is not past its
	 * initial transfer phase then the disk could be null.
	 */
	private StorageObject disk = null;
	/**
	 * if the VM is suspended then its memory is saved in the following storage
	 * object.
	 */
	private StorageObject savedmemory = null;
	/**
	 * where should the VM's virtual appliance be located
	 */
	private Repository vasource = null;
	/**
	 * where should the VM's disk storage be placed during the VM's initiation
	 * procedure.
	 */
	private Repository vatarget = null;

	/**
	 * the possible states of a virtual machine in DISSECT-CF.
	 * 
	 * @author "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems,
	 *         MTA SZTAKI (c) 2012"
	 */
	public static enum State {
		/**
		 * The VA of the machine is arranged to be usable for the execution. The VM is
		 * not consuming energy. There is no used storage.
		 */
		INITIAL_TR,
		/**
		 * The VM is booting up, and already consumes energy although it does not offer
		 * useful services for its user. The VM stores a clone of the VA in a
		 * repository.
		 */
		STARTUP,
		/**
		 * The VM is operating according to the user's needs. The VM consumes energy.
		 * The VM stores a clone of the VA in a repository.
		 */
		RUNNING,
		/**
		 * The VM is about to be suspended, and its memory is under serialization. The
		 * VM does not consume energy anymore. The VM stores a clone of the VA in a
		 * repository.
		 */
		SUSPEND_TR,
		/**
		 * The VM is awaiting to be resumed. It can be resumed fast and it can skip the
		 * bootup procedure. The VM does not consume energy. The VM stores a clone of
		 * the VA and its serialized memory in a repository.
		 */
		SUSPENDED,
		/**
		 * This is a rapid transitional state, once the VM's state is transferred but
		 * its tasks not yet resumed.
		 */
		SUSPENDED_MIG,
		/**
		 * The VM is about to be running. Its memory is transferred and deserialized.
		 * The VM still stores a clone of the VA and its serialized memory in a
		 * repository. The VM starts to consume energy for the deserialization.
		 */
		RESUME_TR,
		/**
		 * The VM is on the move between two Phisical machines. During this operation it
		 * could happen that the VM and its serialized memory occupies disk space in two
		 * repositories. The VM starts to consume energy during the deserialization of
		 * its memory on the target PM.
		 */
		MIGRATING,
		/**
		 * The VM is not running. It's disk image (but not its memory state) can be
		 * found in the repository. So it is possible to start the VM up without the
		 * need for initial transfer. The VM is not consuming energy.
		 */
		SHUTDOWN,
		/**
		 * The VM is not running and it does not have any storage requirements in any of
		 * the repositories. The VM is not consuming energy.
		 */
		DESTROYED,
		/**
		 * The VM is destroyed, and it is not possible to instantiate it in the current
		 * cloud infrastructure (or the VM was terminated on user request before it was
		 * possible to instantiate it in the cloud)
		 */
		NONSERVABLE
	};

	/**
	 * the set of those VM states that are expected to consume energy
	 */
	public final static EnumSet<State> consumingStates = EnumSet.of(State.STARTUP, State.RUNNING, State.MIGRATING,
			State.RESUME_TR);
	/**
	 * the set of those VM states that are transferring VM related data
	 */
	public final static EnumSet<State> transferringStates = EnumSet.of(State.INITIAL_TR, State.SUSPEND_TR,
			State.RESUME_TR, State.MIGRATING);
	/**
	 * the states in which the VM is suspended to disk
	 */
	public final static EnumSet<State> suspendedStates = EnumSet.of(State.SUSPENDED, State.SUSPENDED_MIG);
	/**
	 * the states that can preceed the startup phase
	 */
	public final static EnumSet<State> preStartupStates = EnumSet.of(State.DESTROYED, State.SHUTDOWN);
	/**
	 * the set of states that show that a VM scheduler was not able to schedule the
	 * VM (maybe just yet)
	 */
	public final static EnumSet<State> preScheduleState = EnumSet.of(State.DESTROYED, State.NONSERVABLE);

	/**
	 * the current state of the VM
	 */
	private State currState = State.DESTROYED;
	/**
	 * the local handler of VM state change events.
	 */
	private final StateDependentEventHandler<StateChange, Triple<VirtualMachine, State, State>> vmStateChangelistenerManager = VMStateChangeNotificationHandler
			.getHandlerInstance();

	/**
	 * the list of resourceconsumptions (i.e. compute tasks) that were suspended and
	 * need to be resumed after the VM itself is resumed.
	 */
	private ArrayList<ResourceConsumption> suspendedTasks;

	/**
	 * represents operations required for handling the virtual machine monitor
	 */
	private HashMap<String, ResourceConsumption> currentVMMOperations = new HashMap<String, ResourceConsumption>();

	/**
	 * Instantiates a VM object
	 * 
	 * @param va
	 *            the virtual appliance that should be the base for this VM,
	 * 
	 * @throws IllegalStateException
	 *             if the va is <i>null</i>
	 */
	public VirtualMachine(final VirtualAppliance va) {
		super(0);
		if (va == null) {
			throw new IllegalStateException("Cannot accept nonexistent virtual appliances on instantiation");
		}
		this.va = va;
	}

	/**
	 * Always use this function to set the current VM state. This way all the
	 * interested parties get notified on the changes.
	 * 
	 * @param newstate
	 *            The new state the VM is in.
	 */
	private void setState(final State newstate) {
		final State oldState = currState;
		currState = newstate;
		vmStateChangelistenerManager.notifyListeners(Triple.of(this, oldState, newstate));
	}

	/**
	 * Queries the VA used by this VM
	 * 
	 * @return the va used by this VM
	 */
	public VirtualAppliance getVa() {
		return va;
	}

	/**
	 * Queries the current state of the VM
	 * 
	 * @return the current vm state
	 */
	public State getState() {
		return currState;
	}

	/**
	 * Prepares the VM so it can be started without the need to clone its VA first.
	 * This function is useful in advanced scheduling situations.
	 * 
	 * @param vatarget
	 *            the disk that will host the VM.
	 * @param vasource
	 *            the repository where the VA for this VM is found. If null, the
	 *            function assumes it is found in the hosting PM's repository.
	 * @throws StateChangeException
	 *             if the VM is not destroyed
	 * @throws VMManagementException
	 *             if the VA transfer failed and the state change was reverted
	 */
	public void prepare(final Repository vasource, final Repository vatarget)
			throws VMManagementException, NetworkNode.NetworkException {
		if (currState != State.DESTROYED) {
			throw new StateChangeException("The VM is not destroyed");
		}
		initialTransfer(vasource, vatarget, sdEvent);
	}

	/**
	 * The event that will be received upon the completion of the VA's copy from
	 * vasource to vatarget.
	 * 
	 * @author "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems,
	 *         MTA SZTAKI (c) 2012"
	 * 
	 * 
	 */
	class InitialTransferEvent extends ConsumptionEventAdapter {
		/**
		 * the target repository where the VA is expected to turn up
		 */
		final Repository target;
		/**
		 * the event to be fired after the transfer is complete
		 */
		final EventSetup esetup;
		/**
		 * the expected id of the storage object in the target repository
		 */
		final String diskid;

		/**
		 * Initiates the event handler object
		 * 
		 * @param t
		 *            the repository to observe
		 * @param event
		 *            the event to fire after the transfer to the target repo happened
		 * @param did
		 *            the disk id of the newly created storage object in the target repo
		 *            for the new runnable VA.
		 */
		public InitialTransferEvent(final Repository t, final EventSetup event, final String did) {
			target = t;
			esetup = event;
			diskid = did;
		}

		/**
		 * stores the newly transferred storage object into the VM's disk field, and
		 * then continues with the next step in the VM state management (represented
		 * with the event setup)
		 */
		@Override
		public void conComplete() {
			currentVMMOperations.clear();
			disk = target.lookup(diskid);
			esetup.changeEvents(VirtualMachine.this);
		}

		@Override
		public void conCancelled(ResourceConsumption problematic) {
			currentVMMOperations.clear();
			releaseRa(State.DESTROYED);
		}

	}

	private void ensureEmptyVMMOperationList() throws VMManagementException {
		if (!currentVMMOperations.isEmpty()) {
			throw new VMManagementException("Other VMM related background operation is in progress!");
		}
	}

	/**
	 * Ensures the transfer of the VM to the appropriate location. The location is
	 * determined based on the VM storage approach used. While transferring it
	 * maintains the INITIAL_TR state. If there is a fault it falls back to the
	 * state beforehand. If successful it allows the caller to change the event on
	 * the way it sees fit.
	 * 
	 * @param vatarget
	 *            the storage that will host the VM's working image (typically this
	 *            is going to be the disk of the PM that will host the VM).
	 * @param vasource
	 *            the repository where the VA for this VM is found. If null, the
	 *            function assumes it is found in the hosting PM's repository.
	 * @param es
	 *            The way the VM's state should be changed the function will fire an
	 *            event on this channel if the VA is cloned properly
	 * @throws VMManagementException
	 *             if the VA transfer failed and the state change was reverted
	 * @throws NetworkException
	 *             if the VA's transfer cannot be completed (e.g., because of
	 *             connectivity issues)
	 */
	private void initialTransfer(final Repository vasource, final Repository vatarget, final EventSetup es)
			throws VMManagementException, NetworkNode.NetworkException {
		final State oldState = currState;
		final long bgnwload = va.getBgNetworkLoad();
		if (bgnwload > 0 && vasource == vatarget) {
			throw new VMManagementException("Cannot initiate a transfer for remotely running VM on the remote site!");
		}
		ensureEmptyVMMOperationList();
		setState(State.INITIAL_TR);
		// Allows the immediate cancellation of the transfer i.e., in reaction
		// to the INITIAL_TR change
		if (State.INITIAL_TR.equals(currState)) {
			this.vasource = vasource;
			this.vatarget = vatarget;
			final String diskid = "VMDisk-of-" + Integer.toString(hashCode());
			ResourceConsumption currentVMMOperation = null;
			if (bgnwload > 0) {
				// Remote scenario
				currentVMMOperation = vasource.duplicateContent(va.id, diskid,
						new InitialTransferEvent(vasource, es, diskid));
			} else {
				if (vasource == null) {
					// Entirely local scenario
					if (vatarget != null) {
						currentVMMOperation = vatarget.duplicateContent(va.id, diskid,
								new InitialTransferEvent(vatarget, es, diskid));
					}
				} else {
					// Mixed scenario
					currentVMMOperation = vasource.requestContentDelivery(va.id, diskid, vatarget,
							new InitialTransferEvent(vatarget, es, diskid));
				}
			}
			if (currentVMMOperation != null) {
				currentVMMOperations.put(currState.toString(), currentVMMOperation);
			} else {
				setState(oldState);
				throw new VMManagementException("Initial transfer failed");
			}
		}
	}

	/**
	 * Initiates the startup procedure of a VM. If the VM is in destroyed state then
	 * it ensures the disk image for the VM is ready to be used (i.e. first it
	 * starts the inittransfer procedure).
	 * 
	 * @param allocation
	 *            the resource allocation which will be used to deploy the VM on.
	 * @param vasource
	 *            the repository where the VA for this VM is found. If null, the
	 *            function assumes it is found in the hosting PM's repository.
	 * @throws StateChangeException
	 *             if the VM is not destroyed or shutdown
	 * @throws VMManagementException
	 *             if the VA transfer failed and the state change was reverted
	 */
	public void switchOn(final PhysicalMachine.ResourceAllocation allocation, final Repository vasource)
			throws VMManagementException, NetworkNode.NetworkException {
		switch (currState) {
		case DESTROYED:
			setResourceAllocation(allocation);
			initialTransfer(vasource, allocation.getHost().localDisk, switchonEvent);
			break;
		case SHUTDOWN:
			// Shutdown has already done the transfer, we just need to make sure
			// the VM will get through its boot procedure
			if (allocation.getHost().localDisk != vatarget) {
				// TODO: maybe we can switch back to destroyed
				throw new VMManagementException("VM was not prepared for this PM");
			}
			setResourceAllocation(allocation);
			switchonEvent.changeEvents(this);
			break;
		default:
			throw new StateChangeException("The VM is not shut down or destroyed");
		}
	}

	/**
	 * Forwards the migration call internally allowing both live/non-live migrations
	 * 
	 * @param target
	 *            the new resource allocation on which the resume operation should
	 *            take place
	 * @throws StateChangeException
	 *             if the VM is not in running state currently
	 * @throws VMManagementException
	 *             if the system have had troubles during the suspend operation.
	 */
	public void migrate(final PhysicalMachine.ResourceAllocation target)
			throws VMManagementException, NetworkNode.NetworkException {
		migrate(target, false);
	}

	/**
	 * Moves all data necessary for the VMs execution from its current physical
	 * machine to another. Supports migration from suspended state.
	 * 
	 * @param target
	 *            the new resource allocation on which the resume operation should
	 *            take place
	 * @param onlyLiveMigration
	 *            <ul>
	 *            <li><i>true</i> live migration is explicitly requested (if not
	 *            possible, a VMManagementException will be thrown)
	 *            <li><i>false</i> if live migration is priorised but if not
	 *            possible, non-live will be performed
	 *            </ul>
	 * @throws StateChangeException
	 *             if the VM is not in running or suspended state currently
	 * @throws VMManagementException
	 *             if the system have had troubles during the migration operation
	 *             (e.g., storage and connectivity issues).
	 */
	public void migrate(final PhysicalMachine.ResourceAllocation target, boolean onlyLiveMigration)
			throws VMManagementException, NetworkNode.NetworkException {
		/**
		 * This class prepares and transitions a VM through the phases of migration
		 * (both live and non live)
		 * 
		 * @author "Gabor Kecskemeti, Department of Computer Science, Liverpool John
		 *         Moores University, (c) 2017"
		 * @author "Vincenzo De Maio, Distributed and Parallel Systems Group, University
		 *         of Innsbruck (c) 2015"
		 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
		 *         of Innsbruck (c) 2013"
		 * 
		 */
		class MigrationEvent extends ConsumptionEventAdapter {
			/**
			 * When did the last memory transfer start for the current migration process
			 */
			private long lastMemorySnapshotCreatedAt = -1;
			/**
			 * Maximum number of memory transfers to be done before giving up and doing a
			 * non-live final transfer
			 */
			public final static long maxRounds = 5;
			/**
			 * Smallest written working set size that still allows new memory copy rounds
			 */
			public final static long WWS_TERMINAL_SIZE = 262144;
			/**
			 * the secondary resource allocation of this VM (this is only not null when the
			 * VM is in migration)
			 */
			private final PhysicalMachine.ResourceAllocation migrationRa;
			/**
			 * If we are doing live migration
			 */
			private boolean liveMigration = true;
			/**
			 * Pre migration state to return to in case of an error
			 */
			final State prevState = currState;
			/**
			 * The local storage of the target host for this migration
			 */
			final Repository to;
			/**
			 * Non-live transfer count, 1=only memory, 2= disk and memory together
			 */
			int eventcounter = 1;
			/**
			 * Number of memory copy rounds done during the current migration process
			 */
			int rounds = 0;

			public MigrationEvent(PhysicalMachine.ResourceAllocation newRa, boolean onlyLiveMigration)
					throws VMManagementException, NetworkNode.NetworkException {
				ensureEmptyVMMOperationList();
				switch (currState) {
				case SUSPENDED:
					if (onlyLiveMigration) {
						throw new StateChangeException("Live migration cannot be forced in this state!");
					}
					setNonLive();
				case RUNNING:
					break;
				default:
					throw new StateChangeException("Invalid starting state for a VM migration");
				}
				migrationRa = newRa;
				to = migrationRa.getHost().localDisk;
				if (va.getBgNetworkLoad() <= 0) {
					// If the disk is local&mixed image storage
					if (onlyLiveMigration) {
						throw new VMManagementException(
								"Live migration is only allowed if the VM runs from a remote disk");
					}
					NetworkNode.checkConnectivity(vatarget, to);
					setNonLive();
					eventcounter++;
					ResourceConsumption currentVMMOperation;
					if ((currentVMMOperation = vatarget.requestContentDelivery(disk.id, to, this)) != null) {
						currentVMMOperations.put(currState.toString() + disk.id, currentVMMOperation);
					} else {
						setState(prevState);
						throw new VMManagementException(
								"Cannot transfer the disk of the VM during non-live migration.");
					}
				}
				newMemoryRound();
			}

			private void setNonLive() {
				if (liveMigration) {
					liveMigration = false;
					suspendTasks();
					setState(State.MIGRATING);
				}
			}

			private long newMemoryRound() throws NetworkException {
				// If we come from suspend, savedmemory is used.
				final long memSize = savedmemory == null ? identifyWWS() : savedmemory.size;
				// This replaces any previous memory related transfers
				currentVMMOperations.put(currState.toString() + "Migrate Memory",
						NetworkNode.initTransfer(memSize, ResourceConsumption.unlimitedProcessing, vatarget, to, this));
				return memSize;
			}

			/**
			 * Determine the amount of memory dirtied since the last call
			 * <p>
			 * Done as per eq 17 from the paper "<i>De Maio, V., Kecskemeti, G., & Prodan,
			 * R. (2016, December). An improved model for live migration in data centre
			 * simulators. In Utility and Cloud Computing (UCC), 2016 IEEE/ACM 9th
			 * International Conference on (pp. 108-117). IEEE.</i>"
			 * 
			 * @return the total dirtying rate on the VM
			 */
			private long identifyWWS() {
				long previousSnapshot = lastMemorySnapshotCreatedAt;
				lastMemorySnapshotCreatedAt = Timed.getFireCount();
				if (previousSnapshot == -1) {
					return getMemSize();
				}
				long duration = lastMemorySnapshotCreatedAt - previousSnapshot;
				long dirtyBytes = 0;
				for (ResourceConsumption r : underProcessing) {
					dirtyBytes += (Math.min(1, duration * r.getMemDirtyingRate()) * r.getMemSize());
				}
				return dirtyBytes;
			}

			@Override
			public void conComplete() {
				// Cross cloud migration needs an update on the vastorage also,
				// otherwise the VM will use a long distance repository for its
				// background network load!
				if (liveMigration) {
					try {
						long memSizeRemaining = newMemoryRound();
						if (rounds++ >= maxRounds || memSizeRemaining < WWS_TERMINAL_SIZE) {
							// Switching to final, non-live phase
							setNonLive();
						}
					} catch (NetworkException ne) {
						// These exceptions should have occured while
						// registering the first transfer
						throw new RuntimeException(ne);
					}
				} else {
					// In case we came here from suspend
					if (savedmemory != null) {
						vatarget.deregisterObject(savedmemory);
						savedmemory = null;
					}
					eventcounter--;
					// Only continue if we have done all required transfers
					if (eventcounter == 0) {
						currentVMMOperations.clear();
						// Both the disk and memory state has completed its
						// transfer.
						try {
							if (suspendedTasks != null) {
								for (final ResourceConsumption con : suspendedTasks) {
									con.setProvider(migrationRa.getHost());
								}
							}
							releaseRa(State.SUSPENDED_MIG);
							setResourceAllocation(migrationRa);
							if (va.getBgNetworkLoad() <= 0) {
								// Local&Mixed scenario, the disk was moved
								vatarget.deregisterObject(disk);
								vatarget = ra.getHost().localDisk;
							}
							lastMemorySnapshotCreatedAt = -1;
							resumeTasks();
						} catch (VMManagementException e) {
							// Sudden exceptions that should not really happen
							throw new RuntimeException(e);
						}
					}
				}
			}

			/**
			 * migration related transfers cancelled, revert our actions
			 */
			@Override
			public void conCancelled(ResourceConsumption problematic) {
				lastMemorySnapshotCreatedAt = -1;
				currentVMMOperations.clear();
				migrationRa.cancel();
				if (!currState.equals(prevState)) {
					setState(prevState);
				}
			}
		}

		new MigrationEvent(target, onlyLiveMigration);
	}

	/**
	 * Moves all data necessary for the VMs execution from its current physical
	 * machine to another.
	 *
	 * WARNING: in cases when the migration cannot complete, the VM will be left in
	 * a special suspended state: the SUSPENDED_MIG. This allows users to recover
	 * VMs and initiate the migration procedure to someplace else.
	 *
	 *
	 * @param target
	 *            the new resource allocation on which the resume operation should
	 *            take place
	 * @throws StateChangeException
	 *             if the VM is not in running state currently
	 * @throws VMManagementException
	 *             if the system have had troubles during the suspend operation.
	 * @throws NetworkException
	 *             if target host is not reachable
	 */

	public void migrateLive(final PhysicalMachine.ResourceAllocation target)
			throws VMManagementException, NetworkNode.NetworkException {
		migrate(target, true);
	}

	/**
	 * Destroys the VM, and cleans up all repositories that could contain disk or
	 * memory states.
	 * 
	 * @throws StateChangeException
	 *             if some parts of the VM are under transfer so it cannot be
	 *             determined what to clean up.
	 */
	public void destroy(final boolean killTasks) throws VMManagementException {
		if (!currentVMMOperations.isEmpty()) {
			ResourceConsumption[] rcList = currentVMMOperations.values()
					.toArray(new ResourceConsumption[currentVMMOperations.size()]);
			boolean wasRegistered = false;
			for (ResourceConsumption currentVMMOperation : rcList) {
				wasRegistered |= currentVMMOperation.isRegistered();
				currentVMMOperation.cancel();
			}
			if (wasRegistered) {
				// Wait until the cancel takes effect - registration cleanup
				new DeferredEvent(1) {
					@Override
					protected void eventAction() {
						try {
							destroy(killTasks);
						} catch (VMManagementException e) {
							// TODO: allow more graceful exception handling
							throw new RuntimeException(e);
						}
					}
				};
				return;
			}
		}
		finalizeDestroy(killTasks);
	}

	private void finalizeDestroy(final boolean killTasks) throws VMManagementException {
		if (ra != null) {
			switchoff(killTasks);
		}
		if (vasource != null) {
			vasource.deregisterObject(disk);
			vasource.deregisterObject(savedmemory);
			vasource = null;
		}
		if (vatarget != null) {
			vatarget.deregisterObject(disk);
			vatarget.deregisterObject(savedmemory);
		}
		if (!State.DESTROYED.equals(currState)) {
			setState(State.DESTROYED);
		}
	}

	/**
	 * Switches off an already running machine. After the successful execution of
	 * this function, the VM's state will be shutdown.
	 * 
	 * @throws StateChangeException
	 *             if is not running currently
	 */
	public void switchoff(final boolean killTasks) throws StateChangeException {
		if (currState != State.RUNNING && currState != State.STARTUP) {
			throw new StateChangeException("Cannot switch off a not running machine");
		}
		if (killTasks) {
			suspendedTasks = new ArrayList<ResourceConsumption>(underProcessing);
			for (final ResourceConsumption con : suspendedTasks) {
				con.cancel();
			}
			suspendedTasks = null;
		} else if (!underProcessing.isEmpty()) {
			throw new StateChangeException("Cannot switch off a running machine with running tasks");
		}
		releaseRa(State.SHUTDOWN);
	}

	/**
	 * When the VM is about to decouple from a PM this function is called.
	 * 
	 * @param newState
	 *            the state the VM needs to be in after the decoupling is done
	 */
	private void releaseRa(State newState) {
		if (ra != null) {
			ra.release();
			ra = null;
		}
		setState(newState);
	}

	/**
	 * Suspends an already running VM. During the suspend operation, the VM's memory
	 * state is stored to enable the resume operation for fast VM startup.
	 * 
	 * The VM's memory state is first created as a storage object on the PM's local
	 * repository then transferred to its designated location.
	 * 
	 * @throws StateChangeException
	 *             if the machine is not in running state
	 * @throws VMManagementException
	 *             if there is not enough space to store the memory state (first
	 *             locally, then locally/remotely depending on the VM storage
	 *             scenario
	 */
	public void suspend() throws VMManagementException, NetworkNode.NetworkException {
		if (currState != State.RUNNING) {
			throw new StateChangeException("Cannot suspend a not running machine");
		}
		suspendTasks();
		final Repository pmdisk = ra.getHost().localDisk;
		savedmemory = new StorageObject("VM-Memory-State-of-" + hashCode(), getMemSize(), false);
		setState(State.SUSPEND_TR);
		ResourceConsumption currentVMMOperation = null;
		if ((currentVMMOperation = pmdisk.storeInMemoryObject(savedmemory, new ConsumptionEventAdapter() {
			@Override
			public void conComplete() {
				currentVMMOperations.clear();
				releaseRa(State.SUSPENDED);
			}

			@Override
			public void conCancelled(ResourceConsumption problematic) {
				currentVMMOperations.clear();
				setState(State.RUNNING);
				savedmemory = null;
			}
		})) == null) {
			// Set back the status so it is possible to try again
			setState(State.RUNNING);
			String sid = savedmemory.id;
			savedmemory = null;
			throw new VMManagementException("Not enough space on localDisk for the suspend operation of " + sid);
		} else {
			currentVMMOperations.put(currState.toString(), currentVMMOperation);
		}
	}

	/**
	 * Stops the computation of all tasks at this VM, it allows for their resumption
	 * later on
	 */
	private void suspendTasks() {
		if (toBeAdded.size() + underProcessing.size() > 0) {
			if (suspendedTasks == null) {
				suspendedTasks = new ArrayList<ResourceConsumption>(underProcessing);
			} else {
				suspendedTasks.addAll(underProcessing);
			}
			suspendedTasks.addAll(toBeAdded);

			final int currlistsize = suspendedTasks.size();
			for (int idx = 0; idx < currlistsize; idx++) {
				final ResourceConsumption con = suspendedTasks.get(idx);
				con.suspend();
			}
		}
	}

	/**
	 * Re-registers all previously suspended tasks and marks the VM running
	 */
	private void resumeTasks() {
		setState(State.RUNNING);
		if (suspendedTasks != null) {
			int size = suspendedTasks.size();
			for (int i = 0; i < size; i++) {
				suspendedTasks.get(i).registerConsumption();
			}
			suspendedTasks = null;
		}
	}

	/**
	 * Resumes an already suspended VM. During the resume operation, the VM's memory
	 * state is used for fast VM startup.
	 * 
	 * The VM's memory state is first transferred to the PM's repository (simulating
	 * its loading to the VM's memory). Afterwards, this function cleans up the
	 * memory states as after startup the VM already changes them.
	 * 
	 * @throws StateChangeException
	 *             if the machine is not in suspended state
	 * @throws VMManagementException
	 *             if there is not enough space to retreive the memory state to the
	 *             PM's repository
	 */
	public void resume() throws VMManagementException, NetworkNode.NetworkException {
		if (!currState.equals(State.SUSPENDED)) {
			throw new StateChangeException("Cannot resume a not suspended machine");
		}
		ensureEmptyVMMOperationList();
		final State priorState = currState;
		setState(State.RESUME_TR);
		final Repository pmdisk = ra.getHost().localDisk;
		class ResumeComplete extends ConsumptionEventAdapter {
			private void cleanUpIntermediateData() {
				savedmemory = null;
				currentVMMOperations.clear();
			}

			@Override
			public void conComplete() {
				// Deregister saved memory
				pmdisk.deregisterObject(savedmemory);
				cleanUpIntermediateData();
				resumeTasks();
			}

			@Override
			public void conCancelled(ResourceConsumption problematic) {
				cleanUpIntermediateData();
				setState(priorState);
			}
		}
		ResourceConsumption currentVMMOperation;
		if ((currentVMMOperation = pmdisk.fetchObjectToMemory(savedmemory, new ResumeComplete())) == null) {
			// Set back the status so it is possible to try again
			setState(priorState);
			throw new VMManagementException("Failed to fetch the stored memory " + savedmemory + " from PM "
					+ pmdisk.getName() + " for the resume operation of VM " + hashCode());
		} else {
			currentVMMOperations.put(currState.toString(), currentVMMOperation);
		}
	}

	/**
	 * Use this function to get notified about state changes on this VM
	 * 
	 * @param consumer
	 *            the party to be notified when the state changes
	 */
	public void subscribeStateChange(final StateChange consumer) {
		vmStateChangelistenerManager.subscribeToEvents(consumer);
	}

	/**
	 * Use this function to be no longer notified about state changes on this VM
	 * 
	 * @param consumer
	 *            the party who previously received notifications
	 */
	public void unsubscribeStateChange(final StateChange consumer) {
		vmStateChangelistenerManager.unsubscribeFromEvents(consumer);
	}

	/**
	 * determines if a resourceconsumption object can be registered. it is going to
	 * be determined acceptable all the time if the VM is in one of its consuming
	 * states.
	 */
	@Override
	protected boolean isAcceptableConsumption(ResourceConsumption con) {
		return consumingStates.contains(currState) ? super.isAcceptableConsumption(con) : false;
	}

	/**
	 * This is the function that users are expected to use to create computing tasks
	 * on the VMs (not using resourceconsumptions directly). The computing tasks
	 * created with this function are going to utilize CPUs and if there is a
	 * background load defined for the VM then during the processing of the CPU
	 * related activities there will be constant network activities modelled as
	 * well. The background network load represents cases when the VM's disk is
	 * hosted on the network (and thus inherent disk activities that would occur
	 * during CPU related activities can be modeled). Please note the backgorund
	 * load is the property of the VA (i.e. the VA represents an application and
	 * therefore one who creates the VA should know its disk related activities when
	 * the application is executed)
	 * 
	 * @param total
	 *            the amount of processing to be done (in number of instructions)
	 * @param limit
	 *            the amount of processing this new compute task is allowed to do in
	 *            a single tick (in instructions/tick). If there should be no limit
	 *            for the processing then one can use the constant named
	 *            ResourceConsumption.unlimitedProcessing.
	 * @param e
	 *            the object to be notified about the completion of the computation
	 *            ordered here
	 * @return the resource consumption object that will represent the CPU
	 *         consumption. Could return null if the consumption cannot be
	 *         registered or when there is no resoruce for the VM
	 * @throws NetworkException
	 *             if the background network load is not possible to simulate.
	 */
	public ResourceConsumption newComputeTask(final double total, final double limit,
			final ResourceConsumption.ConsumptionEvent e) throws NetworkException {
		if (ra == null) {
			return null;
		}
		ResourceConsumption cons = new ResourceConsumption(total, limit, VirtualMachine.this, ra.getHost(), e);
		if (cons.registerConsumption()) {
			final long bgnwload = va.getBgNetworkLoad();
			if (bgnwload > 0) {
				final long minBW = Math.min(bgnwload,
						Math.min(ra.getHost().localDisk.getOutputbw(), vasource.getInputbw()));
				NetworkNode.initTransfer(minBW * cons.getCompletionDistance(), minBW, ra.getHost().localDisk, vasource,
						new ConsumptionEventAdapter());
			}
			return cons;
		} else {
			return null;
		}
	}

	public ResourceConsumption newComputeTask(final double total, final double limit,
			final ResourceConsumption.ConsumptionEvent e, final double dirtyingRate, final long memSize)
			throws StateChangeException, NetworkException {
		ResourceConsumption rc = newComputeTask(total, limit, e);
		if (rc != null) {
			rc.setMemDirtyingRate(dirtyingRate);
			rc.setMemSize(memSize);
		}
		return rc;
	}

	/**
	 * Allows to set a new resource allocation for the VM
	 * 
	 * This function will notify the resource allocation about the acquiration of
	 * the resources by utilizing the use function!
	 * 
	 * @param newRA
	 *            the allocation to be used later on
	 * @throws VMManagementException
	 *             if the VM is already running using a host
	 */
	public void setResourceAllocation(PhysicalMachine.ResourceAllocation newRA) throws VMManagementException {
		switch (currState) {
		case DESTROYED:
		case SUSPENDED:
		case SHUTDOWN:
		case SUSPENDED_MIG:
			ra = newRA;
			ra.use(this);
			setPerTickProcessingPower(ra.allocated.getTotalProcessingPower());
			break;
		default:
			throw new StateChangeException(
					"The VM is already bound to a host please first resolve the VM-Host association!");
		}
	}

	/**
	 * Determines what is the resource allocation currently used by the VM.
	 * 
	 * @return the resource set used by the VM, null if there is no resource used by
	 *         the VM currently
	 */
	public PhysicalMachine.ResourceAllocation getResourceAllocation() {
		return ra;
	}

	/**
	 * If there are not enough resources for the VM currently, to recover from this
	 * state (and allow the VM to be rescheduled) just issue a destroy command on
	 * the VM
	 */
	public void setNonservable() {
		setState(State.NONSERVABLE);
	}

	/**
	 * Helper function to get the total size of memory easier than through the VM's
	 * allocation
	 * 
	 * @return the amount of memory used by the VM
	 */
	public long getMemSize() {
		return this.ra.allocated.getRequiredMemory();
	}

	/**
	 * A nice single line output for the VM that shows its state and resource
	 * allocation as well as the tasks it is running. Good for debugging and
	 * tracing.
	 */
	@Override
	public String toString() {
		return "VM(" + currState + " " + ra + " " + super.toString() + ")";
	}
} public class SchedulingDependentMachines extends PhysicalMachineController {

	/**
	 * The main PM control mechanisms are implemented in this class
	 * 
	 * The class basically controls a single PM. It switches off its PM when the
	 * PM's free resources reach its complete resource set and there are no VM
	 * requests queuing at the IaaS service's VM scheduler.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University of Innsbruck (c) 2013"
	 *         "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems, MTA SZTAKI (c) 2012"
	 */
	private class CapacityChangeManager
			implements VMManager.CapacityChangeEvent<ResourceConstraints>, PhysicalMachine.StateChangeListener {

		/**
		 * the physical machine that this capacity manager will target with its
		 * operations
		 */
		final PhysicalMachine observed;

		/**
		 * This constructor is expected to be used once a PM is registered to
		 * the parent IaaSService. From that point on the newly registered PM
		 * will be considered for switching off/turning on.
		 * 
		 * @param pm
		 *            the PM to be managed to follow the demand patterns of the
		 *            VM requests to the IaaSService.
		 */
		public CapacityChangeManager(final PhysicalMachine pm) {
			observed = pm;
			observed.subscribeToIncreasingFreeapacityChanges(this);
			observed.subscribeStateChangeEvents(this);
		}

		/**
		 * if the PM gets dropped from the parent IaaSService then we no longer
		 * need to control its behavior. So the class's active behavior is
		 * disabled by calling this function.
		 */
		private void cancelEvents() {
			observed.unsubscribeFromIncreasingFreeCapacityChanges(this);
			observed.unsubscribeStateChangeEvents(this);
		}

		/**
		 * Allows the observed PM to be switched off and its exceptions handled
		 */
		private void switchoffmachine() {
			try {
				observed.switchoff(null);
				// These exceptions below are only relevant if migration
				// is requested now they will never come.
			} catch (VMManagementException e) {
			} catch (NetworkException e) {
			}
		}

		/**
		 * This function is called when the observed PM has newly freed up
		 * resources. It ensures that the PM is switched off if the PM is
		 * completely free and there are no more VMs queuing at the VM scheduler
		 * (i.e., there will be no chance to receive a new VM for the capacities
		 * of this PM).
		 */
		@Override
		public void capacityChanged(final ResourceConstraints newCapacity,
				final List<ResourceConstraints> newlyFreeCapacities) {
			if (observed.getCapacities().compareTo(newCapacity) <= 0
					&& parent.sched.getTotalQueued().getRequiredCPUs() == 0) {
				// Totally free machine and nothing queued
				switchoffmachine();
			}
		}

		/**
		 * This function is called when the PM's power state changes. This event
		 * handler manages situations when the PM is turned on but there are no
		 * longer tasks for it. Also, it initiates a new PM's switchon if the
		 * newly switched on machine will not be enough to host the queued VM
		 * requests found at the VM scheduler of the parent IaaS service.
		 */
		@Override
		public void stateChanged(PhysicalMachine pm, State oldState, State newState) {
			if (PhysicalMachine.State.RUNNING.equals(newState)) {
				currentlyStartingPM = null;
				if (parent.sched.getQueueLength() == 0) {
					new DeferredEvent(observed.getCurrentOnOffDelay()) {
						// Keeps the just started PM on for a short while to
						// allow some new VMs to arrive, otherwise it seems like
						// we just started the PM for no reason
						@Override
						protected void eventAction() {
							if (!observed.isHostingVMs() && observed.isRunning()) {
								switchoffmachine();
							}
						}
					};
				} else {
					ResourceConstraints runningCapacities = parent.getRunningCapacities();
					if (!parent.runningMachines.contains(observed)) {
						// parent have not recognize this PM's startup yet
						runningCapacities = new AlterableResourceConstraints(runningCapacities);
						((AlterableResourceConstraints) runningCapacities).singleAdd(observed.getCapacities());
					}
					if (runningCapacities.compareTo(parent.sched.getTotalQueued()) < 0) {
						// no capacities to handle the currently queued jobs, so
						// we need to start up further machines
						turnOnAMachine();
					}
				}
			}
		}
	}

	/**
	 * this map lists all the currently controlled PMs and their controllers.
	 */
	private HashMap<PhysicalMachine, CapacityChangeManager> capacityManagers = new HashMap<PhysicalMachine, CapacityChangeManager>();
	/**
	 * ensures that we only have a single machine switching on at a time and
	 * shows what is the actual machine that is switching on.
	 */
	private PhysicalMachine currentlyStartingPM = null;

	/**
	 * Constructs the scheduler and passes the parent IaaSService to the
	 * superclass.
	 * 
	 * @param parent
	 *            the IaaSService to serve
	 */
	public SchedulingDependentMachines(final IaaSService parent) {
		super(parent);
	}

	/**
	 * Defines to do the following when a new host is (de)registered to the
	 * parent IaaSService:
	 * <ul>
	 * <li>if the current event is a registration event then the function
	 * creates and locally registers a new capacity change manager for the newly
	 * registered pms
	 * <li>if the current event is a deregistration event then the function
	 * cancels the capacity management for all deregistered pms
	 * </ul>
	 */
	@Override
	protected VMManager.CapacityChangeEvent<PhysicalMachine> getHostRegEvent() {
		return new CapacityChangeEvent<PhysicalMachine>() {
			@Override
			public void capacityChanged(final ResourceConstraints newCapacity, final List<PhysicalMachine> alteredPMs) {
				final boolean newRegistration = parent.isRegisteredHost(alteredPMs.get(0));
				final int pmNum = alteredPMs.size();
				if (newRegistration) {
					// Management of capacity increase
					for (int i = pmNum - 1; i >= 0; i--) {
						final PhysicalMachine pm = alteredPMs.get(i);
						capacityManagers.put(pm, new CapacityChangeManager(pm));
					}
				} else {
					// Management of capacity decrease
					for (int i = pmNum - 1; i >= 0; i--) {
						capacityManagers.remove(alteredPMs.get(i)).cancelEvents();
					}
				}
			}
		};
	}

	/**
	 * Defines to do the following when VM requests arrive:
	 * <ol>
	 * <li>check if there is already a PM under preparation (if there is one
	 * then does nothing)
	 * <li>if there are no PM that is currently prepared then starts to prepare
	 * one for accepting VM requests.
	 * </ol>
	 */
	@Override
	protected Scheduler.QueueingEvent getQueueingEvent() {
		return new Scheduler.QueueingEvent() {
			@Override
			public void queueingStarted() {
				if (currentlyStartingPM == null
						|| PhysicalMachine.State.RUNNING.equals(currentlyStartingPM.getState())) {
					// If there are no machines under their startup procedure,
					// or the currently started up machine is already running
					// and we still receive the queueingstarted event
					turnOnAMachine();
				}
			}
		};
	}

	/**
	 * switches on a not yet switched on machine from the parent IaaS's PM set.
	 * if there are no more machines in the IaaS that can be turned on then the
	 * calling of this function is ignored.
	 */
	protected void turnOnAMachine() {
		final int pmsize = parent.machines.size();
		if (parent.runningMachines.size() != pmsize) {
			for (int i = 0; i < pmsize; i++) {
				final PhysicalMachine n = parent.machines.get(i);
				if (PhysicalMachine.ToOfforOff.contains(n.getState())) {
					currentlyStartingPM = n;
					n.turnon();
					break;
				}
			}
		}
	}
} public class ResourceConsumption {

	/**
	 * This comparator class provides a simple comparison tool for two resource
	 * consumptions based on their real limits. Useful for sorting the consumptions.
	 */
	public static final Comparator<ResourceConsumption> limitComparator = new Comparator<ResourceConsumption>() {
		@Override
		public int compare(final ResourceConsumption o1, final ResourceConsumption o2) {
			final double upOth = o1.realLimit;
			final double upThis = o2.realLimit;
			return upOth < upThis ? -1 : (upOth == upThis ? 0 : 1);
		}
	};

	/**
	 * If a resource consumption is not supposed to be limited by anything but the
	 * actual resource providers/consumers then this limit could be used in its
	 * constructor.
	 */
	public static final double unlimitedProcessing = Double.MAX_VALUE;

	/**
	 * This interface allows its implementors to get notified when a consumption
	 * completes. Note: the objects will only receive a single call on the below
	 * interfaces depending on the outcome of the resouece consumption's execution.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	public interface ConsumptionEvent {
		/**
		 * This function is called when the resource consumption represented by the
		 * ResourceConsumption object is fulfilled
		 */
		void conComplete();

		/**
		 * This function is called when the resource consumption cannot be handled
		 * properly - if a consumption is suspended (allowing its migration to some
		 * other consumers/providers then this function is <b>not</b> called.
		 */
		void conCancelled(ResourceConsumption problematic);
	}

	/**
	 * The currently processing entities (e.g., a network buffer)
	 * 
	 * <i>NOTE:</i> as this consumption is generic, it is actually the
	 * provider/consumer pair that determines what is the unit of this field
	 */
	private double underProcessing;
	/**
	 * The remaining unprocessed entities (e.g., remaining bytes of a transfer)
	 *
	 * <i>NOTE:</i> as this consumption is generic, it is actually the
	 * provider/consumer pair that determines what is the unit of this field
	 */
	private double toBeProcessed;

	/**
	 * the maximum amount of processing that could be sent from toBeProcessed to
	 * underProcessing in a tick
	 */
	private double processingLimit;
	/**
	 * the user requested processing limit
	 */
	private double requestedLimit;
	/**
	 * the minimum of the perTickProcessing power of the provider/consumer
	 */
	private double hardLimit;
	/**
	 * The processing limit at the particular moment of time (this is set by the
	 * scheduler)
	 * 
	 * This limit is derived from the provider/consumerLimits.
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 */
	private double realLimit;
	/**
	 * 1/2*realLimit
	 */
	private double halfRealLimit;
	/**
	 * The number of ticks it is expected to take that renders both underProcessing
	 * and toBeProcessed as 0 (i.e., the time when the initially specified amount of
	 * resources are completely utilized).
	 */
	private long completionDistance;
	/**
	 * The processing limit imposed because of the provider
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 */
	double providerLimit;
	/**
	 * the processing limit imposed because of the consumer
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 */
	double consumerLimit;
	/**
	 * the amount of processing that can be surely done by both the provider and the
	 * consumer. This is a temporary variable used by the MaxMinFairSpreader to
	 * determine the provider/consumerLimits.
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 */
	double limithelper;
	/**
	 * A helper field to show if the particular resource consumption still
	 * participates in the scheduling process or if it has already finalized its
	 * realLimit value.
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 */
	boolean unassigned;
	/**
	 * A helper field to show if the consumer/providerLimit fields are under update
	 * by MaxMinFairSpreader.assignProcessingPower()
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 */
	boolean inassginmentprocess;

	/**
	 * Added for live migration memDirtyingRate: percentage of memory dirtied
	 */
	protected double memDirtyingRate = 0.0;
	protected long memSize = 0;

	/**
	 * The event to be fired when there is nothing left to process in this
	 * consumption.
	 */
	private final ConsumptionEvent ev;

	/**
	 * The consumer which receives the resources of this consumption.
	 * 
	 * If null, then the consumer must be set before proper operation of the
	 * consumption. As this can be null the resource consumption objects could be
	 * created in multiple phases allowing to first determine the amount of
	 * consumption to be made before actually assigning to a particular consumer.
	 */
	private ResourceSpreader consumer;
	/**
	 * The provider which offers the resources for this consumption.
	 * 
	 * If null, then the provider must be set before proper operation of the
	 * consumption. As this can be null the resource consumption objects could be
	 * created in multiple phases allowing to first determine the amount of
	 * consumption to be made before actually assigning to a particular provider.
	 */
	private ResourceSpreader provider;

	/**
	 * shows if the consumption was suspended (<i>true</i>) or not.
	 */
	private boolean resumable = true;
	/**
	 * shows if the consumption object actually participates in the resource sharing
	 * machanism.
	 */
	private boolean registered = false;
	/**
	 * shows if the consumption event was already sent out to the listener
	 */
	private boolean eventNotFired = true;

	/**
	 * This constructor describes the basic properties of an individual resource
	 * consumption.
	 * 
	 * @param total
	 *            The amount of processing to be done during the lifetime of the
	 *            just created object
	 * @param limit
	 *            the maximum amount of processing allowable for this particular
	 *            resource consumption (this allows the specification of an upper
	 *            limit of any consumption). If there is no upper limit needed then
	 *            this value should be set with the value of the unlimitedProcessing
	 *            field.
	 * @param consumer
	 *            the consumer that will benefit from the resource consumption. This
	 *            field could be null, then the consumer must be set with the
	 *            setConsumer() function.
	 * @param provider
	 *            the provider which will offer its resources for the consumer. This
	 *            field could be null, then the provider must be set with the
	 *            setProvider() function.
	 * @param e
	 *            Specify here the event to be fired when the just created object
	 *            completes its transfers. With this event it is possible to notify
	 *            the entity who initiated the transfer. This event object cannot be
	 *            null. If there is no special event handling is needed then just
	 *            create a ConsumptionEventAdapter.
	 */
	public ResourceConsumption(final double total, final double limit, final ResourceSpreader consumer,
			final ResourceSpreader provider, final ConsumptionEvent e) {
		underProcessing = 0;
		toBeProcessed = total;
		this.consumer = consumer;
		this.provider = provider;
		if (e == null) {
			throw new IllegalStateException("Cannot create a consumption without an event to be fired");
		} else if (total < 0 || limit < 0) {
			throw new IllegalArgumentException("Cannot create negative consumptions");
		}
		ev = e;
		requestedLimit = limit;
	}

	/**
	 * Provides a unified update method for the hard processing limit (which will
	 * become the minimum of the provider's/consumer's per tick processing power) of
	 * this consumption. All values that depend on hard limit (the real and
	 * processing limits) are also updated.
	 * 
	 * This function can be called even if the provider/consumer is not set yet in
	 * that case the processing limit for the non-set spreader will be unlimited.
	 */
	private void updateHardLimit() {
		final double provLimit = provider == null ? unlimitedProcessing : provider.perTickProcessingPower;
		final double conLimit = consumer == null ? unlimitedProcessing : consumer.perTickProcessingPower;
		hardLimit = requestedLimit < provLimit ? requestedLimit : provLimit;
		if (hardLimit > conLimit) {
			hardLimit = conLimit;
		}
		processingLimit = requestedLimit < hardLimit ? requestedLimit : hardLimit;
		setRealLimit(hardLimit);
	}

	/**
	 * Initiates the processing of a resource consumption. By calling this function
	 * the resource consumption object will be participating in the unified resource
	 * sharing mechanism's scheduling and spreading operations.
	 * 
	 * Before the registration actually happens, it updates the hard limit of the
	 * consumption so the spreaders could now operate using its values.
	 * 
	 * <i>NOTE:</i> this function is also used for resuming a suspended consumption
	 * 
	 * @return
	 *         <ul>
	 *         <li><i>true</i> if the registration was successful
	 *         <li><i>false</i> otherwise. For example: if the provider/consumer is
	 *         not yet set, if the consumption cannot be registered between the
	 *         particular provider/consumer pair or if the consumption was already
	 *         registered.
	 *         </ul>
	 */
	public boolean registerConsumption() {
		if (!registered) {
			if (getUnProcessed() == 0) {
				fireCompleteEvent();
				return true;
			} else if (resumable && provider != null && consumer != null) {
				updateHardLimit();
				if (ResourceSpreader.registerConsumption(this)) {
					registered = true;
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Returns the amount of processing still remaining in this resource
	 * consumption.
	 * 
	 * @return the remaining processing
	 */
	public double getUnProcessed() {
		return underProcessing + toBeProcessed;
	}

	/**
	 * terminates the consumption, deregisters it from its consumer/provider pair
	 * and ensures that it can no longer be registered
	 */
	public void cancel() {
		boolean wasRegistered = registered;
		suspend();
		resumable = false;
		if (!wasRegistered) {
			fireCancelEvent();
		}
	}

	/**
	 * Terminates the consumption but ensures that it will be resumable later on. If
	 * a consumption needs to be resumed then it must be re-registered, there is no
	 * special function for resume.
	 */
	public void suspend() {
		if (registered) {
			ResourceSpreader.cancelConsumption(this);
			registered = false;
		}
	}

	/**
	 * Allows to set a provider for the consumption if the consumption is not yet
	 * under way.
	 * 
	 * @param provider
	 *            the provider to be used for offering the resources for the
	 *            consumption
	 */
	public void setProvider(final ResourceSpreader provider) {
		if (!registered) {
			this.provider = provider;
			updateHardLimit();
			return;
		} else {
			throw new IllegalStateException("Attempted consumer change with a registered consumption");
		}
	}

	/**
	 * Allows to set a consumer for the consumption if the consumption is not yet
	 * under way.
	 * 
	 * @param consumer
	 *            the consumer to be used for utilizing the resources received
	 *            through this resource consumption object.
	 */
	public void setConsumer(final ResourceSpreader consumer) {
		if (!registered) {
			this.consumer = consumer;
			updateHardLimit();
			return;
		} else {
			throw new IllegalStateException("Attempted consumer change with a registered consumption");
		}
	}

	/**
	 * Updates the completion distance field, should be called every time the real
	 * limit is updated or when the amount of unprocessed consumption changes.
	 */
	private void calcCompletionDistance() {
		completionDistance = Math.round(getUnProcessed() / realLimit);
	}

	/**
	 * This function simulates how the provider offers the resources for its
	 * consumer. The offered resources are put in the underprocessing field from the
	 * toBeprocessed.
	 * 
	 * If the processing is really close to completion (determined by using
	 * halfreallimit), then this function cheats a bit and offers the resources for
	 * the last remaining processable consumption. This is actually ensuring that we
	 * don't need to simulate sub-tick processing operations.
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 * 
	 * @param ticksPassed
	 *            the number of ticks to be simulated (i.e. how many times we should
	 *            multiply realLimit) before offering the resources to the
	 *            underprocessing field.
	 * @return the amount of resources actually offered for consumption. Negative
	 *         values mark the end of this resource consumption (i.e. when there is
	 *         no more processing to be done for this consumption). Albeit such
	 *         values are negative, their negativeness is just used as a flag and
	 *         their absolute value still represent the amount of offered resources.
	 */
	double doProviderProcessing(final long ticksPassed) {
		double processed = 0;
		if (toBeProcessed > 0) {
			final double possiblePush = ticksPassed * realLimit;
			processed = possiblePush < toBeProcessed ? possiblePush : toBeProcessed;
			toBeProcessed -= processed;
			underProcessing += processed;
			if (toBeProcessed < halfRealLimit) {
				// ensure that tobeprocessed is 0!
				processed += toBeProcessed;
				underProcessing += toBeProcessed;
				toBeProcessed = 0;
				return -processed;
			}
		}
		return processed;
	}

	/**
	 * This function simulates how the consumer utilizes the resources from its
	 * provider. The utilized resources are used from the underprocessing field.
	 * 
	 * If the processing is really close to completion (determined by calculating
	 * the completion distance), then this function cheats a bit and utilizes the
	 * resources for the last remaining underprocessing. This is actually ensuring
	 * that we don't need to simulate sub-tick processing operations.
	 * 
	 * <i>WARNING:</i> this is necessary for the internal behavior of
	 * MaxMinFairSpreader
	 * 
	 * @param ticksPassed
	 *            the number of ticks to be simulated (i.e. how many times we should
	 *            multiply realLimit) before utilizing the resources from the
	 *            underprocessing field.
	 * @return the amount of resources actually utilized by the consumer. Negative
	 *         values mark the end of this resource consumption (i.e. when there is
	 *         no more processing to be done for this consumption). Albeit such
	 *         values are negative, their negativeness is just used as a flag and
	 *         their absolute value still represent the amount of utilized
	 *         resources.
	 */
	double doConsumerProcessing(final long ticksPassed) {
		double processed = 0;
		if (underProcessing > 0) {
			final double possibleProcessing = ticksPassed * realLimit;
			processed = possibleProcessing < underProcessing ? possibleProcessing : underProcessing;
			underProcessing -= processed;
			calcCompletionDistance();
			if (completionDistance == 0) {
				// ensure that tobeprocessed is 0!
				processed += underProcessing;
				underProcessing = 0;
				return -processed;
			}
		}
		return processed;
	}

	/**
	 * Determines the amount of processing for which no resources were offered from
	 * the provider so far.
	 * 
	 * @return the tobeprocessed value
	 */
	public double getToBeProcessed() {
		return toBeProcessed;
	}

	/**
	 * Determines the amount of resoruces already offered by the provider but not
	 * yet used by the consumer.
	 * 
	 * @return the underprocessing value
	 */
	public double getUnderProcessing() {
		return underProcessing;
	}

	/**
	 * Retrieves the maximum amount of processing that could be sent from
	 * toBeProcessed to underProcessing in a single tick
	 */

	public double getProcessingLimit() {
		return processingLimit;
	}

	/**
	 * Retrieves the processing limit at the particular moment of time (just queries
	 * the value last set by the scheduler)
	 */
	public double getRealLimit() {
		return realLimit;
	}

	/**
	 * Retrieves the number of ticks it is expected to take that renders both
	 * underProcessing and toBeProcessed as 0 (i.e., the time when the initially
	 * specified amount of resources are completely utilized). This is again just
	 * the value that is derived from the real limit last set by the scheduler.
	 */
	public long getCompletionDistance() {
		return completionDistance;
	}

	/**
	 * Queries the consumer associated with this resource consumption.
	 * 
	 * @return the consumer which will utilize the resources received through this
	 *         consumption object
	 */
	public ResourceSpreader getConsumer() {
		return consumer;
	}

	/**
	 * Queries the provider associated with this resource consumption.
	 * 
	 * @return the provider which will offer the resources for this particular
	 *         resource consumption object.
	 */
	public ResourceSpreader getProvider() {
		return provider;
	}

	/**
	 * Simultaneously updates the real limit (the instantaneous processing limit
	 * determined by the low level scheduler of the unified resoruce sharing model
	 * of DISSECT-CF) value as well as the halfreallimit field.
	 * 
	 * @param rL
	 *            the value to be set as real limit
	 */
	private void setRealLimit(final double rL) {
		realLimit = rL;
		halfRealLimit = rL / 2;
	}

	/**
	 * Sets the real limit based on the scheduler set provider and consumer limits
	 * (the smaller is used as real).
	 * 
	 * Updates the completion distance if instructed.
	 * 
	 * @param updateCD
	 *            <i>true</i> tells the system to update the completion distance
	 *            alongside the real limit setup. This more frequent update on the
	 *            real limit than the completion distance is calculated.
	 * 
	 *            <i>IMPORTANT:</i> if set to false then it is expected that the
	 *            scheduler will call the updateRealLimit at least once more with a
	 *            true parameter. Failing to do so the consumption object will
	 *            become broken.
	 * @return the real limit that was actually determined and set by this function
	 * @throws IllegalStateException
	 *             if the real limit would become 0
	 */
	double updateRealLimit(final boolean updateCD) {
		final double rlTrial = providerLimit < consumerLimit ? providerLimit : consumerLimit;
		if (rlTrial == 0) {
			throw new IllegalStateException(
					"Cannot calculate the completion distance for a consumption without a real limit! " + this);
		}
		setRealLimit(rlTrial);
		if (updateCD) {
			calcCompletionDistance();
		}
		return realLimit;
	}

	/**
	 * Determines the dirtying rate of this process in a single tick
	 * 
	 * @return the current dirtying rate
	 */
	public double getMemDirtyingRate() {
		return memDirtyingRate;
	}

	/**
	 * Sets the dirtying rate for this RC.
	 * 
	 * <p>
	 * <i>Note</i>, the value set here only considered just before a live migration
	 * round, if it changes during a particular round, the last set dirtying rate
	 * will be used by the VM.
	 * 
	 * @param memDirtyingRate
	 */
	public void setMemDirtyingRate(double memDirtyingRate) {
		if (memDirtyingRate < 0.0 || memDirtyingRate > 1.0)
			throw new IllegalArgumentException("Dirtying rate must be between 0.0 and 1.0");
		this.memDirtyingRate = memDirtyingRate;
	}

	/**
	 * The amount of memory used by the task
	 * 
	 * @return
	 */
	public long getMemSize() {
		return memSize;
	}

	/**
	 * Change the amount of memory used by the task.
	 * <p>
	 * <i>Note</i>, the value set here only considered just before a live migration
	 * round, if it changes during a particular round, the last set size will be
	 * used by the VM.
	 * 
	 * @param newMemSize
	 */
	public void setMemSize(long newMemSize) {
		memSize = newMemSize;
	}

	/**
	 * Provides a nice formatted output of the resource consumption showing how much
	 * processing is under way, how much is still held back and what is the current
	 * real limit set by the scheduler.
	 * 
	 * Intended for debugging and tracing outputs.
	 */
	@Override
	public String toString() {
		return "RC(C:" + underProcessing + " T:" + toBeProcessed + " L:" + realLimit + ")";
	}

	/**
	 * Determines if the object is registered and resources are used because of this
	 * consumption object
	 * 
	 * @return <i>true</i> if the object is registered.
	 */
	public boolean isRegistered() {
		return registered;
	}

	/**
	 * Allows to query whether this resource consumption was cancelled or not
	 * 
	 * @return <i>false</i> if the resource consumption was cancelled and it can no
	 *         longer be registered within the unified resource sharing model of the
	 *         simulator.
	 */
	public boolean isResumable() {
		return resumable;
	}

	/**
	 * Determines the hard processing limit for this resource consumption.
	 * 
	 * @return the hard limit
	 */
	public double getHardLimit() {
		return hardLimit;
	}

	/**
	 * Sends out the completion event to the listener
	 * 
	 * @return false if the event was not sent
	 */
	boolean fireCompleteEvent() {
		if (eventNotFired && getUnProcessed() == 0) {
			eventNotFired = false;
			ev.conComplete();
			return true;
		}
		return false;
	}

	/**
	 * Sends out the cancellation event to the listener
	 * 
	 * @return false if the event was not sent
	 */
	boolean fireCancelEvent() {
		if (eventNotFired) {
			eventNotFired = false;
			ev.conCancelled(this);
			return true;
		}
		return false;
	}
} public class FirstFitScheduler extends Scheduler {

	/**
	 * The set of resource allocations made for the current VM request (this is
	 * important for multi VM requests)
	 */
	ResourceAllocation[] ras = new ResourceAllocation[5];
	/**
	 * the largest allocation that was possible to collect from all running PMs
	 * in the infrastructure. this is important to determine the amount of
	 * resources that need to become free before the scheduler would be able to
	 * place the head of the queue to any of the PMs in the infrastructure.
	 */
	ResourceAllocation raBiggestNotSuitable = null;
	/**
	 * the iterator of the running PMs allowing to easily traverse the PM set in
	 * a predefined order. The iterator plays a crucial role in this
	 * implementation as several FirstFit derivatives only differ in their
	 * handling of the PMs.
	 */
	private final PMIterator it;

	/**
	 * the constructor of the scheduler that passes on the parent IaaS service
	 * and initiates the basic PM iterator for this scheduler which will
	 * 
	 * @param parent
	 */
	public FirstFitScheduler(IaaSService parent) {
		super(parent);
		it = instantiateIterator();
	}

	/**
	 * Allows the customization of the PM iterator by subclasses. This function
	 * is not intended to be used by anything else but the constructor of this
	 * class.
	 * 
	 * @return the desired PM iterator to be used for traversing the PMs while
	 *         doing the scheduling
	 */
	protected PMIterator instantiateIterator() {
		return new PMIterator(parent.runningMachines);
	}

	/**
	 * Resets the iterator then offers it to the caller
	 * 
	 * @return the PMIterator that is ready to be used during the scheduling
	 *         process
	 */
	protected PMIterator getPMIterator() {
		it.reset();
		return it;
	}

	/**
	 * The actual first fit scheduling implementation. This implementation
	 * supports requests with multiple VMs. It assumes that users want to deploy
	 * all VMs or nothing so it waits until all VMs could be deployed at once.
	 */
	@Override
	protected ConstantConstraints scheduleQueued() {
		final PMIterator currIterator = getPMIterator();
		ConstantConstraints returner = new ConstantConstraints(getTotalQueued());
		if (currIterator.hasNext()) {
			QueueingData request;
			ResourceAllocation allocation;
			boolean processableRequest = true;
			int vmNum = 0;
			while (queue.size() > 0 && processableRequest) {
				request = queue.get(0);
				currIterator.restart(false);
				vmNum = 0;
				do {
					processableRequest = false;
					do {
						final PhysicalMachine pm = currIterator.next();
						if (pm.localDisk.getFreeStorageCapacity() >= request.queuedVMs[vmNum].getVa().size) {
							try {
								allocation = pm.allocateResources(request.queuedRC, false,
										PhysicalMachine.defaultAllocLen);
								if (allocation != null) {
									if (allocation.allocated.compareTo(request.queuedRC) >= 0) {
										// Successful allocation
										if (pm.freeCapacities.getRequiredCPUs() == 0 && currIterator.hasNext()) {
											currIterator.next();
										}
										currIterator.markLastCollected();
										if (vmNum == ras.length) {
											ResourceAllocation[] rasnew = new ResourceAllocation[vmNum * 2];
											System.arraycopy(ras, 0, rasnew, 0, vmNum);
											ras = rasnew;
										}
										ras[vmNum] = allocation;
										processableRequest = true;
										break;
									} else {
										if (raBiggestNotSuitable == null) {
											raBiggestNotSuitable = allocation;
										} else {
											if (allocation.allocated.compareTo(raBiggestNotSuitable.allocated) > 0) {
												raBiggestNotSuitable.cancel();
												raBiggestNotSuitable = allocation;
											} else {
												allocation.cancel();
											}
										}
									}
								}
							} catch (VMManagementException e) {
							}
						}
					} while (currIterator.hasNext());
					currIterator.restart(true);
				} while (++vmNum < request.queuedVMs.length && processableRequest);
				if (processableRequest) {
					try {
						for (int i = request.queuedVMs.length - 1; i >= 0; i--) {
							vmNum--;
							allocation = ras[i];
							allocation.getHost().deployVM(request.queuedVMs[i], allocation, request.queuedRepo);
							ras[i]=null;
						}
						manageQueueRemoval(request);
					} catch (VMManagementException e) {
						processableRequest = false;
					} catch (NetworkException e) {
						// Connectivity issues! Should not happen!
						System.err.println("WARNING: there are connectivity issues in the system." + e.getMessage());
						processableRequest = false;
					}
				} else {
					AlterableResourceConstraints arc = new AlterableResourceConstraints(request.queuedRC);
					arc.multiply(request.queuedVMs.length - vmNum + 1);
					if (raBiggestNotSuitable != null) {
						arc = new AlterableResourceConstraints(request.queuedRC);
						arc.subtract(raBiggestNotSuitable.allocated);
					}
					returner = new ConstantConstraints(arc);
				}
				if (raBiggestNotSuitable != null) {
					raBiggestNotSuitable.cancel();
					raBiggestNotSuitable = null;
				}
			}
			vmNum--;
			for (int i = 0; i < vmNum; i++) {
				ras[i].cancel();
				ras[i] = null;
			}
		}
		return returner;
	}
} public static class NetworkException extends Exception {
	private static final long serialVersionUID = 5173643896341066497L;

	public NetworkException(String msg) {
		super(msg);
	}
} public class NetworkNode {

	public static class NetworkException extends Exception {
		private static final long serialVersionUID = 5173643896341066497L;

		public NetworkException(String msg) {
			super(msg);
		}
	}

	/**
	 * The instances of this class represent an individual data transfer in the
	 * system. The visibility of the class and its members are defined so the
	 * compiler does not need to generate access methods for the members thus
	 * allowing fast and prompt changes in its contents.
	 * 
	 * To create a new instance of this class, one must use the initTransfer method
	 * of the NetworkNode.
	 * 
	 * <i>WARNING</i> this is an internal representation of the transfer. This class
	 * is not supposed to be used outside of the context of the NetworkNode.
	 * 
	 * @author "Gabor Kecskemeti, Distributed and Parallel Systems Group, University
	 *         of Innsbruck (c) 2013"
	 * 
	 */
	static class SingleTransfer extends ResourceConsumption {

		/**
		 * This constructor describes the basic properties of an individual transfer.
		 * 
		 * @param tottr
		 *            The amount of data to be transferred during the lifetime of the
		 *            just created object
		 * @param e
		 *            Specify here the event to be fired when the just created object
		 *            completes its transfers. With this event it is possible to notify
		 *            the entity who initiated the transfer.
		 */
		private SingleTransfer(final int latency, final long tottr, final double limit, final MaxMinConsumer in,
				final MaxMinProvider out, final ResourceConsumption.ConsumptionEvent e) {
			super(tottr, limit, in, out, e);
			if (latency != 0) {
				new DeferredEvent(latency) {
					@Override
					protected void eventAction() {
						regAndCancelOnFailure();
					}
				};
			} else {
				regAndCancelOnFailure();
			}
		}

		private void regAndCancelOnFailure() {
			if (!registerConsumption()) {
				cancel();
			}
		}
	}

	/**
	 * Represents the possible states of the network nodes modeled in the system
	 * 
	 * @author "Gabor Kecskemeti, Department of Computer Science, Liverpool John
	 *         Moores University, (c) 2017"
	 * 
	 */
	public static enum State {
		/**
		 * The machine is completely switched off, minimal consumption is recorded.
		 */
		OFF,
		/**
		 * The machine is currently serving VMs. The machine and its VMs are consuming
		 * energy.
		 */
		RUNNING
	};

	State currState;
	/**
	 * Models the incoming network connections of this network node
	 */
	public final MaxMinConsumer inbws;
	/**
	 * Models the outgoing network connections of this network node
	 */
	public final MaxMinProvider outbws;
	/**
	 * Models the write bandwidth of the disk of this network node
	 */
	public final MaxMinConsumer diskinbws;
	/**
	 * Models the read bandwidth of the disk of this network node
	 */
	public final MaxMinProvider diskoutbws;
	/**
	 * Models the memory write bandwidth on this network node
	 */
	public final MaxMinConsumer meminbws;
	/**
	 * Models the memory read bandwidth on this network node
	 */
	public final MaxMinProvider memoutbws;

	private final ResourceSpreader[] allSpreaders;

	/**
	 * The name of this network node (this could be an IP or what is most suitable
	 * for the simulation at hand).
	 */
	private final String name;
	/**
	 * The direct network connections of this network node.
	 * 
	 * Contents of the map:
	 * <ul>
	 * <li>The key of this map lists the names of the network nodes to which this
	 * particular network node is connected.
	 * <li>The value of this map lists the latencies in ticks between this network
	 * node and the node named in the key.
	 * </ul>
	 * 
	 */
	private final Map<String, Integer> latencies;
	/**
	 * Mapping between the various PM states and its representative disk power
	 * behaviors.
	 */
	private final Map<String, PowerState> storagePowerBehavior;
	/**
	 * Mapping between the various PM states and its representative network power
	 * behaviors.
	 */
	private final Map<String, PowerState> networkPowerBehavior;

	/**
	 * This function initializes the bandwidth spreaders for the node to ensure
	 * equal network share for each transfer occurring on the node.
	 * 
	 * @param maxInBW
	 *            the input bw of the node
	 * @param maxOutBW
	 *            the output bw of the node
	 * @param diskBW
	 *            the disk bw of the node
	 */
	public NetworkNode(final String id, final long maxInBW, final long maxOutBW, final long diskBW,
			final Map<String, Integer> latencymap, Map<String, PowerState> diskPowerTransitions,
			Map<String, PowerState> networkPowerTransitions) {
		if (diskPowerTransitions == null || networkPowerTransitions == null) {
			throw new IllegalStateException("Cannot initialize network node without a complete power behavior set");
		}
		storagePowerBehavior = Collections.unmodifiableMap(diskPowerTransitions);
		networkPowerBehavior = Collections.unmodifiableMap(networkPowerTransitions);
		name = id;
		outbws = new MaxMinProvider(maxOutBW);
		inbws = new MaxMinConsumer(maxInBW);
		diskinbws = new MaxMinConsumer(diskBW / 2f);
		diskoutbws = new MaxMinProvider(diskBW / 2f);
		// Just making sure we will have enough bandwidth for every operation we
		// could possibly have
		final double memBW = (maxOutBW + maxInBW + diskBW);
		meminbws = new MaxMinConsumer(memBW);
		memoutbws = new MaxMinProvider(memBW);
		latencies = latencymap;
		allSpreaders = new ResourceSpreader[] { diskinbws, diskoutbws, outbws, inbws, meminbws, memoutbws };
		try {
			setState(State.OFF);
		} catch (NetworkException nex) {
			// Not expected
		}
	}

	/**
	 * Determines the total output bandwidth available for the node
	 * 
	 * @return the maximum bandwidth with this network node can send data to the
	 *         outside world
	 */
	public long getOutputbw() {
		return (long) outbws.getPerTickProcessingPower();
	}

	/**
	 * Determines the total input bandwidth available for the node
	 * 
	 * @return the maximum bandwidth with this network node can receive data from
	 *         the outside world
	 */
	public long getInputbw() {
		return (long) inbws.getPerTickProcessingPower();
	}

	/**
	 * The bandwidth available when duplicating local disk contents.
	 * 
	 * @return the maximal bandwidth usable by the network node while copying a file
	 *         or raw disk blocks on its storage subsystem
	 */
	public long getDiskbw() {
		return (long) diskinbws.getPerTickProcessingPower() * 2;
	}

	/**
	 * This function ensures the proper initialization of an individual transfer.
	 * 
	 * @param size
	 *            defines the size of the transfer to be simulated
	 * @param from
	 *            defines the source of the transfer
	 * @param to
	 *            defines the destination of the transfer
	 * @param e
	 *            defines the way the initiator will be notified upon the completion
	 *            of the transfer
	 * @return the resource consumption object representing the transfer. This is
	 *         returned to allow the cancellation of the object or to allow the
	 *         observation of its state.
	 */
	public static ResourceConsumption initTransfer(final long size, final double limit, final NetworkNode from,
			final NetworkNode to, final ResourceConsumption.ConsumptionEvent e) throws NetworkException {
		from.ensureRunning();
		to.ensureRunning();
		if (from == to) {
			return new SingleTransfer(0, size, limit, from.diskinbws, from.diskoutbws, e);
		} else {
			return new SingleTransfer(checkConnectivity(from, to), size, limit, to.inbws, from.outbws, e);
		}
	}

	private void ensureRunning() throws NetworkException {
		if (!currState.equals(State.RUNNING)) {
			throw new NetworkException("This networknode is not ready for communication");
		}
	}

	/**
	 * This function allows the simplified creation of singletransfer objects for
	 * modeling the operation of writing data to the disk/network of this node from
	 * its memory.
	 * 
	 * @param size
	 *            the amount of data to be transferred from the memory to the
	 *            disk/network (in bytes)
	 * @param limit
	 *            the maximum bandwidth allowed to be available for this particular
	 *            transfer (in bytes/tick)
	 * @param toDisk
	 *            <ul>
	 *            <li><i>true</i> if the transfer should be managed to the network
	 *            node's disk
	 *            <li><i>false</i> if the bytes read from memory should be sent over
	 *            the network
	 *            </ul>
	 * @param e
	 *            to be fired when the transfer completes
	 * @return the resource consumption object that models the transfer. This is
	 *         returned to allow the cancellation of the object or to allow the
	 *         observation of its state.
	 */
	public ResourceConsumption pushFromMemory(final long size, final double limit, boolean toDisk,
			final ResourceConsumption.ConsumptionEvent e) throws NetworkException {
		ensureRunning();
		return new SingleTransfer(0, size, limit, toDisk ? diskinbws : inbws, memoutbws, e);
	}

	/**
	 * This function allows the simplified creation of singletransfer objects for
	 * modeling the operation of reading data from the disk/network of this node to
	 * its memory.
	 * 
	 * @param size
	 *            the amount of data to be transferred to the memory from the
	 *            disk/network (in bytes)
	 * @param limit
	 *            the maximum bandwidth allowed to be available for this particular
	 *            transfer (in bytes/tick)
	 * @param fromDisk
	 *            <ul>
	 *            <li><i>true</i> if the transfer should be managed from the network
	 *            node's disk
	 *            <li><i>false</i> if the bytes written to memory should be received
	 *            over the network
	 *            </ul>
	 * @param e
	 *            to be fired when the transfer completes
	 * @return the resource consumption object that models the transfer. This is
	 *         returned to allow the cancellation of the object or to allow the
	 *         observation of its state.
	 */
	public ResourceConsumption readToMemory(final long size, final double limit, boolean fromDisk,
			final ResourceConsumption.ConsumptionEvent e) throws NetworkException {
		ensureRunning();
		return new SingleTransfer(0, size, limit, meminbws, fromDisk ? diskoutbws : outbws, e);
	}

	/**
	 * Determines if there is direct network connection possible between two network
	 * nodes
	 * 
	 * @param from
	 *            the network node which is expected to send some data
	 * @param to
	 *            the network node which is expected to receive the sent data
	 * @return the network latency of the connection between the two
	 * @throws NetworkException
	 *             if there is no direct connection possible between the two
	 *             specified nodes.
	 */
	public static int checkConnectivity(final NetworkNode from, final NetworkNode to) throws NetworkException {
		if (from == to) {
			return 0;
		}
		final Integer lat = from.latencies.get(to.name);
		if (lat == null)
			throw new NetworkException("No connection between: '" + from.name + "' and '" + to.name + "'");
		return lat;
	}

	/**
	 * Allows to query the networknode's name
	 * 
	 * @return the name of the node
	 */
	public String getName() {
		return name;
	}

	/**
	 * provides an overview of the network node concentrating on the network's
	 * properties. useful for tracing and debug.
	 */
	@Override
	public String toString() {
		return "NetworkNode(Id:" + name + " NI:" + getInputbw() + ",NO:" + getOutputbw() + " -- RX:"
				+ inbws.getTotalProcessed() + " TX:" + outbws.getTotalProcessed() + " --, D:" + getDiskbw() + ")";
	}

	public void setState(State newState) throws NetworkException {
		if (currState != null) {
			if (currState.equals(newState)) {
				return;
			}
			if (currState.equals(State.RUNNING)) {
				for (ResourceSpreader rs : allSpreaders) {
					if (rs.toBeAdded.size() + rs.underProcessing.size() > 0) {
						throw new NetworkException(
								"There is still some network activity in progress, cannot transition to a non-running state");
					}
				}
			}
		}
		currState = newState;
		PowerState curStBehaviour = PowerTransitionGenerator.getPowerStateFromMap(storagePowerBehavior,
				newState.toString());
		PowerState curNwBehaviour = PowerTransitionGenerator.getPowerStateFromMap(networkPowerBehavior,
				newState.toString());
		diskinbws.setCurrentPowerBehavior(curStBehaviour);
		diskoutbws.setCurrentPowerBehavior(curStBehaviour);
		inbws.setCurrentPowerBehavior(curNwBehaviour);
		outbws.setCurrentPowerBehavior(curNwBehaviour);
	}

	public long getLastEvent() {
		long latest = -1;
		for (ResourceSpreader rs : allSpreaders) {
			ResourceSpreader.FreqSyncer fs = rs.getSyncer();
			if (fs.isSubscribed()) {
				latest = Math.max(latest, fs.getNextEvent());
			}
		}
		return latest;
	}
} public class Repository extends NetworkNode {

	/**
	 * Stuff that is already in the current repository
	 */
	final HashMap<String, StorageObject> contents = new HashMap<String, StorageObject>(16);

	/**
	 * Contents that are under transfer, to ensure that we are not allowing the
	 * deletion of contents that are being transferred currently
	 */

	final HashSet<String> underTransfer = new HashSet<String>();

	/**
	 * The total possible size of the contents in the current repository
	 */
	final private long maxStorageCapacity;
	/**
	 * The current total size of the contents in the actual repository object
	 */
	private long currentStorageUse = 0;
	/**
	 * The amount of contents that are about to arrive.
	 */
	private long promisedStorage = 0;

	/**
	 * Constructor for repository objects
	 * 
	 * @param capacity
	 *            the storage capacity of the repository
	 * @param maxInBW
	 *            the input network bandwidth of the repository
	 * @param maxOutBW
	 *            the output network bandwidth of the repository
	 * @param diskBW
	 *            the disk bandwidth of the repository
	 */

	public Repository(final long capacity, final String id, final long maxInBW, final long maxOutBW, final long diskBW,
			final Map<String, Integer> latencyMap, Map<String, PowerState> diskPowerTransitions,
			Map<String, PowerState> networkPowerTransitions) {
		super(id, maxInBW, maxOutBW, diskBW, latencyMap, diskPowerTransitions, networkPowerTransitions);
		maxStorageCapacity = capacity;
	}

	/**
	 * This function is designed to initially set up the repository contents. It
	 * does not simulate data movement, for data movement simulation please use the
	 * request content delivery function. The function also ensures that the given
	 * StorageObject is only stored once.
	 * 
	 * @param so
	 *            is the object to be stored
	 * @return true if the reuqested object was stored, false when there is not
	 *         enough space to store the object
	 */
	public boolean registerObject(final StorageObject so) {
		if (!contents.containsKey(so.id)) {
			final long futureFree = getFreeStorageCapacity() - so.size;
			if (futureFree < 0) {
				return false;
			}
			contents.put(so.id, so);
			currentStorageUse += so.size;
		}
		return true;
	}

	/**
	 * This function is designed to simulate the erase function of the repository
	 * given that its user knows the StorageObject to be dropped.
	 * 
	 * @param so
	 *            The storage object to be removed from the repository
	 * @return
	 *         <ul>
	 *         <li>true, if the requested object was dropped from the repo,
	 *         <li>false if there are ongoing transfers involving the object
	 *         </ul>
	 */
	public boolean deregisterObject(final StorageObject so) {
		if (so == null) {
			// Nothing to remove so we can report success.
			return true;
		}
		return deregisterObject(so.id);
	}

	/**
	 * This function is designed to simulate the erase function of the repository
	 * given that its user knows the identifier of the content to be dropped.
	 * 
	 * @param soid
	 *            The storage object identifier
	 * @return
	 *         <ul>
	 *         <li>true, if the requested object was dropped from the repo,
	 *         <li>false if there are ongoing transfers involving the object
	 *         </ul>
	 */
	public boolean deregisterObject(final String soid) {
		if (soid == null) {
			// Nothing to remove so we can report success.
			return true;
		}
		if (!underTransfer.contains(soid)) {
			StorageObject removed = contents.remove(soid);
			if (removed != null) {
				currentStorageUse -= removed.size;
				return true;
			}
		}
		return false;
	}

	/**
	 * Initiates transfer from a remote location
	 * 
	 * @param id
	 *            The storage object id that will be transferred
	 * @param target
	 *            The target repository where the transferred data will reside
	 * @param ev
	 *            the event to be fired if the transfer is completed
	 * @return the consumption object that represents the appropriate data transfer
	 *         or <b>null</b> if it is not possible to initiate
	 */
	public ResourceConsumption requestContentDelivery(final String id, final Repository target,
			final ResourceConsumption.ConsumptionEvent ev) throws NetworkException {
		return requestContentDelivery(id, null, target, ev);
	}

	/**
	 * Initiates the duplication of some repository content <br>
	 * 
	 * @param id
	 *            The storage object id that will be duplicated
	 * @param newId
	 *            The name of the copied storage object id if the target is the same
	 *            repository where the request is made.
	 * @param ev
	 *            the event to be fired if the transfer is completed
	 * @return the consumption object that represents the appropriate data
	 *         duplication or <b>null</b> if it is not possible to initiate
	 */
	public ResourceConsumption duplicateContent(final String id, final String newId,
			final ResourceConsumption.ConsumptionEvent ev) throws NetworkException {
		return requestContentDelivery(id, newId, this, ev);
	}

	/**
	 * This function registers a storage object for transfer. This object must be
	 * already stored in the requested repository. After the transfer is completed
	 * the function ensures that the target repository registers the transferred
	 * object.
	 * 
	 * @param id
	 *            The storage object id that will be transferred
	 * @param newId
	 *            The name of the copied storage object id if it needs to be
	 *            changed. If the target is the same repository this must be
	 *            specified. If the caller needs the same storage id then null can
	 *            be specified here.
	 * @param target
	 *            The target repository where the transferred data will reside. If
	 *            the target is the same repository please check the specific
	 *            requirements for newId!
	 * @param ev
	 *            the event to be fired if the transfer is completed
	 * @return the consumption object that represents the appropriate data transfer
	 *         or <b>null</b> if it is not possible to initiate. The system will not
	 *         fire a transfer event if false is returned!
	 */
	public ResourceConsumption requestContentDelivery(final String id, final String newId, final Repository target,
			final ResourceConsumption.ConsumptionEvent ev) throws NetworkException {
		if (target == null || (this == target && (newId == null || newId.equals(id))))
			return null;
		final StorageObject totransfer = contents.get(id);
		if (totransfer == null) {
			return null;
		}
		return manageStoragePromise(totransfer.size, id, target, new MainStorageActivity() {
			@Override
			public ResourceConsumption doStorage() throws NetworkException {
				underTransfer.add(id);
				return initTransfer(totransfer.size, ResourceConsumption.unlimitedProcessing, Repository.this, target,
						new ResourceConsumption.ConsumptionEvent() {
							private void cleanUpRepos() {
								underTransfer.remove(id);
								target.promisedStorage -= totransfer.size;
							}

							@Override
							public void conComplete() {
								cleanUpRepos();
								target.registerObject(
										(target == Repository.this || newId != null) ? totransfer.newCopy(newId)
												: totransfer);
								if (ev != null) {
									ev.conComplete();
								}
							}

							@Override
							public void conCancelled(ResourceConsumption problematic) {
								cleanUpRepos();
								if (ev != null) {
									ev.conCancelled(problematic);
								}
							}
						});
			}
		});
	}

	/**
	 * An internal interface for managing storage related operations
	 * 
	 * @author "Gabor Kecskemeti, Laboratory of Parallel and Distributed Systems,
	 *         MTA SZTAKI (c) 2015"
	 *
	 */
	private static interface MainStorageActivity {
		/**
		 * The action that actually does the depositing of the requested content
		 * 
		 * @return the consumption object that represents the appropriate data transfer
		 *         or <b>null</b> if it is not possible to initiate
		 * @throws NetworkException
		 *             if there are connectivity errors amongst repositories
		 */
		ResourceConsumption doStorage() throws NetworkException;
	}

	/**
	 * Manages the promisedStorage field of repository objects. It is used
	 * internally to uniformly manage the promised storage from the various
	 * functions of the repository.
	 * 
	 * WARNING: tis function only manages the increase of the promised storage, the
	 * decrease must be handled by the entity implementing the actual storage
	 * activity
	 * 
	 * @param size
	 *            the amount of size to be deposited in the repository
	 * @param id
	 *            the storage object's id to be deposited
	 * @param target
	 *            the repository in which the storage object will be deposited
	 * @param mainActivity
	 *            the storage activity to be done if there is enough promised
	 *            storage on the target repository
	 * @return the consumption object that represents the appropriate data transfer
	 *         or <b>null</b> if it is not possible to initiate
	 * @throws NetworkException
	 *             if there were connectivity problems with the target reppository
	 */
	private static ResourceConsumption manageStoragePromise(final long size, final String id, final Repository target,
			final MainStorageActivity mainActivity) throws NetworkException {
		final long increasedpromise = target.promisedStorage + size;
		if (increasedpromise + target.currentStorageUse <= target.maxStorageCapacity) {
			target.promisedStorage = increasedpromise;
			return mainActivity.doStorage();
		}
		return null;

	}

	/**
	 * Allows the modeling of storing data that previously resided in the memory of
	 * this repository.
	 * 
	 * @param so
	 *            the storage object that represents the data in memory
	 * @param ev
	 *            the event to be fired upon completing the storage operation
	 * @return the consumption object that represents the appropriate data transfer
	 *         or <b>null</b> if it is not possible to initiate (e.g., if the to be
	 *         stored storage object is already in the repository)
	 * @throws NetworkException
	 *             propagated from MainStorageActivity, never used here.
	 */
	public ResourceConsumption storeInMemoryObject(final StorageObject so,
			final ResourceConsumption.ConsumptionEvent ev) throws NetworkException {
		if (lookup(so.id) != null) {
			return null;
		}
		return manageStoragePromise(so.size, so.id, this, new MainStorageActivity() {
			@Override
			public ResourceConsumption doStorage() throws NetworkException {
				return pushFromMemory(so.size, ResourceConsumption.unlimitedProcessing, true,
						new ResourceConsumption.ConsumptionEvent() {
							@Override
							public void conComplete() {
								promisedStorage -= so.size;
								registerObject(so);
								if (ev != null) {
									ev.conComplete();
								}
							}

							@Override
							public void conCancelled(ResourceConsumption problematic) {
								promisedStorage -= so.size;
								if (ev != null) {
									ev.conCancelled(problematic);
								}
							}
						});
			}
		});
	}

	/**
	 * Allows the modeling of getting an storage object from the disk into the
	 * memory.
	 * 
	 * @param so
	 *            the storage object to be read from the repository
	 * @param ev
	 *            the event to be fired upon completing the transfer of the above
	 *            object to the memory of the repository.
	 * @return the consumption object that represents the appropriate data transfer
	 *         or <b>null</b> if it is not possible to initiate (e.g., if the to be
	 *         stored storage object is already in the repository)
	 */
	public ResourceConsumption fetchObjectToMemory(final StorageObject so,
			final ResourceConsumption.ConsumptionEvent ev) throws NetworkException {
		if (lookup(so.id) == null) {
			return null;
		}
		underTransfer.add(so.id);
		return readToMemory(so.size, ResourceConsumption.unlimitedProcessing, true,
				new ResourceConsumption.ConsumptionEvent() {

					@Override
					public void conComplete() {
						underTransfer.remove(so.id);
						if (ev != null) {
							ev.conComplete();
						}
					}

					@Override
					public void conCancelled(ResourceConsumption problematic) {
						underTransfer.remove(so.id);
						if (ev != null) {
							ev.conCancelled(problematic);
						}
					}
				});
	}

	/**
	 * Searches and returns the storage object with a given identifier
	 * 
	 * @param soid
	 *            the id of the storage object in question
	 * @return if found, the storage object, otherwise null
	 */
	public StorageObject lookup(final String soid) {
		return contents.get(soid);
	}

	/**
	 * Offers an unmodifiable list of contents.
	 * 
	 * @return the list of storage objects stored in this repository
	 */
	public Collection<StorageObject> contents() {
		return Collections.unmodifiableCollection(contents.values());
	}

	/**
	 * provides a summary of this repository good for debugging.
	 */
	@Override
	public String toString() {
		return "Repo(DS:" + maxStorageCapacity + " Used:" + currentStorageUse + " " + super.toString() + ")";
	}

	/**
	 * Retrieves the maximum storage capacity of this repository. This is constant
	 * during the life of the repository.
	 * 
	 * @return the maximum storage capacity
	 */
	public long getMaxStorageCapacity() {
		return maxStorageCapacity;
	}

	/**
	 * Retrieves the currently available free space on this repository. This can
	 * vary from call to call.
	 * 
	 * @return the available storage for depositing storage objects.
	 */
	public long getFreeStorageCapacity() {
		return maxStorageCapacity - currentStorageUse - promisedStorage;
	}
} public class IaaSRelatedFoundation extends VMRelatedFoundation {
	public final static int dummyPMCoreCount = 1;
	public final static double dummyPMPerCorePP = 1;
	public final static int vaSize = 100;
	public final static long dummyPMMemory = vaSize * 40;
	private final static HashMap<String, Integer> globalLatencyMapInternal = new HashMap<String, Integer>(10000);
	public final static Map<String, Integer> globalLatencyMap = Collections.unmodifiableMap(globalLatencyMapInternal);

	@BeforeClass
	public static void preloadIaaS() throws Exception {
		new IaaSRelatedFoundation().getNewServiceArray();
	}

	@Before
	public void resetLatencyMap() {
		globalLatencyMapInternal.clear();
	}

	public static String generateName(final String prefix, final int latency) {
		return generateNames(1, prefix, latency)[0];
	}

	public static String[] generateNames(final int count, final String prefix, final int latency) {
		final byte[] seed = new byte[4 * count];
		SeedSyncer.centralRnd.nextBytes(seed);
		final String[] names = new String[count];
		for (int i = 0; i < count; i++) {
			final int mult = i * 4;
			names[i] = prefix + seed[mult] + seed[mult + 1] + seed[mult + 2] + seed[mult + 3];
			globalLatencyMapInternal.put(names[i], latency);
		}
		return names;
	}

	public static PhysicalMachine[] dummyPMsCreator(final int machineCount, final int corecount, final double pcpp,
			final long memory) {
		final PhysicalMachine[] pms = new PhysicalMachine[machineCount];
		final String[] names = generateNames(machineCount, "M", 1);
		for (int i = 0; i < machineCount; i++) {
			pms[i] = new PhysicalMachine(corecount, pcpp, memory, dummyRepoWithName(false, names[i]), 1, 1,
					defaultHostTransitions);
		}
		return pms;

	}

	public static PhysicalMachine dummyPMcreator() {
		return dummyPMsCreator(1, dummyPMCoreCount, dummyPMPerCorePP, dummyPMMemory)[0];
	}

	public static Repository dummyRepoWithName(boolean withVa, String name) {
		final Repository repo = new Repository(vaSize * 400, name, 1, 1, 1, globalLatencyMapInternal,
				defaultStorageTransitions, defaultNetworkTransitions);
		if (withVa) {
			final VirtualAppliance va = new VirtualAppliance("VA", 2000, 0, false, vaSize / 5);
			Assert.assertTrue("Registration should succeed", repo.registerObject(va));
		}
		return repo;

	}

	public static Repository dummyRepoCreator(boolean withVA) {
		return dummyRepoWithName(withVA, generateName("R", 3));
	}

	public static IaaSService setupIaaS(Class<? extends Scheduler> vmsch,
			Class<? extends PhysicalMachineController> pmsch, final int hostCount, final int coreCount)
			throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		final IaaSService basic = new IaaSService(vmsch, pmsch);
		basic.bulkHostRegistration(
				Arrays.asList(dummyPMsCreator(hostCount, coreCount, dummyPMPerCorePP, dummyPMMemory)));
		basic.registerRepository(dummyRepoCreator(true));
		return basic;
	}

	public void fireVMat(final IaaSService iaas, long distance, final double processing, final int corecount) {
		new DeferredEvent(distance) {
			@Override
			protected void eventAction() {
				final ResourceConstraints pmsize = iaas.machines.get(0).getCapacities();
				int instancecount = pmsize.getRequiredCPUs() >= corecount ? 1
						: (corecount / ((int) pmsize.getRequiredCPUs()))
								+ ((corecount % (int) pmsize.getRequiredCPUs()) == 0 ? 0 : 1);
				double requestedprocs = ((double) corecount) / instancecount;
				final ResourceConstraints vmsize = new UnalterableConstraintsPropagator(
						new AlterableResourceConstraints(requestedprocs, pmsize.getRequiredProcessingPower(), 512));
				final Repository repo = iaas.repositories.get(0);

				try {
					VirtualMachine[] vms = iaas.requestVM((VirtualAppliance) repo.contents().iterator().next(), vmsize,
							repo, instancecount);
					for (int i = 0; i < vms.length; i++) {
						vms[i].subscribeStateChange(new VirtualMachine.StateChange() {
							@Override
							public void stateChanged(final VirtualMachine vm, VirtualMachine.State oldState,
									VirtualMachine.State newState) {
								if (VirtualMachine.State.RUNNING.equals(newState)) {
									try {
										vm.newComputeTask(
												processing * vm.getResourceAllocation().allocated
														.getTotalProcessingPower(),
												ResourceConsumption.unlimitedProcessing, new ConsumptionEventAssert() {
													@Override
													public void conComplete() {
														super.conComplete();
														try {
															vm.destroy(false);
														} catch (VMManagementException e) {
															throw new IllegalStateException(e);
														}
													}
												});
									} catch (Exception e) {
										throw new IllegalStateException(e);
									}
								}
							}
						});
					}
				} catch (Exception e) {
					throw new IllegalStateException(e);
				}
			}
		};
	}

	public ArrayList<IaaSService> getNewServiceArray() throws Exception {
		ArrayList<IaaSService> serviceArray = new ArrayList<IaaSService>();
		serviceArray.add(new IaaSService(FirstFitScheduler.class, AlwaysOnMachines.class));
		serviceArray.add(new IaaSService(FirstFitScheduler.class, SchedulingDependentMachines.class));
		serviceArray.add(new IaaSService(NonQueueingScheduler.class, AlwaysOnMachines.class));
		serviceArray.add(new IaaSService(NonQueueingScheduler.class, SchedulingDependentMachines.class));
		serviceArray.add(new IaaSService(SmallestFirstScheduler.class, AlwaysOnMachines.class));
		serviceArray.add(new IaaSService(SmallestFirstScheduler.class, SchedulingDependentMachines.class));
		serviceArray.add(new IaaSService(RandomScheduler.class, AlwaysOnMachines.class));
		serviceArray.add(new IaaSService(RandomScheduler.class, SchedulingDependentMachines.class));
		return serviceArray;
	}
}
import hu.mta.sztaki.lpds.cloud.simulator.DeferredEvent;
import hu.mta.sztaki.lpds.cloud.simulator.Timed;
import hu.mta.sztaki.lpds.cloud.simulator.energy.EnergyMeter;
import hu.mta.sztaki.lpds.cloud.simulator.energy.MonitorConsumption;
import hu.mta.sztaki.lpds.cloud.simulator.energy.powermodelling.ConstantConsumptionModel;
import hu.mta.sztaki.lpds.cloud.simulator.energy.powermodelling.LinearConsumptionModel;
import hu.mta.sztaki.lpds.cloud.simulator.energy.powermodelling.PowerState;
import hu.mta.sztaki.lpds.cloud.simulator.energy.specialized.IaaSEnergyMeter;
import hu.mta.sztaki.lpds.cloud.simulator.energy.specialized.PhysicalMachineEnergyMeter;
import hu.mta.sztaki.lpds.cloud.simulator.energy.specialized.SimpleVMEnergyMeter;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.IaaSService;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.PhysicalMachine;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.PhysicalMachine.State;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.VMManager.VMManagementException;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.constraints.ResourceConstraints;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.VirtualMachine;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.pmscheduling.AlwaysOnMachines;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.pmscheduling.SchedulingDependentMachines;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.resourcemodel.ResourceConsumption;
import hu.mta.sztaki.lpds.cloud.simulator.iaas.vmscheduling.FirstFitScheduler;
import hu.mta.sztaki.lpds.cloud.simulator.io.NetworkNode.NetworkException;
import hu.mta.sztaki.lpds.cloud.simulator.io.NetworkNode;
import hu.mta.sztaki.lpds.cloud.simulator.io.Repository;
import hu.mta.sztaki.lpds.cloud.simulator.io.VirtualAppliance;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import at.ac.uibk.dps.cloud.simulator.test.ConsumptionEventAssert;
import at.ac.uibk.dps.cloud.simulator.test.IaaSRelatedFoundation;
/*
 *  ========================================================================
 *  DIScrete event baSed Energy Consumption simulaTor 
 *    					             for Clouds and Federations (DISSECT-CF)
 *  ========================================================================
 *  
 *  This file is part of DISSECT-CF.
 *  
 *  DISSECT-CF is free software: you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or (at
 *  your option) any later version.
 *  
 *  DISSECT-CF is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 *  General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with DISSECT-CF.  If not, see <http://www.gnu.org/licenses/>.
 *  
 *  (C) Copyright 2014, Gabor Kecskemeti (gkecskem@dps.uibk.ac.at,
 *   									  kecskemeti.gabor@sztaki.mta.hu)
 */

package at.ac.uibk.dps.cloud.simulator.test.simple.cloud;





public class PowerMeterTest extends IaaSRelatedFoundation {

	@Test(timeout = 100)
	public void VMmeasurementTest() throws VMManagementException, NetworkException {