package org.dominokit.domino.api.client.mvp.presenter;

import org.dominokit.domino.api.client.ClientApp;
import org.dominokit.domino.api.client.async.AsyncRunner;
import org.dominokit.domino.api.client.extension.DominoEvents;
import org.dominokit.domino.api.client.startup.BaseRoutingStartupTask;
import org.dominokit.domino.api.shared.extension.DominoEvent;
import org.dominokit.domino.api.shared.extension.DominoEventListener;
import org.dominokit.domino.history.AppHistory;
import org.dominokit.domino.history.DominoHistory;
import org.dominokit.domino.history.TokenParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public abstract class BaseClientPresenter extends ClientPresenter implements Presentable {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseClientPresenter.class);
    private PresenterState state;
    protected boolean activated;
    private BaseRoutingStartupTask routingTask;

    private final PresenterState initialized = () ->
            LOGGER.info("Presenter " + BaseClientPresenter.this.getClass() + " Have already been initialized.");

    private final PresenterState uninitialized = this::initialize;

    private Map<Class<? extends DominoEvent>, DominoEventListener> listeners;

    protected void initialize() {
        postConstruct();
        this.listeners = getListeners();
        registerListeners();
        state = initialized;
        if (isAutoActivate()) {
            activate();
        }
    }

    protected void postConstruct() {

    }

    protected void activate() {
        activated = true;
        fireStateEvent(true);
        onActivated();
    }

    protected void fireStateEvent(boolean state) {
        fireActivationEvent(state);
    }

    protected void fireActivationEvent(boolean state) {
    }

    private void registerListeners() {
        listeners.forEach((key, value) -> ClientApp.make().registerEventListener(key, value));
    }

    private void removeListeners() {
        listeners.forEach((key, value) -> ClientApp.make().removeEventListener(key, value));
    }

    @Override
    public Presentable init() {
        this.state = uninitialized;
        prepare();
        return this;
    }

    @Override
    public ClientPresenter prepare() {
        state.process();
        return this;
    }

    protected final void deActivate() {
        removeListeners();
        activated = false;
        fireStateEvent(false);
        onDeactivated();
    }

    @Override
    protected void onActivated() {

    }

    @Override
    protected void onDeactivated() {

    }

    public void setState(DominoHistory.State state) {

    }

    public void setRoutingTask(BaseRoutingStartupTask routingTask) {
        this.routingTask = routingTask;
    }

    public final void onSkippedRouting() {
        if (!routingTask.isEnabled()) {
            routingTask.enable();
        }
    }

    protected void publishState(String token, String title, String data) {
        routingTask.disable();
        history().fireState(token, title, data);
    }

    protected void publishState(String token, String title, String data, TokenParameter... parameters) {
        routingTask.disable();
        history().fireState(token, title, data, parameters);
    }

    protected void publishState(String token) {
        routingTask.disable();
        history().fireState(token);
    }

    protected void publishState(String token, TokenParameter... parameters) {
        routingTask.disable();
        history().fireState(token, parameters);
    }

    protected boolean isAutoActivate() {
        return true;
    }

    public final boolean isActivated() {
        return activated;
    }

    protected Map<Class<? extends DominoEvent>, DominoEventListener> getListeners() {
        return new HashMap<>();
    }

    protected <E extends DominoEvent> void fireEvent(Class<E> extensionPointInterface, E extensionPoint) {
        DominoEvents.fire(extensionPointInterface, extensionPoint);
    }

    protected void runAsync(AsyncRunner.AsyncTask asyncTask) {
        ClientApp.make().getAsyncRunner().runAsync(asyncTask);
    }

    protected AppHistory history() {
        return ClientApp.make().getHistory();
    }
}

@@ -220,16 +220,190 @@
 Events;%0A
+import org.dominokit.domino.api.client.mvp.IsStore;%0Aimport org.dominokit.domino.api.client.mvp.RegistrationHandler;%0Aimport org.dominokit.domino.api.client.mvp.StoreRegistry;%0A
 import o
@@ -806,16 +806,44 @@
 ctory;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -860,16 +860,39 @@
 ashMap;%0A
+import java.util.List;%0A
 import j
@@ -1519,16 +1519,100 @@
 steners;
+%0A    private final List%3CRegistrationHandler%3E storeRegisterations= new ArrayList%3C%3E();
 %0A%0A    pr
@@ -2790,24 +2790,48 @@
 ent(false);%0A
+        removeStores();%0A
         onDe
@@ -2842,32 +2842,175 @@
 vated();%0A    %7D%0A%0A
+    private void removeStores()%7B%0A        storeRegisterations.forEach(RegistrationHandler::remove);%0A        storeRegisterations.clear();%0A    %7D%0A%0A
     @Override%0A  
@@ -3163,32 +3163,255 @@
 tate) %7B%0A%0A    %7D%0A%0A
+    public void RegisterStore(String key, IsStore%3C?%3E store)%7B%0A        RegistrationHandler registrationHandler = StoreRegistry.INSTANCE.registerStore(key, store);%0A        storeRegisterations.add(registrationHandler);%0A%0A    %7D%0A%0A
     public void 

allow presenter to register stores and remove them upon deactivation