package com.sap.runlet.interpreter.expressions;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashSet;
import java.util.Set;
import behavioral.actions.Statement;
import com.sap.runlet.abstractinterpreter.Interpreter;
import com.sap.runlet.abstractinterpreter.objects.MultiValuedObject;
import com.sap.runlet.abstractinterpreter.objects.RunletObject;
import com.sap.runlet.abstractinterpreter.repository.RepositoryObject;
import com.sap.runlet.interpreter.RunletInterpreter;
import com.sap.runlet.interpreter.RunletStackFrame;
import com.sap.runlet.interpreter.objects.FunctionObject;
import com.sap.runlet.interpreter.statements.ReturnInterpreter;
import data.classes.Association;
import data.classes.AssociationEnd;
import data.classes.ClassTypeDefinition;
import data.classes.FunctionSignatureImplementation;
import data.classes.NativeImpl;
import data.classes.SapClass;
import data.classes.SignatureImplementation;
import data.classes.TypeDefinition;
import dataaccess.analytics.CellSet;
import dataaccess.analytics.Dimension;
import dataaccess.analytics.DimensionExpression;
import dataaccess.expressions.Expression;
public class DimensionExpressionInterpreter implements Interpreter<DimensionExpression, SapClass, TypeDefinition, ClassTypeDefinition, Association, AssociationEnd, Statement, Expression, SignatureImplementation, RunletStackFrame, NativeImpl, RunletInterpreter> {
/**
* Wraps a {@link RunletObject} such that its {@link #equals(Object)} and
* {@link #hashCode()} implementation map to
* {@link RunletObject#logicallyEquals(RunletObject)} and
* {@link RunletObject#logicalHashCode()}, respectively. These compare/hash
* ignoring the {@link RepositoryObject#getOrigin() snapshot} to which the
* object belongs.
*
* @author Axel Uhl D043530
*/
private static class LogicalWrapper {
private RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> ro;
public LogicalWrapper(RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> ro) {
this.ro = ro;
}
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
if (o instanceof LogicalWrapper) {
return ro.logicallyEquals(((LogicalWrapper) o).get());
} else if (o instanceof RunletObject) {
return ro.logicallyEquals((RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) o);
} else {
return false;
}
}
public int hashCode() {
return ro.logicalHashCode();
}
public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> get() {
return ro;
}
}
private DimensionExpression dimensionExpression;
public DimensionExpressionInterpreter(DimensionExpression dimensionExpression) {
this.dimensionExpression = dimensionExpression;
}
@Override
public RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> evaluate(RunletInterpreter interpreter)
throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> facts = interpreter.evaluate(dimensionExpression.getFacts());
FunctionObject cellSetFunction = (FunctionObject) interpreter.evaluate(dimensionExpression.getCellSet());
CellSet cellSet = (CellSet) cellSetFunction.getImplementation();
Set<LogicalWrapper> wrappedDimensionValues = new LinkedHashSet<LogicalWrapper>();
Set<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>> dimensionValues = new LinkedHashSet<RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>>();
int dimensionIndex = dimensionExpression.getDimensionParameter().getOwnerSignature().getInput().indexOf(dimensionExpression.getDimensionParameter()) - 1;
Dimension dimension = cellSet.getDimensions().get(dimensionIndex);
FunctionSignatureImplementation impl = dimension.getCharacteristicFunction().getImplementation();
// TODO correct nested multiplicity handling, removing the "flatten()"
// call again
for (RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> fact : facts.flatten()) {
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> dimensionValueForFact = interpreter.convert(
callSingleArgFunction(interpreter, fact, impl), dimensionExpression.getDimensionParameter().getType());
// compare dimension values ignoring snapshot
LogicalWrapper lw = new LogicalWrapper(dimensionValueForFact);
if (!wrappedDimensionValues.contains(lw)) {
wrappedDimensionValues.add(lw);
dimensionValues.add(dimensionValueForFact);
}
}
MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> result =
new MultiValuedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>(
dimensionExpression.getType(), dimensionValues, dimensionExpression.getType().isOrdered(),
dimensionExpression.getType().isUnique());
return result;
}
private RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> callSingleArgFunction(RunletInterpreter interpreter,
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> arg, FunctionSignatureImplementation impl)
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
RunletStackFrame stackFrame = new RunletStackFrame();
stackFrame.enterValue(impl.getImplementedSignature().getInput().get(0).getName(), arg);
interpreter.push(stackFrame);
RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> dimensionValueForFact = ((ReturnInterpreter.ReturnResult) interpreter
.evaluateSignatureImplementation(impl)).getResult();
interpreter.pop();
return dimensionValueForFact;
}
}