The final restructured version for automatic build using maven tycho
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / model / LogicModel.java
diff --git a/plugins/net.mograsim.logic.model/src/net/mograsim/logic/model/model/LogicModel.java b/plugins/net.mograsim.logic.model/src/net/mograsim/logic/model/model/LogicModel.java
new file mode 100644 (file)
index 0000000..17d0a44
--- /dev/null
@@ -0,0 +1,196 @@
+package net.mograsim.logic.model.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import net.mograsim.logic.model.model.components.ModelComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.model.wires.ModelWire;
+
+public class LogicModel
+{
+       private final Map<String, ModelComponent> components;
+       private final Map<String, Runnable> componentDestroyFunctions;
+       private final Map<String, ModelComponent> componentsUnmodifiable;
+       private final Map<String, ModelWire> wires;
+       private final Map<String, Runnable> wireDestroyFunctions;
+       private final Map<String, ModelWire> wiresUnmodifiable;
+
+       private final List<Consumer<? super ModelComponent>> componentAddedListeners;
+       private final List<Consumer<? super ModelComponent>> componentRemovedListeners;
+       private final List<Consumer<? super ModelWire>> wireAddedListeners;
+       private final List<Consumer<? super ModelWire>> wireRemovedListeners;
+       private final List<Consumer<? super Runnable>> redrawHandlerChangedListeners;
+
+       private Runnable redrawHandler;
+
+       protected LogicModel()
+       {
+               components = new HashMap<>();
+               componentDestroyFunctions = new HashMap<>();
+               componentsUnmodifiable = Collections.unmodifiableMap(components);
+               wires = new HashMap<>();
+               wireDestroyFunctions = new HashMap<>();
+               wiresUnmodifiable = Collections.unmodifiableMap(wires);
+
+               componentAddedListeners = new ArrayList<>();
+               componentRemovedListeners = new ArrayList<>();
+               wireAddedListeners = new ArrayList<>();
+               wireRemovedListeners = new ArrayList<>();
+               redrawHandlerChangedListeners = new ArrayList<>();
+       }
+
+       /**
+        * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
+        * code as it is automatically called in {@link ModelComponent}'s constructor.
+        * 
+        * @author Daniel Kirschten
+        */
+       protected void componentCreated(ModelComponent component, Runnable destroyed)
+       {
+               if (components.containsKey(component.getName()))
+                       throw new IllegalStateException("Don't add the same component twice!");
+               components.put(component.getName(), component);
+               componentDestroyFunctions.put(component.getName(), destroyed);
+               callComponentAddedListeners(component);
+               requestRedraw();
+       }
+
+       /**
+        * Destroyes the given component, removes it from the list of components and calls all componentRemovedListeners.
+        * 
+        * @author Daniel Kirschten
+        */
+       protected void destroyComponent(ModelComponent component)
+       {
+               componentDestroyFunctions.get(component.getName()).run();
+               if (!components.containsKey(component.getName()))
+                       throw new IllegalStateException("Don't remove the same component twice!");
+               components.remove(component.getName());
+               callComponentRemovedListeners(component);
+               requestRedraw();
+       }
+
+       /**
+        * Adds the given wire to the list of wires and calls all wireAddedListeners. Don't call this method from application code as it is
+        * automatically called in {@link ModelWire}'s constructor.
+        * 
+        * @author Daniel Kirschten
+        */
+       protected void wireCreated(ModelWire wire, Runnable destroyed)
+       {
+               if (wires.containsKey(wire.name))
+                       throw new IllegalStateException("Don't add the same wire twice!");
+               wires.put(wire.name, wire);
+               wireDestroyFunctions.put(wire.name, destroyed);
+               callWireAddedListeners(wire);
+               requestRedraw();
+       }
+
+       /**
+        * Destroys the given wire, removes it from the list of wires and calls all wireRemovedListeners.
+        * 
+        * @author Daniel Kirschten
+        */
+       protected void destroyWire(ModelWire wire)
+       {
+               wireDestroyFunctions.get(wire.name).run();
+               if (!wires.containsKey(wire.name))
+                       throw new IllegalStateException("Don't remove the same wire twice!");
+               wires.remove(wire.name);
+               callWireRemovedListeners(wire);
+               requestRedraw();
+       }
+
+       public Map<String, ModelComponent> getComponentsByName()
+       {
+               return componentsUnmodifiable;
+       }
+
+       public Map<String, ModelWire> getWiresByName()
+       {
+               return wiresUnmodifiable;
+       }
+
+       public ModelComponent getComponentByName(String name)
+       {
+               return components.get(name);
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T extends ModelComponent> T getComponentByName(String name, Class<T> expectedComponentClass)
+       {
+               ModelComponent comp = components.get(name);
+               Objects.requireNonNull(comp, "Invaild path, component " + name + " not found");
+               if (expectedComponentClass.isInstance(comp))
+                       return (T) comp;
+               throw new IllegalArgumentException("The component " + name + " is not an instance of " + expectedComponentClass);
+       }
+
+       public ModelWire getWireByName(String name)
+       {
+               return wires.get(name);
+       }
+
+       public <T extends ModelComponent> T getComponentBySubmodelPath(String path, Class<T> modelClass)
+       {
+               int firstDot = path.indexOf('.');
+               if (firstDot == -1)
+                       return getComponentByName(path, modelClass);
+               String first = path.substring(0, firstDot);
+               String rest = path.substring(firstDot + 1);
+               return getComponentByName(first, SubmodelComponent.class).submodel.getComponentBySubmodelPath(rest, modelClass);
+       }
+
+       public ModelWire getWireBySubmodelPath(String path)
+       {
+               int firstDot = path.indexOf('.');
+               if (firstDot == -1)
+                       return getWireByName(path);
+               String first = path.substring(0, firstDot);
+               String rest = path.substring(firstDot + 1);
+               return getComponentByName(first, SubmodelComponent.class).submodel.getWireBySubmodelPath(rest);
+       }
+
+       // @formatter:off
+       public void addComponentAddedListener         (Consumer<? super ModelComponent> listener) {componentAddedListeners      .add   (listener);}
+       public void addComponentRemovedListener       (Consumer<? super ModelComponent> listener) {componentRemovedListeners    .add   (listener);}
+       public void addWireAddedListener              (Consumer<? super ModelWire     > listener) {wireAddedListeners           .add   (listener);}
+       public void addWireRemovedListener            (Consumer<? super ModelWire     > listener) {wireRemovedListeners         .add   (listener);}
+       public void addRedrawHandlerChangedListener   (Consumer<? super Runnable      > listener) {redrawHandlerChangedListeners.add   (listener);}
+
+       public void removeComponentAddedListener      (Consumer<? super ModelComponent> listener) {componentAddedListeners      .remove(listener);}
+       public void removeComponentRemovedListener    (Consumer<? super ModelComponent> listener) {componentRemovedListeners    .remove(listener);}
+       public void removeWireAddedListener           (Consumer<? super ModelWire     > listener) {wireAddedListeners           .remove(listener);}
+       public void removeWireRemovedListener         (Consumer<? super ModelWire     > listener) {wireRemovedListeners         .remove(listener);}
+       public void removeRedrawHandlerChangedListener(Consumer<? super Runnable      > listener) {redrawHandlerChangedListeners.remove(listener);}
+
+       private void callComponentAddedListeners     (ModelComponent c) {componentAddedListeners      .forEach(l -> l.accept(c));}
+       private void callComponentRemovedListeners   (ModelComponent c) {componentRemovedListeners    .forEach(l -> l.accept(c));}
+       private void callWireAddedListeners          (ModelWire      w) {wireAddedListeners           .forEach(l -> l.accept(w));}
+       private void callWireRemovedListeners        (ModelWire      w) {wireRemovedListeners         .forEach(l -> l.accept(w));}
+       private void callRedrawHandlerChangedListener(Runnable       r) {redrawHandlerChangedListeners.forEach(l -> l.accept(r));}
+       // @formatter:on
+
+       public void setRedrawHandler(Runnable handler)
+       {
+               this.redrawHandler = handler;
+               callRedrawHandlerChangedListener(handler);
+       }
+
+       public Runnable getRedrawHandler()
+       {
+               return redrawHandler;
+       }
+
+       public void requestRedraw()
+       {
+               if (redrawHandler != null)
+                       redrawHandler.run();
+       }
+}
\ No newline at end of file