package br.uem.din.architectureEvolution.representation;

import static br.uem.din.architectureEvolution.helpers.ElementTypeNames.*;

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

import br.uem.din.architectureEvolution.helpers.ModelElementHelper;

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

public class Interface extends Element {
	
	private final HashMap<String, Operation> operations = new HashMap<String, Operation>();;
	
	public Interface(ModelElement element, Architecture architecture) throws Exception{
		this.setModelElement(element, architecture);		
	}

	@Override
	protected void loadFields() throws Exception {		
		loadOperations();
	}

	private void loadOperations() throws Exception {
		List<ModelElement> elements = ModelElementHelper.getOwnedElementsOfType(getModelElement(), "operation");
		for (ModelElement element : elements) {
			operations.put(element.getXMIID(), new Operation(element, getArchitecture()));
		}
	}

	public  Collection<Operation> getOperations() {
		return operations.values();
	}
	
	public void removeOperation(Operation operation) {
		operations.values().remove(operation);
		getModelElement().removeRelation(MetaModelElement.CONTEXT, operation.getModelElement());
	}
	
	public Operation createOperation(String operationName) throws Exception {
		ModelElement element = new ModelElement(getArchitecture().getMetaModel().getType(OPERATION));
		ModelElement parameterElement = new ModelElement(getArchitecture().getMetaModel().getType(PARAMETER));
		parameterElement.setRefAttribute("parametertype", null);
		element.addRelation(MetaModelElement.CONTEXT, parameterElement);
		String xmiID = getNextOperationXMIID();
		element.setXMIID(xmiID);
		element.setName(operationName);
		Operation operation = new Operation(element, getArchitecture());
		operations.put(xmiID, operation);
		getModelElement().addRelation(MetaModelElement.CONTEXT, element);
		return operation;
	}

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

	public void moveOperationToInterface(Operation operation, Interface interfaceToMove) {
		if (!getOperations().contains(operation)) return;
		
		removeOperation(operation);
		interfaceToMove.addExternalOperation(operation);
	}

	private void addExternalOperation(Operation operation) {
		operations.put(operation.getModelElement().getXMIID(), operation);
		getModelElement().addRelation(MetaModelElement.CONTEXT, operation.getModelElement());
	}

	public Collection<Component> getImplementors() {
		Collection<Component> implementors = new ArrayList<Component>();
		for (AbstractionInterElementRelationship abstraction : getArchitecture().getAbstractionInterElementRelationships()) {
			if (abstraction.getParent().equals(this))
				implementors.add(abstraction.getChild());
		}
		return implementors;
	}

	public Collection<Component> getDependents() {
		Collection<Component> dependents = new ArrayList<Component>();
		for (DependencyComponentInterfaceRelationship dependency : getArchitecture().getDependencyComponentInterfaceRelationships()) {
			if (dependency.getInterface().equals(this))
				dependents.add(dependency.getComponent());
		}
		return dependents;
	}
}