package br.uem.din.architectureEvolution.representation;

import static br.uem.din.architectureEvolution.helpers.ElementTypeNames.CLASS;
import static br.uem.din.architectureEvolution.helpers.ElementTypeNames.COMPONENT;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.sdmetrics.model.MetaModelElement;
import com.sdmetrics.model.ModelElement;

public class Component extends Element {

	private final HashMap<String, Class> classes = new HashMap<String, Class>();
	private final Collection<Interface> implementedInterfaces = new ArrayList<Interface>();
	private final Collection<Interface> requiredInterfaces = new ArrayList<Interface>();
	
	public Component(String name, Architecture architecture) throws Exception {
		ModelElement element = new ModelElement(architecture.getMetaModel().getType(COMPONENT));
		element.setName(name);
		this.setModelElement(element, architecture);
	}
	
	public Component(ModelElement element, Architecture architecture) throws Exception {
		this.setModelElement(element, architecture);					
	}

	public Class getClassByXMIID(String xMIID){
		return classes.get(xMIID);
	}

	public Map<? extends String, ? extends Class> getClasses() {
		return classes;
	}

	@Override
	protected void loadFields() throws Exception {
		Collection<ModelElement> ownedElements = getModelElement().getOwnedElements();
		if (ownedElements == null) return;
		for (ModelElement ownedElement : getModelElement().getOwnedElements()) {
			if (ownedElement.getType().getName().equals("class"))
				classes.put(ownedElement.getXMIID(), new Class(ownedElement, getArchitecture()));
		}
	}

	public Class findClassByName(String name) {
		for (Class c : classes.values()) {
			if (c.getName().equals(name))
				return c;
		}
		return null;
	}

	public Collection<Interface> getImplementedInterfaces() {
		return implementedInterfaces;
	}
	
	public Collection<Interface> getRequiredInterfaces() {
		return requiredInterfaces;
	}

	protected void addImplementedInterface(Interface interface_) {
		implementedInterfaces.add(interface_);
	}
	
	protected void addRequiredInterface(Interface interface_) {
		requiredInterfaces.add(interface_);
	}
	
	public Class createClass(String className) throws Exception {
		ModelElement element = new ModelElement(getArchitecture().getMetaModel().getType(CLASS));
		String xmiID = getNextOwnedClassXMIID();
		element.setXMIID(xmiID);
		element.setName(className);
		Class c = new Class(element, getArchitecture());
		classes.put(xmiID, c);
		getModelElement().addRelation(MetaModelElement.CONTEXT, element);
		return c;
	}
	
	public void removeClass(Class class_) {
		classes.values().remove(class_);
		getModelElement().removeRelation(MetaModelElement.CONTEXT, class_.getModelElement());
	}

	private String getNextOwnedClassXMIID() {
		String xmiID = getModelElement().getXMIID();
		int number = 0;
		String nextXmiID = "";
		do {
			number++;
			nextXmiID = xmiID + number;
		} while(classes.containsKey(nextXmiID));
		return nextXmiID;
	}

	public void moveClassToComponent(Class class_, Component componentToMove) {
		if (!classes.values().contains(class_)) return;
		
		removeClass(class_);
		componentToMove.addExternalClass(class_);
	}

	private void addExternalClass(Class class_) {
		classes.put(class_.getModelElement().getXMIID(), class_);
		getModelElement().addRelation(MetaModelElement.CONTEXT, class_.getModelElement());
	}
	
	public boolean removeImplementedInterface(Interface interface_) {
		if (!implementedInterfaces.contains(interface_)) return false;
		
		implementedInterfaces.remove(interface_);
		return true;
	}

	public boolean removeRequiredInterface(Interface interface_) {
		if (!requiredInterfaces.contains(interface_)) return false;
		
		requiredInterfaces.remove(interface_);
		return true;
	}
}
