package de.renew.net.inscription.arc;

import de.renew.engine.common.SimulatorEventLogger;
import de.renew.engine.events.Checking;
import de.renew.engine.events.Removing;
import de.renew.engine.events.SimulationEvent;
import de.renew.engine.searcher.EarlyExecutable;
import de.renew.engine.searchqueue.SearchQueue;
import de.renew.net.SimulatablePlaceInstance;
import de.renew.simulatorontology.simulation.StepIdentifier;
import de.renew.unify.Impossible;


class InputArcExecutable implements EarlyExecutable {
    private final SimulatablePlaceInstance _placeInstance;
    private final Object _token;
    private final double _delay;
    private final boolean _trace;
    private final boolean _releaseImmediately;

    // This field will store the time stamp of the removed token
    // after a successful removal.
    private double _removeTime;

    InputArcExecutable(
        SimulatablePlaceInstance pInstance, Object token, double delay, boolean releaseImmediately,
        boolean trace)
    {
        _placeInstance = pInstance;
        _token = token;
        _delay = delay;
        _trace = trace;


        // If releaseImmediately is true, the arc behaves like
        // a double arc that puts the token back as soon as possible.
        _releaseImmediately = releaseImmediately;
    }

    @Override
    public long lockPriority() {
        return _placeInstance.getLockOrder();
    }

    @Override
    public int phase() {
        return INPUT;
    }

    /**
     * Locks the {@link de.renew.net.PlaceInstance#_lock PlaceInstance} associated with this arc.
     **/
    @Override
    public void lock() {
        _placeInstance._lock.lock();
    }

    @Override
    public void verify(StepIdentifier stepIdentifier) throws Impossible {
        _removeTime = _placeInstance.removeToken(_token, _delay);
    }

    static void traceInArc(
        StepIdentifier stepIdentifier, boolean checking, Object token,
        SimulatablePlaceInstance placeInstance)
    { //NOTICEsignature
        SimulationEvent event =
            checking ? new Checking(token, placeInstance) : new Removing(token, placeInstance);
        SimulatorEventLogger.log(stepIdentifier, event, placeInstance);
    }

    @Override
    public void execute(StepIdentifier stepIdentifier) {
        if (_trace) {
            traceInArc(stepIdentifier, _releaseImmediately, _token, _placeInstance); //NOTICEsignature
        }

        if (_releaseImmediately) {
            // It would be conceivable to put the token back at
            // a different time.
            _placeInstance.insertToken(_token, SearchQueue.getTime());
        }
    }

    @Override
    public void rollback() {
        // We have to undo the previous removal. We cannot do this
        // without notifying the observers and listeners, because
        // the removal was not done silently. However, the database must not log
        // this modification.
        _placeInstance.internallyInsertToken(_token, _removeTime, false);
    }

    /**
     * Unlocks the {@link de.renew.net.PlaceInstance#_lock PlaceInstance} associated with this arc.
     **/
    @Override
    public void unlock() {
        _placeInstance._lock.unlock();
    }
}