package model;

import java.util.ArrayList;

import classes.Node;
import model.DecoratedHolonObject.HolonObjectState;
import classes.GroupNode;
/**
 * For the @VisualRepresentationalState only.
 * @author Tom
 *
 */
public class DecoratedGroupNode {
	private GroupNode model;
	private ArrayList<Supplier> supplierList;
	private ArrayList<Passiv> passivList;
	private ArrayList<Consumer> consumerList;
	private ArrayList<Node> nodeList;
	/**
	 * Cables that only exist on that group node. From a object in that group node to a object in that group Node.
	 * Not exit the group node (a layer down).
	 */
	private ArrayList<DecoratedCable> internCableList;
	/**
	 * Cables that exit this group node (a Layer Up). From a object in this group node to a object in a upper layer.
	 */
	private ArrayList<ExitCable> exitCableList;	
	private ArrayList<DecoratedSwitch> switchList;
	private ArrayList<DecoratedGroupNode> groupNodeList;



	public DecoratedGroupNode(GroupNode model) {
		this.model = model;
		this.supplierList = new ArrayList<Supplier>();
		this.passivList = new ArrayList<Passiv>();
		this.consumerList = new ArrayList<Consumer>();
		this.nodeList = new ArrayList<Node>();
		this.internCableList = new ArrayList<DecoratedCable>();
		this.exitCableList = new ArrayList<ExitCable>();
		this.switchList = new ArrayList<DecoratedSwitch>();
		this.groupNodeList = new ArrayList<DecoratedGroupNode>();
	}
	public GroupNode getModel() {
		return model;
	}
	public ArrayList<Supplier> getSupplierList() {
		return supplierList;
	}
	public ArrayList<Passiv> getPassivList() {
		return passivList;
	}
	public ArrayList<Consumer> getConsumerList() {
		return consumerList;
	}
	public ArrayList<Node> getNodeList() {
		return nodeList;
	}
	public ArrayList<DecoratedCable> getInternCableList() {
		return internCableList;
	}
	public ArrayList<ExitCable> getExitCableList() {
		return exitCableList;
	}
	public ArrayList<DecoratedSwitch> getSwitchList() {
		return switchList;
	}
	public ArrayList<DecoratedGroupNode> getGroupNodeList() {
		return groupNodeList;
	}
	
	
	//Returns the amount of holons and count himself 
	public int getAmountOfGroupNodes() {
		return 1 + groupNodeList.stream().map(groupNode -> groupNode.getAmountOfGroupNodes()).reduce(0, Integer::sum);
	}
	
	
	//Gather Informations:
	public int getAmountOfSupplier() {
		return supplierList.size() + groupNodeList.stream().map(groupNode -> groupNode.getAmountOfSupplier()).reduce(0, Integer::sum);
	}
	public int getAmountOfConsumer() {
		return consumerList.size() + groupNodeList.stream().map(groupNode -> groupNode.getAmountOfConsumer()).reduce(0,Integer::sum);
	}
	public int getAmountOfPassiv() {
		return passivList.size() + groupNodeList.stream().map(groupNode -> groupNode.getAmountOfPassiv()).reduce(0, Integer::sum);
	}
	
	public int getAmountOfConsumerWithState(HolonObjectState state) {
		return ((int) consumerList.stream().map(con -> con.getState()).filter(rightState -> (rightState == state)).count()) +  groupNodeList.stream().map(groupNode -> groupNode.getAmountOfConsumerWithState(state)).reduce(0, Integer::sum);
	}
	
	public int getAmountOfElemntsFromHolonObjects() {
		return passivList.stream().map(object -> object.getModel().getElements().size()).reduce(0, Integer::sum)+
				supplierList.stream().map(object -> object.getModel().getElements().size()).reduce(0, Integer::sum)+
				consumerList.stream().map(object -> object.getModel().getElements().size()).reduce(0, Integer::sum)+
				groupNodeList.stream().map(groupNode -> groupNode.getAmountOfElemntsFromHolonObjects()).reduce(0, Integer::sum);
	}

	public int getAmountOfAktiveElemntsFromHolonObjects() {
		return passivList.stream().map(object -> object.getModel().getNumberOfActiveElements()).reduce(0, Integer::sum)+
				supplierList.stream().map(object -> object.getModel().getNumberOfActiveElements()).reduce(0, Integer::sum)+
				consumerList.stream().map(object -> object.getModel().getNumberOfActiveElements()).reduce(0, Integer::sum)+
				groupNodeList.stream().map(groupNode -> groupNode.getAmountOfAktiveElemntsFromHolonObjects()).reduce(0, Integer::sum);
	}
	public float getConsumptionFromConsumer() {		
		return consumerList.stream().map(con -> con.getEnergyNeededFromNetwork()).reduce(0.f, Float::sum)+
				groupNodeList.stream().map(groupNode -> groupNode.getConsumptionFromConsumer()).reduce(0.f, Float::sum);
	}
	public float getProductionFromSupplier() {		
		return supplierList.stream().map(sup -> sup.getEnergyToSupplyNetwork()).reduce(0.f, Float::sum)+
				groupNodeList.stream().map(groupNode -> groupNode.getProductionFromSupplier()).reduce(0.f, Float::sum);
	}
	
	public float getAverageConsumption() {
		return getConsumptionFromConsumer() / (float)getAmountOfGroupNodes();
	}
	public float getAverageProduction() {
		return getProductionFromSupplier() / (float)getAmountOfGroupNodes();
	}
	
	
	public String toString() {
		return 
				"GroupNode" + model.getId() + " with [Supplier:" + getAmountOfSupplier() 
				+ ", NotSupplied:" + getAmountOfConsumerWithState(HolonObjectState.NOT_SUPPLIED) 
				+ ", PartiallySupplied:" + getAmountOfConsumerWithState(HolonObjectState.PARTIALLY_SUPPLIED) 
				+ ", Supplied:" + getAmountOfConsumerWithState(HolonObjectState.SUPPLIED) 
				+ ", OverSupplied:" + getAmountOfConsumerWithState(HolonObjectState.OVER_SUPPLIED) 
				+ ", Passiv:"+ getAmountOfPassiv() + "]";
	}
}
