]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.simulation.sequences / src / org / simantics / simulation / sequences / action / AbstractActionContext.java
diff --git a/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java b/bundles/org.simantics.simulation.sequences/src/org/simantics/simulation/sequences/action/AbstractActionContext.java
new file mode 100644 (file)
index 0000000..4cba91d
--- /dev/null
@@ -0,0 +1,115 @@
+package org.simantics.simulation.sequences.action;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.PriorityQueue;\r
+\r
+import org.simantics.scl.runtime.SCLContext;\r
+import org.simantics.scl.runtime.function.Function1;\r
+import org.simantics.scl.runtime.tuple.Tuple0;\r
+\r
+public abstract class AbstractActionContext implements ActionContext {\r
+    public static final double TIME_TOLERANCE = 1e-6;\r
+    \r
+    double currentTime;\r
+    volatile boolean stopped;\r
+    ArrayList<Function1<Tuple0, Object>> scheduledNow = new ArrayList<Function1<Tuple0, Object>>();\r
+    ArrayList<Function1<Tuple0, Object>> scheduledNextStep = new ArrayList<Function1<Tuple0, Object>>();\r
+    PriorityQueue<Task> scheduledAt = new PriorityQueue<Task>();\r
+\r
+       public List<Exception> exceptions; \r
+    \r
+    private static class Task implements Comparable<Task> {\r
+        final double time;\r
+        final Function1<Tuple0, Object> continuation;\r
+        \r
+        public Task(double time, Function1<Tuple0, Object> continuation) {\r
+            this.time = time;\r
+            this.continuation = continuation;\r
+        }\r
+\r
+        @Override\r
+        public int compareTo(Task o) {\r
+            return Double.compare(time, o.time);\r
+        }\r
+    }\r
+    \r
+    @Override\r
+    public double time() {\r
+        return currentTime;\r
+    }\r
+    \r
+    @Override\r
+    public void scheduleNow(Function1<Tuple0, Object> continuation) {\r
+        scheduledNow.add(continuation);\r
+    }\r
+    \r
+    @Override\r
+    public void scheduleNextStep(Function1<Tuple0, Object> continuation) {\r
+        scheduledNextStep.add(continuation);\r
+    }\r
+    \r
+    @Override\r
+    public void scheduleAt(double time, Function1<Tuple0, Object> continuation) {\r
+        if(time <= currentTime)\r
+            scheduleNow(continuation);\r
+        else\r
+            scheduledAt.add(new Task(time, continuation));\r
+    }\r
+    \r
+    @Override\r
+    public void stop() {\r
+        stopped = true;\r
+    }\r
+    \r
+    public boolean isStopped() {\r
+       synchronized (this) {\r
+               return stopped || (scheduledNextStep.isEmpty() && scheduledAt.isEmpty());\r
+       }\r
+    }\r
+    \r
+    public double handleStep(double currentTime) {\r
+       synchronized (this) {\r
+               this.currentTime = currentTime;\r
+               {\r
+                   ArrayList<Function1<Tuple0, Object>> temp = scheduledNow;\r
+                   scheduledNow = scheduledNextStep;\r
+                   scheduledNextStep = temp;\r
+                   Collections.reverse(scheduledNow);\r
+               }\r
+                       \r
+               SCLContext context = SCLContext.getCurrent();\r
+               Object oldActionContext = context.put("sequenceAction", this);\r
+               try {\r
+                   Task firstTask = scheduledAt.peek();\r
+                   while(true) {\r
+                       while(!scheduledNow.isEmpty()) {\r
+                               try {\r
+                                       Function1<Tuple0, Object> currentContinuation = scheduledNow.remove(scheduledNow.size()-1);\r
+                                   currentContinuation.apply(Tuple0.INSTANCE);\r
+                                       currentContinuation = null;\r
+                               } catch (Exception e) {\r
+                                       if (this.exceptions == null)\r
+                                               this.exceptions = new ArrayList<Exception>();\r
+                                       this.exceptions.add(new RuntimeException("Action failure at " + currentTime + ": " + e.getMessage(), e));\r
+                               }\r
+                       }\r
+                       if(firstTask == null)\r
+                           return Double.POSITIVE_INFINITY;\r
+                       else if(firstTask.time > currentTime+TIME_TOLERANCE)\r
+                           return firstTask.time;\r
+                       else {\r
+                           firstTask.continuation.apply(Tuple0.INSTANCE);\r
+                               synchronized (this) {\r
+                                       scheduledAt.remove();\r
+                               }\r
+                           firstTask = scheduledAt.peek();\r
+                       }\r
+                   }\r
+               } finally {\r
+                   context.put("sequenceAction", oldActionContext);\r
+               }\r
+       }\r
+    }\r
+}\r