/*******************************************************************************
* Copyright (c) 2015 ARM Ltd. and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* ARM Ltd and ARM Germany GmbH - Initial API and implementation
*******************************************************************************/
package com.arm.cmsis.pack.data;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import com.arm.cmsis.pack.enums.EEvaluationResult;
/**
* Default implementation of ICpConditionContext interface
*/
public class CpConditionContext extends CpAttributes implements ICpConditionContext {
protected EEvaluationResult fResult = EEvaluationResult.IGNORED;
protected Map<ICpItem, EEvaluationResult> fResults = null;
// temporary variables
protected Set<ICpCondition> tConditionsBeingEvaluated = new HashSet<ICpCondition>(); // to prevent recursion
protected EEvaluationResult tResultAccept = EEvaluationResult.UNDEFINED; // keeps last (the best) accept result
protected boolean tbDeny = false; // flag is set when deny expression is evaluated
public CpConditionContext() {
}
@Override
public void resetResult() {
fResult = EEvaluationResult.IGNORED;
fResults = null;
tResultAccept = EEvaluationResult.UNDEFINED;
tbDeny = false;
tConditionsBeingEvaluated.clear();
}
@Override
public EEvaluationResult getEvaluationResult() {
return fResult;
}
@Override
public void setEvaluationResult(EEvaluationResult result) {
fResult = result;
}
protected void updateEvaluationResult(EEvaluationResult result) {
if(result.ordinal() < fResult.ordinal())
fResult = result;
}
@Override
public EEvaluationResult getEvaluationResult(ICpItem item) {
if(fResults != null)
return fResults.get(item);
return null;
}
@Override
public EEvaluationResult evaluate(ICpItem item) {
if(item == null)
return EEvaluationResult.IGNORED;
EEvaluationResult res = EEvaluationResult.UNDEFINED;
if(fResults == null)
fResults = new HashMap<ICpItem, EEvaluationResult>();
res = getCachedResult(item);
if(isEvaluate(res)) {
res = item.evaluate(this);
putCachedResult(item, res);
}
return res;
}
/**
* Checks if result to be (re-)evaluated
* @param res EEvaluationResult
* @return true if result to be (re-)evaluated
*/
protected boolean isEvaluate(EEvaluationResult res) {
return res == null || res == EEvaluationResult.UNDEFINED;
}
/**
* Retrieves cached result for the given item if already in cache
* @param item ICpItem for which to retrieve result
* @return cached result or null if not yet in cache
*/
protected EEvaluationResult getCachedResult(ICpItem item) {
if(fResults != null)
return fResults.get(item);
return null;
}
/**
* Puts evaluation result into cache
* @param item ICpItem for which to put the result
* @param res result value to cache
*/
protected void putCachedResult(ICpItem item, EEvaluationResult res) {
if(fResults == null)
fResults = new HashMap<ICpItem, EEvaluationResult>();
fResults.put(item, res);
}
@Override
public EEvaluationResult evaluateExpression(ICpExpression expression) {
if(expression == null)
return EEvaluationResult.IGNORED;
switch(expression.getExpressionDomain()) {
case ICpExpression.COMPONENT_EXPRESSION:
return EEvaluationResult.IGNORED;
case ICpExpression.DEVICE_EXPRESSION:
case ICpExpression.TOOLCHAIN_EXPRESSION:
boolean b = matchCommonAttributes(expression.attributes());
return b ? EEvaluationResult.FULFILLED : EEvaluationResult.FAILED;
case ICpExpression.REFERENCE_EXPRESSION:
return evaluate(expression.getCondition());
default:
break;
}
return EEvaluationResult.ERROR;
}
@Override
public EEvaluationResult evaluateCondition(ICpCondition condition) {
if(tConditionsBeingEvaluated.contains(condition))
return EEvaluationResult.ERROR; // recursion
tConditionsBeingEvaluated.add(condition);
EEvaluationResult resultRequire = EEvaluationResult.IGNORED;
EEvaluationResult resultAccept = EEvaluationResult.UNDEFINED;
// first check require and deny expressions
Collection<? extends ICpItem> children = condition.getChildren();
for(ICpItem child : children) {
if(!(child instanceof ICpExpression))
continue;
ICpExpression expr = (ICpExpression)child;
boolean bDeny = tbDeny; // save deny context
if(expr.getExpressionType() == ICpExpression.DENY_EXPRESSION)
tbDeny = !tbDeny; // invert the deny context
EEvaluationResult res = evaluate(expr);
tbDeny = bDeny; // restore deny context
if(res == EEvaluationResult.IGNORED || res == EEvaluationResult.UNDEFINED )
continue;
else if(res == EEvaluationResult.ERROR)
return res;
if(expr.getExpressionType() == ICpExpression.ACCEPT_EXPRESSION) {
if(res.ordinal() > resultAccept.ordinal()){
resultAccept = res;
}
} else {
if(res.ordinal() < resultRequire.ordinal()){
resultRequire = res;
}
}
}
tConditionsBeingEvaluated.remove(condition);
tResultAccept = resultAccept;
if(resultAccept != EEvaluationResult.UNDEFINED &&
resultAccept.ordinal() < resultRequire.ordinal()) {
return resultAccept;
}
return resultRequire;
}
@Override
public Collection<ICpItem> filterItems(Collection<? extends ICpItem> sourceCollection) {
Collection<ICpItem> filtered = new LinkedList<ICpItem>();
if(sourceCollection != null && ! sourceCollection.isEmpty()) {
for(ICpItem item : sourceCollection) {
EEvaluationResult res = item.evaluate(this);
if(res.isFulfilled())
filtered.add(item);
}
}
return filtered;
}
}