final Map<Long, Object[]> ruleColExecutionValue = new HashMap<>();
final Map<String, Integer> ruleAxisBindCount = new HashMap<>();
final Map<RuleMetaKeys, Object> ruleInfo = new CaseInsensitiveMap<>();
boolean done = false;
boolean anyRuleAxes = false;
Map trace = new CaseInsensitiveMap();
ruleInfo.put(RuleMetaKeys.RULES_EXECUTED, trace);
try
{
while (!done)
{
// Step #1 Create coordinate for current counter positions
final Map<String, Column> coord = new CaseInsensitiveMap<>();
idCoord.clear();
List ruleIds = new ArrayList();
for (final String axisName : axisNames)
{
final List<Column> cols = boundCoordinates.get(axisName);
final Column boundColumn = cols.get(counters.get(axisName) - 1);
final Axis axis = axisList.get(axisName);
if (axis.getType() == AxisType.RULE)
{
anyRuleAxes = true;
Object conditionValue;
Object[] ruleValueHolder = ruleColExecutionValue.get(boundColumn.id);
if (ruleValueHolder == null)
{ // Has the condition on the Rule axis been run this execution? If not, run it and cache it.
CommandCell cmd = (CommandCell) boundColumn.getValue();
Map<String, Object> ctx = prepareExecutionContext(validCoord, output);
// If the cmd == null, then we are looking at a default column on a rule axis.
conditionValue = cmd == null ? isZero(ruleAxisBindCount.get(axisName)) : cmd.execute(ctx);
ruleColExecutionValue.put(boundColumn.id, new Object[]{conditionValue});
if (didRuleFire(conditionValue))
{ // Rule fired
Integer count = ruleAxisBindCount.get(axisName);
ruleAxisBindCount.put(axisName, count == null ? 1 : count + 1);
}
}
else
{ // re-use condition on this rule axis (happens when more than one rule axis on an n-cube)
conditionValue = ruleValueHolder[0];
}
// A rule column on a given axis can be accessed more than once (example: A, B, C on
// one rule axis, X, Y, Z on another). This generates coordinate combinations
// (AX, AY, AZ, BX, BY, BZ, CX, CY, CZ). The condition columns must be run only once, on
// subsequent access, the cached result of the condition is used.
if (didRuleFire(conditionValue))
{
coord.put(axisName, boundColumn);
idCoord.add(boundColumn);
Object ruleId = boundColumn.getMetaProperties().get("name");
if (ruleId == null)
{
ruleId = boundColumn.id;
}
ruleIds.add(ruleId);
}
}
else
{
coord.put(axisName, boundColumn);
idCoord.add(boundColumn);
}
}
// Step #2 Execute cell and store return value, associating it to the Axes and Columns it bound to
if (idCoord.size() == axisNames.length)
{ // Conditions on rule axes that do not evaluate to true, do not generate complete coordinates (intentionally skipped)
T cellValue = getCellById(idCoord, validCoord, output);
executedCells.put(coord, cellValue);
if (!ruleIds.isEmpty())
{ // Record the names (or IDs) of the conditions that fired associated to the executed statements return value
trace.put(ruleIds, cellValue);
}
}
// Step #3 increment counters (variable radix increment)
done = incrementVariableRadixCount(counters, boundCoordinates, axisNames.length - 1, axisNames);