package br.uem.din.architectureEvolution.representation;

import static br.uem.din.architectureEvolution.helpers.ModelElementHelper.isClass;
import static br.uem.din.architectureEvolution.helpers.ModelElementHelper.isComponent;
import static br.uem.din.architectureEvolution.helpers.ModelElementHelper.isInterface;

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

import com.sdmetrics.model.ModelElement;

public class Variability {

	private static final String VARIANTS = "variants";
	private static final String MINSELECTION = "minSelection";
	private static final String MAXSELECTION = "maxSelection";
	private static final String ALLOWSADDINGVAR = "allowsAddingVar";
	
	private ModelElement modelElement;
	private Architecture architecture;
	private String name;
	private String minSelection;
	private String maxSelection;
	private String allowsAddingVar;
	
	private final Collection<Element> variationPoints = new ArrayList<Element>();
	private final Collection<Element> variants = new ArrayList<Element>();
	private final HashMap<String, String> attributes = new HashMap<String, String>();
	
	public Variability(ModelElement modelElement, Architecture architecture){
		setArchitecture(architecture);
		setModelElement(modelElement);
		setName(modelElement.getName());				
		loadVariationPoint();
		inspectTaggedValues();
	}

	@SuppressWarnings("unchecked")
	private void inspectTaggedValues() {
		Collection<ModelElement> taggedValues = (Collection<ModelElement>)getModelElement().getSetAttribute("taggedValue");
		
		for (ModelElement taggedValue : taggedValues) {
			String typeName = taggedValue.getRefAttribute("definition").getName();
			String value = taggedValue.getPlainAttribute("value");
			if (typeName.equals(VARIANTS))
				loadVariants(value);
			else if (typeName.equals(MINSELECTION))
				setMinSelection(value);
			else if (typeName.equals(MAXSELECTION))
				setMaxSelection(value);
			else if (typeName.equals(ALLOWSADDINGVAR))
				setAllowsAddingVar(value);
			else
				attributes.put(typeName, value);
		}
	}

	private void loadVariants(String variantsString) {
		variantsString = variantsString.replace("{", "").replace("}", "");
		String[] variantsNames = variantsString.split(",");
		for (String variant : variantsNames) {
			Element element = getArchitecture().findElementByName(variant.trim());
			if (element != null)
				variants.add(element);
		}
	}

	public void loadVariationPoint() {
		ModelElement annotedElement = getModelElement().getRefAttribute("annotatedElement");
		Element variationPoint = null;
		if (isComponent(annotedElement))
			variationPoint = getArchitecture().findComponentByXMIID(annotedElement.getXMIID());
		else if (isClass(annotedElement))
			variationPoint = getArchitecture().findClassByXMIID(annotedElement.getXMIID());
		else if (isInterface(annotedElement))
			variationPoint = getArchitecture().findInterfaceByXMIID(annotedElement.getXMIID());
		getVariationPoints().add(variationPoint);
	}
	
	public String getName() {
		return name;
	}
	
	private void setName(String name) {
		this.name = name;
	}

	public ModelElement getModelElement() {
		return modelElement;
	}
	
	private void setModelElement(ModelElement modelElement) {
		this.modelElement = modelElement;
	}

	public Architecture getArchitecture() {
		return architecture;
	}

	private void setArchitecture(Architecture architecture) {
		this.architecture = architecture;
	}

	public String getMinSelection() {
		return minSelection;
	}

	private void setMinSelection(String minSelection) {
		this.minSelection = minSelection;
	}

	public String getMaxSelection() {
		return maxSelection;
	}

	private void setMaxSelection(String maxSelection) {
		this.maxSelection = maxSelection;
	}

	public String getAllowsAddingVar() {
		return allowsAddingVar;
	}

	private void setAllowsAddingVar(String allowsAddingVar) {
		this.allowsAddingVar = allowsAddingVar;
	}

	public Collection<Element> getVariationPoints() {
		return variationPoints;
	}	
	
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		
		for (Entry<String, String> attribute : attributes.entrySet()) {
			builder.append(attribute.getKey() + ": " + attribute.getValue() + "\n");
		}

		builder.append("MaxSelection: " + getMaxSelection() + "\n");
		builder.append("MinSelection: " + getMinSelection() + "\n");
		builder.append("AllowsAddingVar: " + getAllowsAddingVar() + "\n");
		
		if (!variants.isEmpty()) {
			builder.append("Variants: ");
			Element[] variantsArray = variants.toArray(new Element[0]);
			for (int i = 0; i < variantsArray.length; i++) {
				if (i > 0)
					builder.append(", ");
				builder.append(variantsArray[i].getName());
			}
		}
		return builder.toString();
	}
}
