package org.js.model.feature.edit;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.js.model.feature.Attribute;
import org.js.model.feature.AttributeConstraint;
import org.js.model.feature.AttributeOperand;
import org.js.model.feature.AttributeReference;
import org.js.model.feature.Constraint;
import org.js.model.feature.DiscreteDomain;
import org.js.model.feature.Domain;
import org.js.model.feature.DomainValue;
import org.js.model.feature.Feature;
import org.js.model.feature.FeatureConstraint;
import org.js.model.feature.FeatureModel;
import org.js.model.feature.FeatureState;
import org.js.model.feature.Group;
import org.js.model.feature.Interval;
import org.js.model.feature.NumericalDomain;
/**
*
*/
/**
* @author <a href="mailto:julia.schroeter@tu-dresden.de">Julia Schroeter</a>
*
*/
public class FeatureModelHelper {
// Set<Feature> allFeatures;
Set<Feature> selectedFeatures;
Set<Feature> unboundFeatures;
Set<Feature> deselectedFeatures;
private Set<Group> allGroups;
private Set<Attribute> allAttributes;
private Set<FeatureConstraint> allFeatureConstraints;
private Set<AttributeConstraint> allAttributeConstraints;
private FeatureModel model;
private static Logger log = Logger.getLogger(FeatureModelHelper.class);
public FeatureModelHelper(FeatureModel model) {
this.model = model;
initLists();
initModel(model);
}
public void refresh(){
initLists();
initModel(model);
}
private void initLists() {
selectedFeatures = new HashSet<Feature>();
deselectedFeatures = new HashSet<Feature>();
unboundFeatures = new HashSet<Feature>();
allGroups = new HashSet<Group>();
setAllAttributes(new HashSet<Attribute>());
setAllFeatureConstraints(new HashSet<FeatureConstraint>());
setAllAttributeConstraints(new HashSet<AttributeConstraint>());
}
private void initModel(FeatureModel model) {
TreeIterator<Object> allContents = EcoreUtil.getAllContents(model, true);
while (allContents.hasNext()) {
Object object = (Object) allContents.next();
if (object instanceof Feature) {
Feature feature = (Feature) object;
sortFeature(feature);
} else if (object instanceof Attribute) {
Attribute attribute = (Attribute) object;
getAllAttributes().add(attribute);
} else if (object instanceof FeatureConstraint) {
FeatureConstraint featureConstraint = (FeatureConstraint) object;
getAllFeatureConstraints().add(featureConstraint);
} else if (object instanceof AttributeConstraint) {
AttributeConstraint attributeConstraint = (AttributeConstraint) object;
getAllAttributeConstraints().add(attributeConstraint);
} else if (object instanceof Group) {
Group group = (Group) object;
getAllGroups().add(group);
}
}
}
/**
* getFeature from Attribute Operand if the Operand is an AttributeReference, returns null otherwise.
*
* @param operand
* @return
*/
public static Feature getAttributeOperandFeature(AttributeOperand operand) {
Feature result = null;
if (operand instanceof AttributeReference) {
AttributeReference reference = (AttributeReference) operand;
result = reference.getFeature();
}
return result;
}
private void sortFeature(Feature feature) {
FeatureState configurationState = feature.getConfigurationState();
if (FeatureState.SELECTED.equals(configurationState)) {
selectedFeatures.add(feature);
} else if (FeatureState.DESELECTED.equals(configurationState)) {
deselectedFeatures.add(feature);
} else if (FeatureState.UNBOUND.equals(configurationState)) {
unboundFeatures.add(feature);
}
}
public int getValue(String attributeId) {
String[] split = attributeId.split("~");
// fourth is value, if available
String value = split[3];
return Integer.parseInt(value);
}
/**
* get the currently set attribute value as integer representation. beware: if the attribute does not have a value
* assigned, this methods returns -1. Use the method isAttributeValueSet(Attribute attribute) before to ensure a
* correct result.
*
* @param attribute
* @return
*/
public static int getAttributeValue(Attribute attribute) {
String value = attribute.getValue();
return getAttributeValueForString(value, attribute);
}
/**
* returns the attribute integer representation that belongs to the given String representation.
*
* @param valueString
* @param attribute
* @return
*/
public static int getAttributeValueForString(String valueString, Attribute attribute) {
// if value is -1, it is not found in domain value list
int value = -1;
Domain domain = attribute.getDomain();
value = getDomainValueForString(valueString, domain);
return value;
}
public static int getDomainValueForString(String valueString, Domain domain) {
int value = -1;
if (domain instanceof DiscreteDomain) {
DiscreteDomain discreteDomain = (DiscreteDomain) domain;
EList<DomainValue> values = discreteDomain.getValues();
for (DomainValue domainValue : values) {
String domainValueString = domainValue.getName();
if (valueString.equals(domainValueString)) {
value = domainValue.getInt();
break;
}
}
} else {
value = Integer.parseInt(valueString);
}
return value;
}
/**
* check if the given attribute value is contained in the given domain
*
* @param domain
* @param attributeValue
* @return
*/
public static boolean containsValue(Domain domain, String attributeValue) {
return (domain instanceof DiscreteDomain) ? containsValue((DiscreteDomain) domain, attributeValue)
: containsValue((NumericalDomain) domain, attributeValue);
}
private static boolean containsValue(DiscreteDomain domain, String attributeValue) {
boolean isContained = false;
if (attributeValue != null) {
DiscreteDomain discreteDomain = (DiscreteDomain) domain;
EList<DomainValue> values = discreteDomain.getValues();
for (DomainValue domainValue : values) {
String domainValueString = domainValue.getName();
if (attributeValue.equals(domainValueString)) {
isContained = true;
break;
}
}
}
return isContained;
}
/**
* check if the attribute's value is already set.
*
* @param attribute
* @return
*/
public static boolean isAttributeValueSet(Attribute attribute) {
boolean isSet = false;
String value = attribute.getValue();
boolean existValue = (value != null && !value.isEmpty());
if (existValue) {
Domain domain = attribute.getDomain();
if (domain instanceof DiscreteDomain) {
DiscreteDomain discreteDomain = (DiscreteDomain) domain;
isSet = containsValue(discreteDomain, value);
} else if (domain instanceof NumericalDomain) {
NumericalDomain numDomain = (NumericalDomain) domain;
isSet = containsValue(numDomain, value);
}
}
return isSet;
}
/**
* checks whether the given domain contains the attribute value.
*
* @param numDomain
* @param value
* @return
*/
private static boolean containsValue(NumericalDomain numDomain, String value) {
boolean isContained = false;
if (value != null) {
try {
int number = Integer.parseInt(value);
for (Interval interval : numDomain.getIntervals()) {
isContained = isInInterval(number, interval);
if (isContained) {
break;
}
}
} catch (NumberFormatException e) {
// if the String value cannot be parsed to a numerical representation, the value is not contained in the
// domain.
}
}
return isContained;
}
private static boolean isInInterval(int number, Interval interval) {
boolean isinbounds = false;
int lowerBound = interval.getLowerBound();
int upperBound = interval.getUpperBound();
isinbounds = lowerBound <= number && upperBound >= number;
return isinbounds;
}
/**
* get the String representation of the given attribute and integer value
*
* @param value
* @param attribute
* @return
*/
public static String getAttributeValue(int value, Attribute attribute) {
String valueName = null;
Domain domain = attribute.getDomain();
if (domain instanceof DiscreteDomain) {
DiscreteDomain discreteDomain = (DiscreteDomain) domain;
EList<DomainValue> values = discreteDomain.getValues();
for (DomainValue domainValue : values) {
int domainValueInt = domainValue.getInt();
if (value == domainValueInt) {
valueName = domainValue.getName();
break;
}
}
} else {
valueName = Integer.toString(value);
}
return valueName;
}
/**
* resolve the attribute identified by the given attributeId. the attribute id is used in the cpmodel utilized in the
* csp solver.
*
* @param attributeId
* @return
*/
public Attribute getAttribute(String attributeId) {
Attribute attribute = null;
String[] split = attributeId.split("~");
// first is identifier value or enablement
// String identifier = split[0];
// second is feature id
String featureId = split[1];
// third is attribute id
String attributeName = split[2];
// fourth is value
// String value = split[3];
attribute = getAttribute(featureId, attributeName);
return attribute;
}
/**
* resolve the attribute by its name and feature.
*
* @param featureId
* @param attributeName
* @return
*/
public Attribute getAttribute(String featureId, String attributeName) {
Attribute rattribute = null;
Feature feature = getFeature(featureId);
EList<Attribute> attributes = feature.getAttributes();
for (Attribute attribute : attributes) {
if (attribute.getName().equals(attributeName)) {
rattribute = attribute;
break;
}
}
return rattribute;
}
public Feature getFeature(String featureId) {
Feature result = getUnboundFeature(featureId);
if (result == null) {
result = getSelectedFeature(featureId);
if (result == null) {
result = getDeselectedFeature(featureId);
}
}
return result;
}
private Feature getFeatureFromSet(Set<Feature> featureSet, String featureId) {
Feature result = null;
for (Feature feature : featureSet) {
String id = feature.getId();
if (id.equals(featureId)) {
result = feature;
break;
}
}
return result;
}
private Feature getUnboundFeature(String featureId) {
return getFeatureFromSet(unboundFeatures, featureId);
}
private Feature getSelectedFeature(String featureId) {
return getFeatureFromSet(selectedFeatures, featureId);
}
private Feature getDeselectedFeature(String featureId) {
return getFeatureFromSet(deselectedFeatures, featureId);
}
public Set<Feature> getAllFeatures() {
Set<Feature> allFeatures = new HashSet<Feature>();
allFeatures.addAll(deselectedFeatures);
allFeatures.addAll(selectedFeatures);
allFeatures.addAll(unboundFeatures);
return allFeatures;
}
public Set<Feature> getSelectedFeatures() {
return selectedFeatures;
}
public boolean isFeatureSelected(String featureId) {
Feature feature = getSelectedFeature(featureId);
return feature != null;
}
public boolean isFeatureSelected(Feature feature) {
boolean result = false;
if (feature != null) {
result = FeatureState.SELECTED.equals(feature.getConfigurationState());
}
return result;
}
public Set<FeatureConstraint> getAllFeatureConstraints() {
return allFeatureConstraints;
}
public void setAllFeatureConstraints(Set<FeatureConstraint> allFeatureConstraints) {
this.allFeatureConstraints = allFeatureConstraints;
}
public Set<AttributeConstraint> getAllAttributeConstraints() {
return allAttributeConstraints;
}
public void setAllAttributeConstraints(Set<AttributeConstraint> allAttributeConstraints) {
this.allAttributeConstraints = allAttributeConstraints;
}
public Set<Attribute> getAllAttributes() {
return allAttributes;
}
public void setAllAttributes(Set<Attribute> allAttributes) {
this.allAttributes = allAttributes;
}
public FeatureModel getModel() {
return model;
}
/**
* initialize a featuremodel from an Ifile.
*
* @param file
* @return
*/
public static FeatureModel getFeatureModel(IFile file, ResourceSet resourceSet) {
FeatureModel featuremodel = null;
EObject object = getModel(file, resourceSet);
if (object instanceof FeatureModel) {
featuremodel = (FeatureModel) object;
}
return featuremodel;
}
public static FeatureModel getFeatureModel(IFile file) {
return getFeatureModel(file, new ResourceSetImpl());
}
/**
* Generic method to load a model from a file.
*
* @param file
* @return
*/
public static EObject getModel(IFile file, ResourceSet resourceSet) {
EObject result = null;
Resource modelResource = getModelResource(file, resourceSet);
if (modelResource == null) {
log.warn("The selected resource is not an EMF model,");
} else {
try {
modelResource.load(Collections.EMPTY_MAP);
} catch (IOException e) {
log.debug(e.getMessage());
}
if (modelResource.isLoaded()) {
EList<EObject> contents = modelResource.getContents();
if (contents != null && !contents.isEmpty()) {
result = contents.get(0);
}
}
}
return result;
}
/**
* get the according resource for a file.
*
* @param file
* @return
*/
public static Resource getModelResource(IFile file, ResourceSet resourceSet) {
Resource resource = null;
if (file != null && file.exists()) {
String locationUri = file.getLocationURI().normalize().getPath();
URI uri = URI.createFileURI(locationUri);
resource = resourceSet.createResource(uri);
}
return resource;
}
public Set<Feature> getUnboundFeatures() {
return unboundFeatures;
}
public Set<Feature> getDeselectedFeatures() {
return deselectedFeatures;
}
public Set<Attribute> getAssignedAttributes() {
Set<Attribute> assignedAttributes = new HashSet<Attribute>();
Set<Attribute> attributes = getAllAttributes();
for (Attribute attribute : attributes) {
String value = attribute.getValue();
if (value != null && !value.isEmpty()) {
assignedAttributes.add(attribute);
}
}
return assignedAttributes;
}
public Set<Group> getAllGroups() {
return allGroups;
}
public static Set<Feature> getConstrainedFeatures(Constraint constraint) {
Set<Feature> features = new HashSet<Feature>();
if (constraint instanceof FeatureConstraint) {
FeatureConstraint featureConstraint = (FeatureConstraint) constraint;
features.add(featureConstraint.getLeftOperand());
features.add(featureConstraint.getRightOperand());
} else {
Set<Attribute> constrainedAttributes = getConstrainedAttributes(constraint);
for (Attribute attribute : constrainedAttributes) {
Feature feature = attribute.getFeature();
features.add(feature);
}
}
return features;
}
private static Set<Attribute> getConstrainedAttributes(Constraint constraint) {
Set<Attribute> attributes = new HashSet<Attribute>();
if (constraint instanceof AttributeConstraint) {
AttributeConstraint attributeConstraint = (AttributeConstraint) constraint;
AttributeOperand leftOperand = attributeConstraint.getLeftOperand();
Attribute attribute = getAttribute(leftOperand);
if (attribute != null) {
attributes.add(attribute);
}
AttributeOperand rightOperand = attributeConstraint.getRightOperand();
Attribute secondattribute = getAttribute(rightOperand);
if (secondattribute != null) {
attributes.add(secondattribute);
}
}
return attributes;
}
private static Attribute getAttribute(AttributeOperand operand) {
Attribute attribute = null;
if (operand instanceof AttributeReference) {
AttributeReference attReference = (AttributeReference) operand;
attribute = attReference.getAttribute();
}
return attribute;
}
public Set<Constraint> getConstraintsRelatedToFeature(Feature feature) {
Set<Constraint> related = new HashSet<Constraint>();
Set<Constraint> allConstraints = new HashSet<Constraint>();
allConstraints.addAll(allFeatureConstraints);
allConstraints.addAll(allAttributeConstraints);
for (Constraint featureConstraint : allConstraints) {
Set<Feature> constrainedFeatures = getConstrainedFeatures(featureConstraint);
for (Feature constrainedFeature : constrainedFeatures) {
if (EcoreUtil.equals(feature, constrainedFeature)) {
related.add(featureConstraint);
break;
}
}
}
return related;
}
public static Feature getParentFeature(Feature feature){
Feature parent = null;
EObject eContainer = feature.eContainer();
if (eContainer != null && eContainer instanceof Group){
Group parentGroup = (Group)eContainer;
parent = (Feature) parentGroup.eContainer();
}
return parent;
}
}