package classes;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;

import ui.controller.MultiPurposeController;

/**
 * The class HolonObject represents any Object on the system which capability of
 * injecting or consuming energy on the network, for instance a house or a power
 * plant.
 * 
 * @author Gruppe14
 *
 */
public class HolonObject extends AbstractCpsObject {
	/*
	 * Color of the actual state (red = no supplied, yellow = partially supplied
	 * and green = supplied)
	 */
	private Color stateColor;
	/* Array of all consumers */
	private ArrayList<HolonElement> elements;
	/* Array of all Indices of Elements */
	private HashMap<String, Integer> eleIdx;
	/* Total of consumption */
	private float currentEnergy;

	/*
	 * 0 = no energy, 1 = not supplied, 2 = supplied, 3 producer
	 */
	private int state = 0;

	/**
	 * Constructor Set by default the name of the object equals to the category
	 * name, until the user changes it.
	 * 
	 * @param objName
	 *            name of the Object
	 */
	public HolonObject(String objName) {
		super(objName);
		setElements(new ArrayList<HolonElement>());
		setEleIdx(new HashMap<String, Integer>());
		setState();
	}

	/**
	 * Contructor of a copy of an Object.
	 * 
	 * @param obj
	 *            object to be copied
	 */
	public HolonObject(AbstractCpsObject obj) {
		super(obj);
		setEleIdx(MultiPurposeController.copyHashMap(((HolonObject) obj).getEleIdx()));
		setElements(copyElements(((HolonObject) obj).getElements()));
		setState();
	}

	/**
	 * sets the State, wether object is a producer, zero Energy, supplied or
	 * not.
	 */
	public void setState() {
		if (getCurrentEnergy() > 0) {
			setState(3);
			stateColor = Color.lightGray;
		} else {
			if (getCurrentEnergy() == 0) {
				setState(0);
				stateColor = Color.WHITE;
			} else {
				if (checkIfPartiallySupplied(0)) {
					stateColor = Color.yellow;
				} else {
					stateColor = new Color(230, 120, 100);
				}

			}
		}
	}

	/**
	 * Getter for all Elements in the HolonObject.
	 * 
	 * @return the elements ArrayList
	 */
	public ArrayList<HolonElement> getElements() {
		return elements;
	}

	/**
	 * Set a new ArrayList with HolonElements into the HolonObject.
	 * 
	 * @param elements
	 *            the elements to set
	 */
	public void setElements(ArrayList<HolonElement> elements) {
		this.elements = elements;
	}

	/**
	 * adds an Element to the Object.
	 * 
	 * @param element
	 *            the Element to add
	 */
	public void addElements(HolonElement element) {
		elements.add(element);
	}

	/**
	 * Doesn't take into account which timestep is watched, calculates the max
	 * values.
	 * 
	 * @return the currentEnergy
	 */
	public float getCurrentEnergy() {
		float temp = 0;
		for (HolonElement e : getElements()) {
			if (e.getActive()) {
				temp = temp + e.getTotalEnergy();
			}
		}
		currentEnergy = temp;
		return currentEnergy;
	}

	/**
	 * Getter for the current energy at a given timestep.
	 * 
	 * @param x
	 *            timestep
	 * @return corresponding energy
	 */
	public float getCurrentEnergyAtTimeStep(int x) {
		float temp = 0;
		for (HolonElement e : getElements()) {
			if (e.getActive()) {
				temp = temp + e.getTotalEnergyAtTimeStep(x);
			}
		}
		currentEnergy = temp;
		return currentEnergy;
	}

	/**
	 * deletes Element at a given index.
	 * 
	 * @param idx
	 *            index
	 */
	public void deleteElement(int idx) {
		elements.remove(idx);
	}

