package classes;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

import com.google.gson.annotations.Expose;
/**
 * Representative of a flexibility for a HolonElement.
 *
 */
public class Flexibility {
	/** The Name of a Flexibility.*/
	@Expose
	public String name;
	/** How fast in TimeSteps the Flexibility can be activated. */
	@Expose
	public int speed;
	/** How high the cost for a activation are. */
	@Expose
	public float cost;
	/** SHould this Flexibility be Offered when is constrainList is fulfilled the flexibility can be activated.*/
	@Expose
	public boolean offered;
	/** The Duration in TimeSteps how long the Flexibility is activated.*/
	@Expose
	private int duration;
	/** The Duration after a successful activation between the next possible activation.*/
	@Expose
	private int cooldown;
	/** The Element this flexibility is assigned.*/
	private HolonElement element;





	/** The List of Constrains the Flexibility */
	@Expose
	public List<Constrain> constrainList;
	
	
	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<Constrain>();		
	}
	
	
	/** Checks if all assigned constrains are fulfilled. When no constrains assigned returns true.*/
	public boolean fulfillsConstrains() {
		//System.out.println("Fix me when other is fixed");
		return constrainList.stream().map(constrain -> constrain.getConstrainFunction()).reduce(Predicate::and).orElse(f -> true).test(this);
	}
	
	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.getEnergyPerElement() * element.getAmount();
	}
	
	public float bringtmir(){
		//System.out.println("Name:" +  element.getEleName() + "   BringtMir:" + (-element.getEnergyPerElement() * element.getAmount()));
		return (constrainList.stream().map(constrain -> constrain.getName()).anyMatch(name -> name.equals("onConstrain"))?-1.0f:1.0f) * element.getEnergyPerElement() * element.getAmount();
	}
	public boolean isPositive() {
		return bringtmir() >= 0;
	}
	public boolean isNegative() {
		return bringtmir() < 0;
	}
	
	
	
	public int getSpeed() {
		return speed;
	}
	public void setSpeed(int speed) {
		this.speed = speed;
	}
	@Override
	public String toString() {
		return "Flexibility: " + name + " from [HolonElement: " + element.getEleName() + " ID:" + element.getId()+"]";
	}

	
	

	
	
	
	
}
