package holeg.model; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; /** * Representative of a flexibility for a HolonElement. */ public class Flexibility { /* * MODEL */ /** * The Name of a Flexibility. */ public String name; /** * How fast in TimeSteps the Flexibility can be activated. */ public int speed; /** * How high the cost for a activation are. */ public float cost; /** * SHould this Flexibility be Offered when is constrainList is fulfilled the flexibility can be * activated. */ public boolean offered; /** * The List of Constrains the Flexibility */ public List constrainList; /** * The owner of the Flexibility. */ private transient HolonElement element; /** * The Duration in TimeSteps how long the Flexibility is activated. */ private int duration; /** The Element this flexibility is assigned.*/ /** * The Duration after a successful activation between the next possible activation. */ private int cooldown; /* * STATE */ private transient FlexState state = FlexState.OFFERED; private transient int timeStep; private transient int activationTime = -1; private transient int durationEndTime = -1; private transient int coolDownEndTime = -1; public Flexibility(HolonElement element) { this(0, 0.f, 1, 0, false, element); } public Flexibility(int speed, float cost, int duration, int cooldown, boolean offered, HolonElement element) { this.speed = speed; this.cost = cost; setDuration(duration); setCooldown(cooldown); this.offered = offered; this.element = element; constrainList = new ArrayList(); } public HolonElement getElement() { return element; } public void setElement(HolonElement element) { this.element = element; } public int getDuration() { return duration; } /** * Minimum duration is 1 TimeStep. */ public void setDuration(int duration) { this.duration = Math.max(1, duration); } public int getCooldown() { return cooldown; } /** * No negative cooldown TimeSteps. */ public void setCooldown(int cooldown) { this.cooldown = Math.max(0, cooldown); } /** * returns the total energy Amount accumulated over the TimeSteps. */ public float magnitude() { return ((float) duration) * element.getEnergy(); } public float energyReleased() { return (constrainList.stream().map(Constrain::getName).anyMatch(name -> name.equals("onConstrain")) ? -1.0f : 1.0f) * element.getEnergy(); } public boolean isPositive() { return energyReleased() >= 0; } public boolean isNegative() { return energyReleased() < 0; } public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } @Override public String toString() { return "Flexibility: " + name + " from [HolonElement: " + element.getName() + "]"; } void calculateState(int timestep) { this.timeStep = timestep; state = revalidateState(); } public boolean order() { if (canOrder()) { state = FlexState.IN_USE; durationEndTime = timeStep + this.getDuration(); coolDownEndTime = durationEndTime + this.getCooldown(); activationTime = timeStep; return true; } return false; } public boolean cancel() { if (activationTime == timeStep) { reset(); return true; } return false; } void reset() { durationEndTime = -1; coolDownEndTime = -1; state = revalidateState(); } public boolean canActivate() { return remainingTimeTillActivation() == 0; } public boolean canOrder() { boolean flexIsOffered = state.equals(FlexState.OFFERED); return flexIsOffered && !element.isFlexActive(); } public FlexState getState() { return state; } public int remainingTimeTillActivation() { return Math.max(0, coolDownEndTime - timeStep); } public int remainingDuration() { return Math.max(0, durationEndTime - timeStep); } /** * Checks if all assigned constrains are fulfilled. When no constrains assigned returns true. */ private boolean fulfillsConstrains() { return constrainList.stream().map(Constrain::getConstrainFunction).reduce(Predicate::and) .orElse(f -> true).test(this); } private FlexState revalidateState() { if (canActivate()) { if (!this.fulfillsConstrains() || element.isFlexActive()) { return FlexState.UNAVAILABLE; } else if (this.offered) { return FlexState.OFFERED; } return FlexState.NOT_OFFERED; } else if (remainingDuration() == 0) { return FlexState.ON_COOLDOWN; } else { return FlexState.IN_USE; } } public enum FlexState { IN_USE, ON_COOLDOWN, OFFERED, NOT_OFFERED, UNAVAILABLE } }