package ui.controller;

import java.util.HashMap;
import java.util.Map.Entry;

import classes.Category;
import classes.Edge;
import classes.GroupNode;
import classes.AbstractCanvasObject;
import classes.HolonElement;
import classes.HolonObject;
import ui.model.Model;

/**
 * Controller for Multiple Purposes.
 * 
 * @author Gruppe14
 */
public class MultiPurposeController {

	private Model model;

	/**
	 * Constructor.
	 * 
	 * @param model
	 *            Model
	 */
	public MultiPurposeController(Model model) {
		this.model = model;

	}

	/**
	 * search for category.
	 * 
	 * @param category
	 *            name of the Category
	 * @return the Category
	 */
	public Category searchCat(String category) {

		Integer idx;

		if ((idx = model.getCgIdx().get(category)) == null || model.getCgIdx().size() < 1)
			return null;
		else
			return model.getCategories().get(idx);
	}

	/**
	 * Search for Object in a Category.
	 * 
	 * @param category
	 *            name of the Category
	 * @param object
	 *            Name of the Object
	 * @return The Object
	 */
	public AbstractCanvasObject searchCatObj(Category category, String object) {

		Integer idx;

		if ((idx = category.getObjIdx().get(object)) == null || category.getObjIdx().size() < 1)
			return null;
		else
			return category.getObjects().get(idx);
	}

	/**
	 * Search for Object by ID.
	 * 
	 * @param id
	 *            the ID of the Object
	 * @return the CpsObject
	 */
	public AbstractCanvasObject searchByID(int id) {

		Integer idx;

		if ((idx = model.getCvsObjIdx().get(id)) == null || model.getCvsObjIdx().size() < 1)
			return null;
		else
			return model.getObjectsOnCanvas().get(idx);
	}

	/**
	 * 
	 * @param upperNode
	 * @param id
	 * @return
	 */
	public AbstractCanvasObject searchByIDUpperNode(int id, GroupNode upperNode) {
	
		Integer idx;
	
		if ((idx = upperNode.getNodesIdx().get(id)) == null || upperNode.getNodesIdx().size() < 1)
			return null;
		else
			return upperNode.getNodes().get(idx);
	}

	/**
	 * Search the Element by ID.
	 * 
	 * @param object
	 *            the Holon Object
	 * @param idEle
	 *            the Element ID
	 * @return The Holon Element
	 */
	public HolonElement searchEleById(HolonObject object, int idEle) {
		return object.searchElementById(idEle);
	}

	/**
	 * 
	 * @param id
	 * @return
	 */
	public AbstractCanvasObject searchTracked(int id) {

		for (AbstractCanvasObject cps : model.getTrackingObj()) {
			if (cps.getId() == id)
				return cps;
		}
		return null;
	}

	/**
	 * Search Edge between 2 Objects.
	 * 
	 * @param a
	 *            ID of Object a
	 * @param b
	 *            ID of Object b
	 * @return The Edge
	 */
	public Edge searchEdge(int a, int b) {

		AbstractCanvasObject objA = searchByID(a);
		AbstractCanvasObject objB = searchByID(b);

		for (Edge edge : model.getEdgesOnCanvas()) {
			// if (edge.getA().getObjName().equals(A.getObjName()) &&
			// (edge.getB().getObjName().equals(B.getObjName()))
			// || edge.getB().getObjName().equals(A.getObjName())
			// && (edge.getA().getObjName().equals(B.getObjName())))
			if ((edge.getA().equals(objA) && edge.getB().equals(objB))
					|| (edge.getB().equals(objA)) && edge.getA().equals(objB))
				return edge;
		}
		return null;
	}

	/**
	 * Decrement the Indices if a Key as been removed.
	 * 
	 * @param key
	 *            the Key
	 * @param <T>
	 *            key type
	 * @param map
	 *            the Map
	 */
	public <T> void decIdx(T key, HashMap<T, Integer> map) {
		if(!map.containsKey(key)) {
			return;
		}
		for (Entry<T, Integer> i : map.entrySet()) {
			if (i.getValue() > map.get(key))
				i.setValue(i.getValue() - 1);
		}
	}

	/**
	 * Adjust Indices before porting them from one map to another
	 * 
	 * @param key
	 *            the Key
	 * @param <T>
	 *            key type
	 * @param map
	 *            the Map
	 */
	public <T> void adjustIdx(int x, HashMap<T, Integer> map) {

		for (Entry<T, Integer> i : map.entrySet()) {
			i.setValue(i.getValue() + x + 1);
		}
	}

	/**
	 * Returns the highest Id
	 * 
	 * @param map
	 * @return
	 */
	public <T> int getHighestIdx(HashMap<T, Integer> map) {
		int max = 0;

		for (T i : map.keySet()) {
			if (map.get(i) > max)
				max = map.get(i);
		}

		return max;
	}

	/**
	 * Copies a HashMap into a new One.
	 * 
	 * @param map
	 *            the HashMap
	 * @param <T>
	 *            type
	 * @return Copy of the HashMap
	 */
	public static <T, Integer> HashMap<T, Integer> copyHashMap(HashMap<T, Integer> map) {

		HashMap<T, Integer> newMap = new HashMap<>();
		for (Entry<T, Integer> i : map.entrySet()) {
			newMap.put(i.getKey(), i.getValue());
		}
		return newMap;
	}

	/**
	 * Set the Algorithm.
	 * 
	 * @param obj
	 *            the Algorithm
	 */
	public void setAlgorithm(Object obj) {
		model.setAlgorithm(obj);
	}

}
