]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 package org.simantics.simulation.sequences.action;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.Collections;\r
5 import java.util.List;\r
6 import java.util.PriorityQueue;\r
7 \r
8 import org.simantics.scl.runtime.SCLContext;\r
9 import org.simantics.scl.runtime.function.Function1;\r
10 import org.simantics.scl.runtime.tuple.Tuple0;\r
11 \r
12 public abstract class AbstractActionContext implements ActionContext {\r
13     public static final double TIME_TOLERANCE = 1e-6;\r
14     \r
15     double currentTime;\r
16     volatile boolean stopped;\r
17     ArrayList<Function1<Tuple0, Object>> scheduledNow = new ArrayList<Function1<Tuple0, Object>>();\r
18     ArrayList<Function1<Tuple0, Object>> scheduledNextStep = new ArrayList<Function1<Tuple0, Object>>();\r
19     PriorityQueue<Task> scheduledAt = new PriorityQueue<Task>();\r
20 \r
21         public List<Exception> exceptions; \r
22     \r
23     private static class Task implements Comparable<Task> {\r
24         final double time;\r
25         final Function1<Tuple0, Object> continuation;\r
26         \r
27         public Task(double time, Function1<Tuple0, Object> continuation) {\r
28             this.time = time;\r
29             this.continuation = continuation;\r
30         }\r
31 \r
32         @Override\r
33         public int compareTo(Task o) {\r
34             return Double.compare(time, o.time);\r
35         }\r
36     }\r
37     \r
38     @Override\r
39     public double time() {\r
40         return currentTime;\r
41     }\r
42     \r
43     @Override\r
44     public void scheduleNow(Function1<Tuple0, Object> continuation) {\r
45         scheduledNow.add(continuation);\r
46     }\r
47     \r
48     @Override\r
49     public void scheduleNextStep(Function1<Tuple0, Object> continuation) {\r
50         scheduledNextStep.add(continuation);\r
51     }\r
52     \r
53     @Override\r
54     public void scheduleAt(double time, Function1<Tuple0, Object> continuation) {\r
55         if(time <= currentTime)\r
56             scheduleNow(continuation);\r
57         else\r
58             scheduledAt.add(new Task(time, continuation));\r
59     }\r
60     \r
61     @Override\r
62     public void stop() {\r
63         stopped = true;\r
64     }\r
65     \r
66     public boolean isStopped() {\r
67         synchronized (this) {\r
68                 return stopped || (scheduledNextStep.isEmpty() && scheduledAt.isEmpty());\r
69         }\r
70     }\r
71     \r
72     public double handleStep(double currentTime) {\r
73         synchronized (this) {\r
74                 this.currentTime = currentTime;\r
75                 {\r
76                     ArrayList<Function1<Tuple0, Object>> temp = scheduledNow;\r
77                     scheduledNow = scheduledNextStep;\r
78                     scheduledNextStep = temp;\r
79                     Collections.reverse(scheduledNow);\r
80                 }\r
81                         \r
82                 SCLContext context = SCLContext.getCurrent();\r
83                 Object oldActionContext = context.put("sequenceAction", this);\r
84                 try {\r
85                     Task firstTask = scheduledAt.peek();\r
86                     while(true) {\r
87                         while(!scheduledNow.isEmpty()) {\r
88                                 try {\r
89                                         Function1<Tuple0, Object> currentContinuation = scheduledNow.remove(scheduledNow.size()-1);\r
90                                     currentContinuation.apply(Tuple0.INSTANCE);\r
91                                         currentContinuation = null;\r
92                                 } catch (Exception e) {\r
93                                         if (this.exceptions == null)\r
94                                                 this.exceptions = new ArrayList<Exception>();\r
95                                         this.exceptions.add(new RuntimeException("Action failure at " + currentTime + ": " + e.getMessage(), e));\r
96                                 }\r
97                         }\r
98                         if(firstTask == null)\r
99                             return Double.POSITIVE_INFINITY;\r
100                         else if(firstTask.time > currentTime+TIME_TOLERANCE)\r
101                             return firstTask.time;\r
102                         else {\r
103                             firstTask.continuation.apply(Tuple0.INSTANCE);\r
104                                 synchronized (this) {\r
105                                         scheduledAt.remove();\r
106                                 }\r
107                             firstTask = scheduledAt.peek();\r
108                         }\r
109                     }\r
110                 } finally {\r
111                     context.put("sequenceAction", oldActionContext);\r
112                 }\r
113         }\r
114     }\r
115 }\r