/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.operations;
import java.util.HashMap;
import java.util.Map;
import org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.bindings.IBindingManager;
import org.whole.lang.bindings.IBindingScope;
import org.whole.lang.bindings.IEnvironmentManager;
import org.whole.lang.bindings.NullScope;
import org.whole.lang.model.IEntity;
import org.whole.lang.reflect.ILanguageKit;
import org.whole.lang.reflect.ReflectionFactory;
import org.whole.lang.util.DataTypeUtils;
import org.whole.lang.visitors.IVisitor;
/**
* @author Riccardo Solmi
*/
public abstract class AbstractOperation implements IOperation {
private String operationId;
private final IOperation enclosingOperation;
private final IEnvironmentManager environmentManager;
private final IBindingManager operationEnvironment;
private final IBindingScope resultsScope, argumentsScope;
private String phase = null;
private boolean templatePhase = false;
private int stage = 0;
protected Map<String, IVisitor[]> stagedVisitorsMap; // uri -> stagedVisitors[2]
protected IVisitor[] stagedDefaultVisitors = new IVisitor[2];
private IOperationProgressMonitor operationProgressMonitor = null;
public AbstractOperation(String name, IBindingManager args, boolean resultsInArgs) {
this(name, args, resultsInArgs ? args.wTargetScope() : args.wEnclosingScope());
}
public AbstractOperation(String name, IBindingManager args, IBindingScope optResultsScope) {
operationId = name;
stagedVisitorsMap = initStagedVisitors();
environmentManager = args.wGetEnvironmentManager();
enclosingOperation = environmentManager.getCurrentOperation();
operationEnvironment = args;
argumentsScope = args.wTargetScope();
if (optResultsScope != null)
args.wSetResultScope(optResultsScope);
if (args.wResultScope() == null)
args.wSetResultScope(argumentsScope);
resultsScope = args.wResultScope();
if (resultsScope == NullScope.instance)
throw new IllegalStateException("ResultsScope is a NullScope");
}
public String getOperationId() {
return operationId;
}
public IOperation getEnclosingOperation() {
return enclosingOperation;
}
public IEnvironmentManager getEnvironmentManager() {
return environmentManager;
}
public IBindingManager getOperationEnvironment() {
return operationEnvironment;
}
public IBindingScope getResultsScope() {
if (resultsScope.hasResultIterator())
resultsScope.getResultIterator().setBindings(operationEnvironment);
return resultsScope;
}
public IBindingScope getArgumentsScope() {
return argumentsScope;
}
public boolean isCanceled() {
return getProgressMonitor().isCanceled();
}
public void setCanceled(boolean value) {
getProgressMonitor().setCanceled(value);
}
public IOperationProgressMonitor getProgressMonitor() {
//TODO add environment delegation such that there's always an operationProgressMonitor defined
if (operationProgressMonitor == null) {
operationProgressMonitor = getOperationEnvironment().wIsSet("progressMonitor") ?
(IOperationProgressMonitor) getOperationEnvironment().wGetValue("progressMonitor") :
new DefaultOperationProgressMonitor();
}
return operationProgressMonitor;
}
public boolean isSelectedFeature(String name) {
IBindingManager configuration = getEnvironmentManager().getEnvironment(IEnvironmentManager.CONFIGURATION);
IEntity value = configuration.wGet(name);
if (value == null)
return false;
else if (DataTypeUtils.getDataKind(value).isBoolean())
return value.wBooleanValue();
else
return true;
}
public IEntity setFeature(String name, boolean value) {
return setFeature(name, BindingManagerFactory.instance.createValue(value));
}
public IEntity setFeature(String name, IEntity value) {
IBindingManager configuration = getEnvironmentManager().getEnvironment(IEnvironmentManager.CONFIGURATION);
IEntity oldValue = configuration.wGet(name);
if (value == null)
configuration.wUnset(name);
else if (configuration.wIsSet(name))
configuration.wSetValue(name, value);
else
configuration.wDefValue(name, value);
return oldValue;
}
public final String getPhase() {
return phase;
}
public final void setPhase(String phase) {
this.phase = phase;
}
public final int getStage() {
return stage;
}
public final void setStage(int stage) {
if (!templatePhase)
this.stage = stage;
}
public IVisitor getVisitor(IEntity entity, int absoluteStage) {
int normalizedStage = absoluteStage <= 0 ? 0 : 1;
String uri = ReflectionFactory.getLanguageKit(entity).getURI();
IVisitor[] stagedVisitors = stagedVisitorsMap.get(uri);
if (stagedVisitors == null)
stagedVisitorsMap.put(uri, stagedVisitors = new IVisitor[2]);
IVisitor visitor = stagedVisitors[normalizedStage];
if (visitor == null) {
visitor = stagedVisitors[normalizedStage] = initVisitor(entity, normalizedStage);
visitor.setOperation(this);
}
return visitor;
}
//TODO test and change into liftVisitor
public IVisitor setVisitor(IEntity entity, int absoluteStage, IVisitor visitor) {
ILanguageKit languageKit = ReflectionFactory.getLanguageKit(entity);
IVisitor oldVisitor = languageKit.hasVisitor(this) ? getVisitor(entity, absoluteStage) : null;
int normalizedStage = absoluteStage <= 0 ? 0 : 1;
String uri = ReflectionFactory.getLanguageKit(entity).getURI();
IVisitor[] stagedVisitors = stagedVisitorsMap.get(uri);
if (stagedVisitors == null)
stagedVisitorsMap.put(uri, stagedVisitors = new IVisitor[2]);
stagedVisitors[normalizedStage] = visitor;
return oldVisitor;
}
protected Map<String, IVisitor[]> initStagedVisitors() {
return new HashMap<String, IVisitor[]>();
}
protected IVisitor initVisitor(IEntity entity, int normalizedStage) {
ILanguageKit languageKit = ReflectionFactory.getLanguageKit(entity);
IVisitor visitor = null;
if (languageKit.hasVisitor(this))
visitor = languageKit.getVisitor(this, normalizedStage);
if (visitor == null)
visitor = getDefaultVisitor(entity, normalizedStage);
return visitor;
}
public IVisitor getDefaultVisitor(IEntity entity, int absoluteStage) {
int normalizedStage = absoluteStage <= 0 ? 0 : 1;
if (stagedDefaultVisitors[normalizedStage] == null) {
stagedDefaultVisitors[normalizedStage] = createDefaultVisitor(entity, normalizedStage);
stagedDefaultVisitors[normalizedStage].setOperation(this);
}
return stagedDefaultVisitors[normalizedStage];
}
protected IVisitor createDefaultVisitor(IEntity entity, int normalizedStage) {
//TODO getOperation(normalizedStage).getVisitor(entity, normalizedStage);
throw new UnsupportedOperationException("The "+entity.wGetLanguageKit().getURI()+" language does not support the (visitor) operation "+getOperationId()+" at stage "+normalizedStage+".");
}
public final void stagedVisit(IEntity entity) {
stagedVisit(entity, 0);
}
public void stagedVisit(IEntity entity, int stageShift) {
boolean isOperationChanged = getEnvironmentManager().getCurrentOperation() != this;
if (isOperationChanged)
getEnvironmentManager().enterOperation(this);
int oldAbsoluteStage = getStage();
if (stageShift == 0 || templatePhase)
getVisitor(entity, oldAbsoluteStage).visit(entity);
else {
int absoluteStage = oldAbsoluteStage + stageShift;
setStage(absoluteStage);
getVisitor(entity, absoluteStage).visit(entity);
setStage(oldAbsoluteStage);
}
if (isOperationChanged)
getEnvironmentManager().exitOperation();
}
public static int PHASE_SHIFT = 100;
public void stagedVisit(IEntity entity, int stageShift, String phase) {
String outerPhase = getPhase();
int outerStage = getStage();
boolean samePhase = (phase == null && phase == outerPhase) || (phase != null && phase.equals(outerPhase));
boolean outerTemplate = outerStage > 0;
// boolean innerTemplate = stageShift > 0;
if (samePhase)
stagedVisit(entity, stageShift);
else if (outerTemplate) {
boolean outerTemplatePhase = templatePhase;
templatePhase = true;
stagedVisit(entity);
templatePhase = outerTemplatePhase;
} else {
setPhase(phase);
stagedVisit(entity, stageShift*PHASE_SHIFT);
setPhase(outerPhase);
}
}
public void stagedDefaultVisit(IEntity entity, int stageShift) {
boolean isOperationChanged = getEnvironmentManager().getCurrentOperation() != this;
if (isOperationChanged)
getEnvironmentManager().enterOperation(this);
int oldAbsoluteStage = getStage();
if (stageShift == 0 || templatePhase)
getDefaultVisitor(entity, oldAbsoluteStage).visit(entity);
else {
int absoluteStage = oldAbsoluteStage + stageShift;
setStage(absoluteStage);
getDefaultVisitor(entity, absoluteStage).visit(entity);
setStage(oldAbsoluteStage);
}
if (isOperationChanged)
getEnvironmentManager().exitOperation();
}
}