package easysm.calculators;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import easysm.Constants;
import easysm.datatypes.Expr;
import easysm.datatypes.Value;
import easysm.datatypes.information.*;
import easysm.factories.ListFactory;
import easysm.factories.SetFactory;
import easysm.stores.*;
import easysm.stores.Class;
/**
* @author Alessio Parma
*/
public class Generator
{
/**
* @param usedSO
* A set containing all used state observers, that is, the subset
* of state observers that are both "discrete" and "chosen" by
* the modeler to be used in the state table.
* @return A table as shown in figure 9 of the method, or an empty list if
* one or more of given state observers have a non finite type.
*/
public static List<Row> generateStateTable(List<StateObserver> usedSO)
{
if (usedSO.isEmpty()) {
return new Vector<Row>();
}
// We store the number of columns (i.e., the number of used state
// observers) since it is frequently used in following code
int columnCount = usedSO.size();
// Conversion to allow indexed traversal
StateObserver[] usedSo = usedSO.toArray(new StateObserver[0]);
Value[][] allValues = new Value[columnCount][];
int rowCount = 1;
for (int j = 0; j < columnCount; ++j) {
if (usedSo[j].type().values() == null) {
return new Vector<Row>();
}
allValues[j] = usedSo[j].type().values().toArray(new Value[0]);
rowCount *= allValues[j].length;
}
// It would be sufficient a Vector<Value>[], but it seems it is not
// possible to allocate such a type
Vector<Vector<Value>> rows = new Vector<Vector<Value>>(rowCount);
for (int i = 0; i < rowCount; ++i) {
rows.add(new Vector<Value>(columnCount));
}
int rowSubsets = 1;
for (int j = 0; j < columnCount; ++j) {
rowSubsets *= allValues[j].length;
int subsetSize = rowCount / rowSubsets;
for (int i = 0; i < rowSubsets; ++i) {
Value currValue = allValues[j][i % allValues[j].length];
for (int k = 0; k < subsetSize; ++k) {
rows.get(i * subsetSize + k).add(currValue);
}
}
}
List<Row> rowsToReturn = new Vector<Row>(rowCount);
for (int i = 0; i < rowCount; ++i) {
rowsToReturn.add(new Row(rows.get(i), Constants.IMPOSSIBLE_NAME));
}
return rowsToReturn;
}
/**
* If given class diagram has not a context class,
* this method will return an empty set.
*/
public static Set<StateObserver> generateBasicSO(ClassDiagram cd)
{
StateObserverInfo soInfo;
Set<StateObserver> basicSO = SetFactory.createSet(StateObserver.class);
if (cd.context() == null) {
return basicSO;
}
for (Attribute a : cd.context().attributes()) {
soInfo = new StateObserverInfo(a.name(), a.type(), Expr.EMPTY);
basicSO.add(new StateObserver(soInfo));
}
return basicSO;
}
/**
* If given class diagram has not a context class,
* this method will return an empty set.
*/
public static Set<Event> generateBasicEvents(ClassDiagram cd)
{
Set<Event> basicEvents = SetFactory.createSet(Event.class);
Set<ParameterInfo> paramsInfo;
if (cd.context() == null) {
return basicEvents;
}
for (Operation o : cd.context().operations()) {
if (o.returnType() != null) {
continue;
}
paramsInfo = SetFactory.createSet(ParameterInfo.class);
for (Parameter p : o.parameters()) {
paramsInfo.add(new ParameterInfo(p.name(), p.type()));
}
EventInfo eventInfo = new EventInfo(o.name(), paramsInfo);
basicEvents.add(new Event(eventInfo));
}
return basicEvents;
}
/**
* Returns a list containing at least the initial state,
* and a state for each state defined in given state table.
*/
public static List<State> generateStates(StateTable stateTable)
{
List<State> states = ListFactory.createList(State.class);
// Initial state, always necessary
states.add(State.INITIAL);
// Defined states
for (Row row : stateTable.rows()) {
if (row.state() != null) {
states.add(row.state());
}
}
return states;
}
/**
* Returns a transition having given source and target,
* as condition and reaction the "remaining" condition
* and reaction, as trigger the signature of given event.
*/
public static Transition generateTransition(State source,
State target,
Event event,
CondReact cr)
{
String repr = (event.equals(Event.CREATED)) ? "" : event.toString();
return new Transition(source, target, cr.remCond(), cr.remReact(), new UMLEvent(repr));
}
/**
* If given class diagram has not a context class,
* this method will return an empty class diagram.
*/
public static ClassDiagram generateOutputCD(ClassDiagram inputCD,
List<StateObserver> stateObservers,
List<Event> events)
{
// Output class diagram
ClassDiagram outputCD = new ClassDiagram(new ClassDiagramInfo());
// If context is not defined, return an empty class diagram
if (inputCD.context() == null) {
return outputCD;
}
// Context class
ClassInfo contextInfo = new ClassInfo(inputCD.context().name());
Class context = new Class(contextInfo);
outputCD.addCDElement(context);
outputCD.changeContext(context);
// All other classes and enumerations
for (Class cl : inputCD.classes()) {
if (cl != inputCD.context()) {
outputCD.addCDElement(cl);
}
}
for (Enumeration en : inputCD.enums()) {
outputCD.addCDElement(en);
}
// All NOT used state observers as context class attributes
for (StateObserver so : stateObservers) {
if (so.equals(StateObserver.FINAL)) {
continue;
}
AttributeInfo attrInfo = new AttributeInfo(so.name(), context, so.type());
outputCD.addCDElement(new Attribute(attrInfo));
}
// All events as context class operations
for (Event event : events) {
if (event.equals(Event.CREATED)) {
continue;
}
Set<ParameterInfo> paramsInfo = SetFactory.createSet(ParameterInfo.class);
for (Parameter param : event.parameters()) {
paramsInfo.add(new ParameterInfo(param.name(), param.type()));
}
OperationInfo opInfo = new OperationInfo(event.name(), context, paramsInfo, null);
outputCD.addCDElement(new Operation(opInfo));
}
return outputCD;
}
}