content: package org.lightview.presenter;
  
  import java.util.*;
  import javafx.beans.property.StringProperty;
  import javafx.beans.value.ChangeListener;
  import javafx.beans.value.ObservableValue;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  import javafx.collections.ObservableMap;
  import javafx.concurrent.Worker;
  import org.lightview.model.Escalation;
  import org.lightview.model.Script;
  import org.lightview.model.Snapshot;
  import org.lightview.service.EscalationProvider;
  import org.lightview.service.ScriptManager;
  
  /**
   *
   * @author adam bien, adam-bien.com
   */
  public final class EscalationsPresenter implements EscalationsPresenterBindings {
  
      public static final String ESCALATIONS_URI = "/escalations/";
      ScriptManager scriptManager;
      StringProperty uri;
      private ObservableMap<String, ObservableList<Snapshot>> escalationBindings;
      private Map<String, EscalationProvider> runningServices;
  
      public EscalationsPresenter(StringProperty uri) {
          this.uri = uri;
          this.escalationBindings = FXCollections.observableHashMap();
          this.runningServices = new HashMap<>();
          registerURIListener();
      }
  
      void resyncActiveScripts() {
          List<Script> scripts = this.scriptManager.getAllScripts();
          Set<String> keySet = this.escalationBindings.keySet();
          for (String scriptName : keySet) {
              if (!scriptExists(scripts, scriptName)) {
                  deactivateEscalationService(scriptName);
              }
          }
          for (Script script : scripts) {
              final String name = script.getName();
              if (!this.escalationBindings.containsKey(name)) {
                  this.escalationBindings.put(name, getSnapshots(name));
                  this.registerService(name);
              }
          }
      }
  
      void registerURIListener() {
          this.uri.addListener(new ChangeListener<String>() {
              @Override
              public void changed(ObservableValue<? extends String> ov, String t, String uri) {
                  System.out.println("Uri changed to: " + uri);
                  if (uri != null) {
                      reinitializeScriptManager(uri);
                      restartServices();
                  }
              }
          });
      }
  
      void startFetching() {
          runningServices.clear();
          List<Script> scripts = this.scriptManager.getAllScripts();
          System.out.println("Scripts: " + scripts);
          for (Script script : scripts) {
              final String scriptName = script.getName();
              registerService(scriptName);
          }
      }
  
      void registerService(final String scriptName) {
          EscalationProvider provider = new EscalationProvider(getUri() + ESCALATIONS_URI + scriptName);
          this.runningServices.put(scriptName, provider);
          provider.start();
          provider.valueProperty().addListener(
                  new ChangeListener<Escalation>() {
  
                      @Override
                      public void changed(ObservableValue<? extends Escalation> observable, Escalation old, Escalation newValue) {
                          if (newValue != null) {
                              onEscalationArrival(scriptName, newValue);
                          }
                      }
                  });
          registerRestarting(provider);
      }
  
      void restartServices() {
          for (EscalationProvider escalationProvider : runningServices.values()) {
              resetService(escalationProvider);
          }
          this.startFetching();
      }
  
      void resetService(EscalationProvider service) {
          if (service != null && service.isRunning()) {
              service.cancel();
              service.reset();
          }
      }
  
      private void onEscalationArrival(String scriptName, Escalation newValue) {
          System.out.println("Arrived: " + scriptName + " " + newValue);
          resyncActiveScripts();
          ObservableList<Snapshot> snapshots = getSnapshots(scriptName);
          if (!snapshots.contains(newValue.getSnapshot())) {
              snapshots.add(newValue.getSnapshot());
          }
      }
  
      void registerRestarting(final EscalationProvider provider) {
          provider.stateProperty().addListener(new ChangeListener<Worker.State>() {
  
              @Override
              public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldState, Worker.State newState) {
                  if (newState.equals(Worker.State.SUCCEEDED) || newState.equals(Worker.State.FAILED)) {
                      provider.reset();
                      provider.start();
                  }
              }
          });
      }
  
      public String getUri() {
          return this.uri.getValue();
      }
  
      @Override
      public ObservableMap<String, ObservableList<Snapshot>> getEscalations() {
          return escalationBindings;
      }
  
      ObservableList<Snapshot> getSnapshots(String scriptName) {
          ObservableList<Snapshot> escalationForScript = this.escalationBindings.get(scriptName);
          if (escalationForScript == null) {
              escalationForScript = FXCollections.observableArrayList();
              this.escalationBindings.put(scriptName, escalationForScript);
          }
          return escalationForScript;
      }
  
      void reinitializeScriptManager(String uri) {
          this.scriptManager = new ScriptManager(uri);
      }
  
      @Override
      public void deleteScript(String name) {
          this.scriptManager.deleteScript(name);
          this.resyncActiveScripts();
      }
  
      @Override
      public void newScript(String name, String content) {
          this.scriptManager.registerNewScript(new Script(name, content, true));
          this.resyncActiveScripts();
      }
  
      boolean scriptExists(List<Script> scripts, String scriptName) {
          for (Script script : scripts) {
              if (script.getName().equalsIgnoreCase(scriptName)) {
                  return true;
              }
          }
          return false;
      }
  
      void deactivateEscalationService(String scriptName) {
          EscalationProvider snapshot = this.runningServices.get(scriptName);
          if(snapshot == null)
              return;
          snapshot.cancel();
          this.runningServices.remove(scriptName);
      }
  }
  