From 6fb323d435defcf57b23487375dd583cfa4702a0 Mon Sep 17 00:00:00 2001
From: dev-manuel <manuel_krofficial@online.de>
Date: Sun, 24 Jan 2021 23:38:47 +0100
Subject: [PATCH] Replaced ControllerItem and ControlledItem w/ ECA

---
 eraser-base/src/main/jastadd/Item.jrag        | 61 ++++++++++++-------
 eraser-base/src/main/jastadd/Printing.jrag    |  4 +-
 eraser-base/src/main/jastadd/Rules.jrag       |  3 +-
 eraser-base/src/main/jastadd/Rules.relast     |  1 +
 eraser-base/src/main/jastadd/eraser.flex      |  1 -
 eraser-base/src/main/jastadd/eraser.parser    |  4 +-
 eraser-base/src/main/jastadd/shem.relast      |  1 -
 .../inf/st/eraser/spark/Application.java      |  1 -
 .../inf/st/eraser/spark/SimpleItem.java       |  1 -
 9 files changed, 44 insertions(+), 33 deletions(-)

diff --git a/eraser-base/src/main/jastadd/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag
index 87d45fa2..e6378feb 100644
--- a/eraser-base/src/main/jastadd/Item.jrag
+++ b/eraser-base/src/main/jastadd/Item.jrag
@@ -290,7 +290,6 @@ aspect ItemHandling {
    *   <li>Send the new state via MQTT</li>
    *   <li>Send the new state to Influx DB</li>
    *   <li>Notify the attached {@link ItemObserver}, if any</li>
-   *   <li>Update state of controlled items</li>
    * </ul>
    * @param shouldSendState whether to send the new state (currently affects MQTT and Influx)
    */
@@ -306,9 +305,6 @@ aspect ItemHandling {
     if (hasItemObserver()) {
       getItemObserver().apply();
     }
-    for (Item controlled : getControllingList()) {
-      doUpdateFor(controlled);
-    }
   }
 
   //--- sendState ---
@@ -388,22 +384,49 @@ aspect ItemHandling {
   syn DateTimeItem Item.asDateTimeItem() = (DateTimeItem) this;
   syn DateTimeItem DateTimeItem.asDateTimeItem() = this;
 
-  //--- doUpdateFor ---
-  protected abstract void Item.doUpdateFor(Item controlling);
-  protected void ItemWithBooleanState.doUpdateFor(Item controlling) {
-    controlling.setStateFromBoolean(this.getState());
+
+  //--- State Copy ---
+  public void Item.addControlling(Item controlledItem) { 
+    getRoot().addRule(createControllerRule(this,controlledItem));
+  }
+
+  public void Item.addControlledBy(Item controllerItem) { 
+    getRoot().addRule(createControllerRule(controllerItem,this));
+  }
+
+  
+  private Rule Item.createControllerRule(Item controllerItem, Item controlledItem) {
+    Rule rule = new Rule();
+
+    ItemStateChangeCondition condition = new ItemStateChangeCondition();
+    condition.setItem(controllerItem);
+    rule.addCondition(condition);
+
+    SetStateFromTriggeringItemAction action = new SetStateFromTriggeringItemAction();
+    action.setAffectedItem(controlledItem);
+    rule.addAction(action);
+    
+    return rule;
+    
+  }
+  
+
+  //--- copyStateTo ---
+  protected abstract void Item.copyStateTo(Item stateReceiver);
+  protected void ItemWithBooleanState.copyStateTo(Item stateReceiver) {
+    stateReceiver.setStateFromBoolean(this.getState());
   }
-  protected void ItemWithStringState.doUpdateFor(Item controlling) {
-    controlling.setStateFromString(this.getState());
+  protected void ItemWithStringState.copyStateTo(Item stateReceiver) {
+    stateReceiver.setStateFromString(this.getState());
   }
-  protected void ItemWithDoubleState.doUpdateFor(Item controlling) {
-    controlling.setStateFromDouble(this.getState());
+  protected void ItemWithDoubleState.copyStateTo(Item stateReceiver) {
+    stateReceiver.setStateFromDouble(this.getState());
   }
-  protected void ColorItem.doUpdateFor(Item controlling) {
-    controlling.setStateFromColor(this.getState());
+  protected void ColorItem.copyStateTo(Item stateReceiver) {
+    stateReceiver.setStateFromColor(this.getState());
   }
-  protected void DateTimeItem.doUpdateFor(Item controlling) {
-    controlling.setStateFromInstant(this.getState());
+  protected void DateTimeItem.copyStateTo(Item stateReceiver) {
+    stateReceiver.setStateFromInstant(this.getState());
   }
 
   private void ColorItem.setBrightness(int value) {
@@ -415,18 +438,12 @@ aspect ItemHandling {
   public void ItemUpdateColor.apply() {
     getItem().setStateFromColor(getNewHSB());
     getItem().freeze();
-    for (Item controller : getItem().getControlledByList()) {
-      controller.setStateFromColor(getNewHSB());
-    }
     getItem().unfreeze();
   }
   //--- ItemUpdate.apply ---
   public void ItemUpdateDouble.apply() {
     getItem().setStateFromDouble(getNewValue());
     getItem().freeze();
-    for (Item controller : getItem().getControlledByList()) {
-      controller.setStateFromDouble(getNewValue());
-    }
     getItem().unfreeze();
   }
 
diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag
index fec6c4ab..0b454039 100644
--- a/eraser-base/src/main/jastadd/Printing.jrag
+++ b/eraser-base/src/main/jastadd/Printing.jrag
@@ -49,7 +49,7 @@ aspect Printing {
         .build();
   }
 
-//ITEM_TYPE Item: id="" label="" state="" category="" topic="" controls=["ITEM_ID", "ITEM_ID"];
+//ITEM_TYPE Item: id="" label="" state="" category="" topic="";
   syn String Item.prettyPrint() {
     return new MemberPrinter(prettyPrintType())
         .addRequired("id", getID())
@@ -57,7 +57,6 @@ aspect Printing {
         .addRequired("state", getStateAsString())
         .addOptional("category", hasCategory(), () -> getCategory().getName())
         .addOptional("topic", hasTopic(), () -> getTopic().getTopicString())
-        .addIds("controls", getControllingList())
         .addNodes("metaData", getNumMetaData(), getMetaDataList(),
                   md -> "\"" + md.getKey() + "\":\"" + md.getValue() + "\"",
                   MemberPrinter.ListBracketType.CURLY)
@@ -86,7 +85,6 @@ aspect Printing {
         .addNonDefault("label", getLabel())
         .addOptional("category", hasCategory(), () -> getCategory().getName())
         .addOptional("topic", hasTopic(), () -> getTopic().getTopicString())
-        .addIds("controls", getControllingList())
         .addNodes("metaData", getNumMetaData(), getMetaDataList(),
                   md -> "\"" + md.getKey() + "\":\"" + md.getValue() + "\"",
                   MemberPrinter.ListBracketType.CURLY)
diff --git a/eraser-base/src/main/jastadd/Rules.jrag b/eraser-base/src/main/jastadd/Rules.jrag
index e1e0db7c..464b3d3d 100644
--- a/eraser-base/src/main/jastadd/Rules.jrag
+++ b/eraser-base/src/main/jastadd/Rules.jrag
@@ -79,6 +79,7 @@ aspect Rules {
   syn boolean Condition.holdsFor(Item item);
   eq ItemStateCheckCondition.holdsFor(Item item) = getItemStateCheck().holdsFor(item);
   eq ExpressionCondition.holdsFor(Item item) = getLogicalExpression().eval();
+  eq ItemStateChangeCondition.holdsFor(Item item) = getItem() == item;
 
   // --- Action.applyFor ---
   public abstract void Action.applyFor(Item item);
@@ -101,7 +102,7 @@ aspect Rules {
     getAffectedItem().setStateFromString(getNewStateProvider().get());
   }
   public void SetStateFromTriggeringItemAction.applyFor(Item item) {
-    item.doUpdateFor(getAffectedItem());
+    item.copyStateTo(getAffectedItem());
   }
   public void SetStateFromItemsAction.applyFor(Item item) {
     getAffectedItem().setStateFromString(getCombinator().apply(getSourceItems()));
diff --git a/eraser-base/src/main/jastadd/Rules.relast b/eraser-base/src/main/jastadd/Rules.relast
index 33858584..25a0fd2b 100644
--- a/eraser-base/src/main/jastadd/Rules.relast
+++ b/eraser-base/src/main/jastadd/Rules.relast
@@ -2,6 +2,7 @@
 Rule ::= Condition* Action* ;
 abstract Condition ;
 ItemStateCheckCondition : Condition ::= ItemStateCheck ;
+ItemStateChangeCondition : Condition ::= Item;
 ExpressionCondition : Condition ::= LogicalExpression ;
 abstract Action ;
 NoopAction : Action ;
diff --git a/eraser-base/src/main/jastadd/eraser.flex b/eraser-base/src/main/jastadd/eraser.flex
index bc9b3e8d..5f70414f 100644
--- a/eraser-base/src/main/jastadd/eraser.flex
+++ b/eraser-base/src/main/jastadd/eraser.flex
@@ -77,7 +77,6 @@ Comment = "//" [^\n\r]+
 "channels"     { return sym(Terminals.CHANNELS); }
 "channelTypes" { return sym(Terminals.CHANNEL_TYPES); }
 "context"      { return sym(Terminals.CONTEXT); }
-"controls"     { return sym(Terminals.CONTROLS); }
 "dbName"       { return sym(Terminals.DB_NAME); }
 "default"      { return sym(Terminals.DEFAULT); }
 "description"  { return sym(Terminals.DESCRIPTION); }
diff --git a/eraser-base/src/main/jastadd/eraser.parser b/eraser-base/src/main/jastadd/eraser.parser
index 5c275fa8..68967a56 100644
--- a/eraser-base/src/main/jastadd/eraser.parser
+++ b/eraser-base/src/main/jastadd/eraser.parser
@@ -125,15 +125,13 @@ Item item =
   |  ITEM COLON item_body.ib SEMICOLON                {: return eph.retype(new DefaultItem(), ib); :}
   ;
 
-// ITEM_TYPE Item: id="" label="" state="" category="" topic="" controls=["ITEM_ID"] metaData={"key":"value"} ;
+// ITEM_TYPE Item: id="" label="" state="" category="" topic="" metaData={"key":"value"} ;
 Item item_body =
      ID EQUALS TEXT.n item_body.i       {: return eph.setID(i, n); :}
   |  LABEL EQUALS TEXT.n item_body.i    {: i.setLabel(n); return i; :}
   |  STATE EQUALS TEXT.n item_body.i    {: i.setStateFromString(n); return i; :}
   |  TOPIC EQUALS TEXT.n item_body.i    {: return eph.setTopic(i, n); :}
   |  CATEGORY EQUALS TEXT.n item_body.i {: return eph.setCategory(i, n); :}
-  |  CONTROLS EQUALS string_list.controlling item_body.i
-    {: return eph.setControlling(i, controlling); :}
   |  META_DATA EQUALS string_map.md item_body.i
     {: return eph.setMetaData(i, md); :}
   |                                     {: return eph.createItem(); :}
diff --git a/eraser-base/src/main/jastadd/shem.relast b/eraser-base/src/main/jastadd/shem.relast
index 34ad05fe..ca1878ac 100644
--- a/eraser-base/src/main/jastadd/shem.relast
+++ b/eraser-base/src/main/jastadd/shem.relast
@@ -27,7 +27,6 @@ ParameterDefaultValue ::= <Value:String> ;
 
 abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* [ItemObserver] ;
 rel Item.Category? -> ItemCategory ;
-rel Item.Controlling* <-> Item.ControlledBy* ;
 
 abstract ItemWithBooleanState : Item ::= <_state:boolean> ;
 abstract ItemWithStringState : Item ::= <_state:String> ;
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java
index c646b0e5..d8a76db6 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java
@@ -243,7 +243,6 @@ public class Application {
         item.getTopic() != null ? item.getTopic().getTopicString() : null,
         item.isFrozen(),
         item.isSendState(),
-        item.getControllingList().stream().map(Item::getID).collect(Collectors.toList()),
         wrapMetaData(item.getMetaDataList()));
   }
 
diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleItem.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleItem.java
index 2eac6243..cd18057f 100644
--- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleItem.java
+++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleItem.java
@@ -17,6 +17,5 @@ public class SimpleItem {
   public final String topic;
   public final boolean frozen;
   public final boolean sendState;
-  public final List<String> controlling;
   public final Map<String, String> metaData;
 }
-- 
GitLab