package de.accso.flexinale.common.infrastructure.eventbus;

import de.accso.flexinale.common.api.eventbus.EventContextHolder;
import de.accso.flexinale.common.api.event.EventContext;
import de.accso.flexinale.common.shared_kernel.DeveloperMistakeException;

import java.util.concurrent.atomic.AtomicInteger;

public class InMemorySyncEventContextHolder implements EventContextHolder {

    // this implementation holds only one context:
    // - as long as a context with the same correlation id is used, it is kept, i.e. counter is increased (so that a remove is not deleting it yet)
    // - as soon as a context with a different correlation id is used, it is reset, i.e. counter is set to 1
    // -> So it is not possible to use a separate event chain and go back - for that, we could change that to a stack
    //    where context instances are pushed as new and popped to be cleared
    private EventContext CONTEXT = null;
    private AtomicInteger counter = new AtomicInteger(0);

    @Override
    public EventContext get() {
        return CONTEXT;
    }

    @Override
    public void set(final EventContext eventContext) {
        if (CONTEXT != null && CONTEXT.equalsByCorrelationId(eventContext)) {
            counter.incrementAndGet();
        }
        else {
            counter = new AtomicInteger(1);
            CONTEXT = eventContext;
        }
    }

    @Override
    public void remove() {
        if (counter.get() == 0) {
            throw new DeveloperMistakeException("remove on InMemorySyncEventContextHolder once too much, should not happen");
        }
        else {
            counter.decrementAndGet();
            if (counter.get() == 0) {
                CONTEXT = null;
            }
        }
    }

    @Override
    public boolean isEmpty() {
        return CONTEXT == null;
    }
}
