package de.renew.net;

import de.renew.engine.thread.SimulationThreadPool;
import de.renew.expression.Expression;
import de.renew.expression.VariableMapper;
import de.renew.unify.Impossible;
import de.renew.unify.StateRecorder;
import de.renew.unify.Unify;


/**
 * An ExpressionTokenSource is a {@link TokenSource} that creates tokens from the result of an expression.
 */
public class ExpressionTokenSource implements TokenSource {
    /**
     * The expression that is evaluated to generate tokens.
     */
    private final Expression _expression;
    /**
     * Whether tracing should be activated for this {@code ExpressionTokenSource}.
     */
    private boolean _trace = true;

    /**
     * Constructs a new {@code ExpressionTokenSource} based on an expression.
     *
     * @param expression the expression whose result will be used as the created token
     */
    public ExpressionTokenSource(Expression expression) {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        _expression = expression;
    }

    /**
     * Activate/Deactivate tracing for this {@code ExpressionTokenSource} according to the given parameter.
     *
     * @param trace {@code true} if tracing should be active, {@code false} otherwise
     */
    public void setTrace(boolean trace) {
        _trace = trace;
    }

    /**
     * Get whether tracing is active for this {@code ExpressionTokenSource}.
     *
     * @return {@code true} if tracing is active, {@code false} otherwise
     */
    public boolean getTrace() {
        return _trace;
    }

    @Override
    public Object createToken(VariableMapper mapper) throws Impossible {
        assert SimulationThreadPool.isSimulationThread() : "is not in a simulation thread";
        Object value = _expression.startEvaluation(mapper, new StateRecorder(), null);
        if (!Unify.isBound(value)) {
            throw new Impossible("Cannot bind expression " + _expression);
        }
        return value;
    }
}