	/**
	 * String of all consumers in this HolonObject.
	 * 
	 * @return all the names of this HolonObject separated by "," each object
	 */
	public String toStringElements() {
		String objString = "Empty";
		for (HolonElement e : elements) {
			if (objString == "Empty") {
				objString = e.getEleName();
			} else {
				objString = objString + ", " + e.getEleName();
			}
		}
		return objString;
	}

	/**
	 * Getter index of all elements in the HolonObject.
	 * 
	 * @return the eleIdx
	 */
	public HashMap<String, Integer> getEleIdx() {
		return eleIdx;
	}

	/**
	 * Set the indexes of all elements.
	 * 
	 * @param eleIdx
	 *            the eleIdx to set
	 */
	public void setEleIdx(HashMap<String, Integer> eleIdx) {
		this.eleIdx = eleIdx;
	}

	/**
	 * Copy all Elements into a New Array.
	 * 
	 * @param arr
	 *            to copy
	 * @return the copy of arr
	 */
	public ArrayList<HolonElement> copyElements(ArrayList<HolonElement> arr) {
		ArrayList<HolonElement> newArr = new ArrayList<>();
		for (HolonElement t : arr) {
			newArr.add(new HolonElement(t));
		}
		return newArr;
	}

	/**
	 * Get the state of the Object.
	 * 
	 * @return state the State of the Element
	 */
	public int getState() {
		return this.state;
	}

	/**
	 * Set the state of the Object.
	 * 
	 * @param state
	 *            boolean if the Object is fully supplied
	 */
	public void setState(int state) {
		this.state = state;
		switch (state) {
		case 0:
			stateColor = Color.WHITE;
			break;

		case 1:
			stateColor = new Color(230, 120, 100);
			break;

		case 2:
			stateColor = Color.GREEN;
			break;

		case 3:
			stateColor = Color.lightGray;
			break;

		case 4:
			stateColor = Color.YELLOW;
		}
	}

	/**
	 * Search for the element with the name.
	 * 
	 * @param name
	 *            name of the object to be searched
	 * @return the searched HolonElement
	 */
	public HolonElement searchElement(String name) {
		HolonElement ele = null;
		for (HolonElement e : getElements()) {
			if (e.getEleName().equals(name)) {
				ele = e;
			}
		}
		return ele;
	}

	/**
	 * Search for the element with the id.
	 * 
	 * @param id
	 *            id of the element to be founded
	 * @return the element
	 */
	public HolonElement searchElementById(int id) {
		HolonElement ele = null;
		for (HolonElement e : getElements()) {
			if (e.getId() == id) {
				ele = e;
			}
		}
		return ele;
	}

	/**
	 * Check if Partially Supplied.
	 * 
	 * @param x
	 *            current Iteration
	 * @return boolean is partially supplied
	 */
	public boolean checkIfPartiallySupplied(int x) {
		if (getElements().size() == 0) {
			return false;
		}
		float minConsum = getElements().get(0).getTotalEnergyAtTimeStep(x);
		float prod = 0;
		for (HolonElement e : getElements()) {
			if (e.getActive()) {
				if (e.getTotalEnergyAtTimeStep(x) > 0) {
					prod = prod + e.getTotalEnergyAtTimeStep(x);
				}
				if (minConsum < 0 && (e.getTotalEnergyAtTimeStep(x) > minConsum && e.getTotalEnergyAtTimeStep(x) < 0)) {
					minConsum = e.getTotalEnergyAtTimeStep(x);
				} else if (minConsum >= 0 && e.getTotalEnergyAtTimeStep(x) < minConsum) {
					minConsum = e.getTotalEnergyAtTimeStep(x);
				}
			}
		}
		// System.out.println("minCons: " + minConsum + " prod: " + prod);
		if (minConsum < 0 && prod >= -minConsum) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Set the State Color.
	 * 
	 * @param color
	 *            the Color
	 */
	public void setColor(Color color) {
		stateColor = color;
	}

	/**
	 * Get the Color.
	 * 
	 * @return stateColor the Color
	 */
	public Color getColor() {
		return stateColor;
	}
}