package com.progressoft.brix.domino.gwt.client.history;

import com.progressoft.brix.domino.api.client.ClientApp;
import com.progressoft.brix.domino.api.shared.history.AppHistory;
import com.progressoft.brix.domino.api.shared.history.HistoryToken;
import com.progressoft.brix.domino.api.shared.history.TokenFilter;
import com.progressoft.brix.domino.gwt.client.history.History.PopStateEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class StateHistory implements AppHistory {

    private static final Logger LOGGER = LoggerFactory.getLogger(StateHistory.class);

    private Set<HistoryListener> listeners = new HashSet<>();

    public StateHistory() {
        PopStateEventListener listener =
                event -> {
                    if (Objects.nonNull(event.getState()))
                        inform(event.getState().historyToken, event.getState().title, event.getState().data);
                };
        Window.getSelf().addEventListener("popstate", listener::onPopState);
    }

    private void inform(String token, String title, String stateJson) {
        listeners.stream().filter(l -> l.tokenFilter.filter(token))
                .forEach(l -> ClientApp.make().getAsyncRunner().runAsync(() ->
                        l.listener.onPopState(new DominoHistoryState(token, title, stateJson))));
    }

    @Override
    public DirectState listen(StateListener listener) {
        return listen(TokenFilter.any(), listener);
    }

    @Override
    public DirectState listen(TokenFilter tokenFilter, StateListener listener) {
        listeners.add(new HistoryListener(listener, tokenFilter));
        return new DominoDirectState(tokenFilter, currentState());
    }

    @Override
    public void back() {
        Window.getSelf().getHistory().back();
    }

    @Override
    public void forward() {
        Window.getSelf().getHistory().forward();
    }

    @Override
    public void pushState(String token, String title, String data) {
        Window.getSelf().getHistory().pushState(History.state(token, title, data), title, "/" + token);
    }

    @Override
    public void replaceState(String token, String title, String data) {
        Window.getSelf().getHistory().replaceState(
                History.state(token, data), title, "/" + token);
    }

    @Override
    public StateHistoryToken currentToken() {
        return new StateHistoryToken(windowToken());
    }

    @Override
    public void fireCurrentStateHistory() {
        fireState(windowToken(), stateData(windowState()));
    }

    private void fireState(String token, String state) {
        replaceState(token, windowTitle(), state);
        inform(token, windowTitle(), state);
    }

    private History.State windowState() {
        return Window.getSelf().getHistory().getState();
    }

    private String windowTitle() {
        return Window.getSelf().getDocument().getTitle();
    }

    private String windowToken() {
        return Window.getSelf().getLocation().getPathname().substring(1) + Window.getSelf().getLocation().getSearch();
    }

    private State currentState() {
        return new DominoHistoryState(windowToken(), windowTitle(), stateData(windowState()));
    }

    private String stateData(History.State state) {
        return Objects.isNull(state) ? "" : state.data;
    }

    private class HistoryListener {
        private final StateListener listener;

        private final TokenFilter tokenFilter;

        private HistoryListener(StateListener listener,
                                TokenFilter tokenFilter) {
            this.listener = listener;
            this.tokenFilter = tokenFilter;
        }
    }

    private class DominoHistoryState implements State {

        private final HistoryToken token;
        private final String data;
        private final String title;

        public DominoHistoryState(String token, String title, String data) {
            this.token = new StateHistoryToken(token);
            this.data = data;
            this.title = title;
        }

        @Override
        public HistoryToken token() {
            return this.token;
        }

        @Override
        public String data() {
            return this.data;
        }

        @Override
        public String title() {
            return this.title;
        }
    }
}

@@ -526,16 +526,52 @@
 l.Set;%0A%0A
+import static java.util.Objects.*;%0A%0A
 public c
@@ -883,24 +883,16 @@
     if (
-Objects.
 nonNull(
@@ -2077,32 +2077,121 @@
  String data) %7B%0A
+        if(nonNull(currentToken().value()) && !currentToken().value().equals(token))%0A    
         Window.g
@@ -2270,32 +2270,32 @@
 , %22/%22 + token);%0A
-
     %7D%0A%0A    @Over
@@ -3448,32 +3448,32 @@
 .State state) %7B%0A
+
         return O
@@ -3471,24 +3471,16 @@
  return 
-Objects.
 isNull(s

fix push state is fired after pop state event completion