package de.renew.net.inscription.arc;

import de.renew.net.SimulatablePlaceInstance;
import de.renew.net.TokenReserver;
import de.renew.unify.Unify;
import de.renew.unify.Variable;
import de.renew.util.Value;

/**
 * An {@code InputArcBinder} is responsible for reserving the token that was bound by an
 * {@link ArcAssignBinder} and simulating the token's removal.
 */
public class InputArcBinder extends ArcRemoveBinder {
    private final Variable _delayVar;

    /**
     * The constructor of InputArcBinder.
     *
     * @param variable the variable that will be bound
     * @param delayVar the variable that determines the delay
     * @param placeInstance the place instance that tokens are taken from
     */
    protected InputArcBinder(
        Variable variable, Variable delayVar, SimulatablePlaceInstance placeInstance)
    {
        super(variable, placeInstance);
        _delayVar = delayVar;
    }

    private double getDelay() {
        Object timeObj = _delayVar.getValue();
        if (timeObj instanceof Value) {
            timeObj = ((Value) timeObj).value;
        }
        if (timeObj instanceof Number) {
            // For input arcs a positive delay forces earlier tokens.
            return ((Number) timeObj).doubleValue();
        } else {
            // Sorry, no such token.
            return Double.POSITIVE_INFINITY;
        }
    }

    @Override
    protected boolean mayBind() {
        return Unify.isBound(_delayVar);
    }

    @Override
    protected boolean possible(TokenReserver reserver, Object token) {
        double delay = getDelay();
        return delay != Double.POSITIVE_INFINITY
            && reserver.containsRemovableToken(getPlaceInstance(), token, delay);
    }

    @Override
    protected boolean remove(TokenReserver reserver, Object token) {
        double delay = getDelay();
        return delay != Double.POSITIVE_INFINITY
            && reserver.removeToken(getPlaceInstance(), token, delay);
    }

    @Override
    protected void unremove(TokenReserver reserver, Object token) {
        reserver.unremoveToken(getPlaceInstance(), token, getDelay());
    }
}