/*
* License (BSD Style License):
* Copyright (c) 2011
* Software Engineering
* Department of Computer Science
* Technische Universitiät Darmstadt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Software Engineering Group or Technische
* Universität Darmstadt nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package de.tud.cs.st.vespucci.diagram.creator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.emf.common.util.EList;
import de.tud.cs.st.vespucci.vespucci_model.Dummy;
import de.tud.cs.st.vespucci.vespucci_model.Ensemble;
import de.tud.cs.st.vespucci.vespucci_model.Shape;
/**
* This class encapsulates the ensemble prolog facts.
*
* @author Patrick Jahnke
* @author Thomas Schulz
* @author Alexander Weitzmann
* @author Theo Kischka
*
*/
public class EnsemblePrologFacts {
/**
* Regular expression to check if argument starts with an upper case letter. E.g. a parameter
* variable.
*/
private static final Pattern FIRST_LETTER_IS_UPPER_CASE = Pattern.compile("\\p{Upper}.*");
/**
* Regular expression to match a name of an ensemble that contains parameter.
*/
private static final Pattern PARAMETER_LIST = Pattern.compile("^.+?" + // match the descriptor
"\\(" + // match the first bracket
"(.*)" + // match anything in between as group
"\\)$"); // match the last parenthesis by asserting the string ends here
/**
* Regular expression to split parameter names of ensembles.
*/
private static final Pattern PARAMETER_NAMES = Pattern.compile("(.*?)=(.*)");
/**
* Name of the current diagram file.
*/
private static String diagramFileName;
/**
* A convenience method to retrieve the ensemble prolog facts.
*
* @param shapeList
* @param diagramFileName
* @return Returns the formatted ensemble facts.
*/
static StringBuilder getFacts(final List<Shape> shapeList, final String diagramFileName) throws Exception {
EnsemblePrologFacts.diagramFileName = diagramFileName;
return createEnsembleFacts(shapeList);
}
/**
* Search the diagram recursively and create all ensemble facts, except Dummy.
*
* @param shapeList
* The list of shapes in the diagram.
* @throws Exception
* @return Returns the formatted ensemble facts.
*/
static StringBuilder createEnsembleFacts(final List<Shape> shapeList) throws Exception {
final StringBuilder ensembleFacts = new StringBuilder();
for (final Shape shape : shapeList) {
// create Ensemble facts:
if (shape instanceof Ensemble && shape != null) {
final Ensemble ensemble = (Ensemble) shape;
if (isAbstractEnsemble(ensemble)) {
ensembleFacts.append("abstract_ensemble");
} else {
ensembleFacts.append("ensemble");
}
// TODO: This is a workaround - invent a platform independent solution
final String query = ensemble.getQuery().replaceAll("\\p{Space}", " ");
ensembleFacts.append(String.format("('%s', %s, %s, (%s), [%s]).\n", diagramFileName,
createEnsembleDescriptor(ensemble), createEnsembleParameters(ensemble), query,
listSubEnsembles(ensemble.getShapes())));
// do children exist
if ((ensemble.getShapes() != null) && (ensemble.getShapes().size() > 0)) {
ensembleFacts.append(createEnsembleFacts(ensemble.getShapes()));
}
}
}
return ensembleFacts;
}
/**
* @param ensemble
* @return Return true, only if the ensemble is abstract, i.e. the ensemble contains at least
* one parameter variable.
*/
private static boolean isAbstractEnsemble(final Ensemble ensemble) {
final String[] parameters = splitEnsembleParameterList(ensemble);
for (final String parameter : parameters) {
if (FIRST_LETTER_IS_UPPER_CASE.matcher(parameter).matches()) {
return true;
}
}
return false;
}
/**
*
* @param shape
* @return The name of the ensemble in apostrophes. (Without parameters)
*/
static String createEnsembleDescriptor(final Shape shape) {
String name = "";
if (shape.getName() != null) {
name = shape.getName().length() == 0 ? "non-editpart" : shape.getName();
}
final StringBuilder s = new StringBuilder("'");
if (name.indexOf('(') > 0) {
s.append(name.subSequence(0, name.indexOf('(')));
} else {
s.append(name);
}
s.append("'");
return s.toString();
}
/**
* @param ensemble
* The ensemble whose parameters shall be extracted.
* @return A prolog list of the form ['ParamName'=ParamName, ...]
*/
private static String createEnsembleParameters(final Ensemble ensemble) {
final String[] parameters = splitEnsembleParameterList(ensemble);
if (parameters.length == 0) {
return "[]";
}
final StringBuilder s = new StringBuilder("[");
s.append(createEncodedParameter(parameters[0]));
for (int i = 1; i < parameters.length; i++) {
s.append(", ");
s.append(createEncodedParameter(parameters[i]));
}
s.append("]");
return s.toString();
}
/**
* Create a formatted string with all given ensembles.
*
* @param ensembles
* @return Return formatted string listing the given ensembles.
*/
private static String listSubEnsembles(final EList<Shape> ensembles) {
final StringBuilder strBuilder = new StringBuilder();
if (ensembles == null) {
return strBuilder.toString();
}
String komma = "";
for (final Shape shape : ensembles) {
if (shape instanceof Dummy) {
strBuilder.append(komma + "'empty'");
} else if (shape instanceof Ensemble) {
strBuilder.append(komma + "'" + shape.getName() + "'");
}
komma = ", ";
}
return strBuilder.toString();
}
/**
* Returns the parameter definitions of an ensemble. I.e. the parameter list split at ", ".
*
* @param ensemble
* @return Return an array containing the parameters of given ensemble.
*/
private static String[] splitEnsembleParameterList(final Ensemble ensemble) {
if (ensemble.getName() == null) {
ensemble.setName("");
}
final String name = ensemble.getName().length() == 0 ? "non-editpart" : ensemble.getName();
final Matcher m = PARAMETER_LIST.matcher(name);
if (!m.matches()) {
return new String[0];
}
final List<String> parameterDefinitions = new LinkedList<String>();
final String parameters = m.group(1);
int start = 0;
int matchParenthesis = 0;
for (int i = 0; i < parameters.length(); i++) {
if (parameters.charAt(i) == '(') {
matchParenthesis++;
}
if (matchParenthesis > 0 && parameters.charAt(i) == ')') {
matchParenthesis--;
}
if (parameters.charAt(i) == ',' && matchParenthesis == 0) {
parameterDefinitions.add(parameters.substring(start, i).trim());
start = i + 1;
}
}
parameterDefinitions.add(parameters.substring(start, parameters.length()).trim());
final String[] result = new String[parameterDefinitions.size()];
return parameterDefinitions.toArray(result);
}
/**
* @param parameter
* @return Return the encoded parameter.
*/
private static String createEncodedParameter(final String parameter) {
final StringBuilder s = new StringBuilder();
if (FIRST_LETTER_IS_UPPER_CASE.matcher(parameter).matches()) {
s.append("'");
s.append(parameter);
s.append("'");
s.append("=");
s.append(parameter);
return s.toString();
}
final Matcher m = PARAMETER_NAMES.matcher(parameter);
if (m.matches()) {
s.append("'");
s.append(m.group(1));
s.append("'");
s.append("=");
s.append(m.group(2));
return s.toString();
}
s.append("_");
s.append("=");
s.append(parameter);
return s.toString();
}
}