1 package org.simantics.simulation.sequences.action;
\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
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
12 public abstract class AbstractActionContext implements ActionContext {
\r
13 public static final double TIME_TOLERANCE = 1e-6;
\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
21 public List<Exception> exceptions;
\r
23 private static class Task implements Comparable<Task> {
\r
25 final Function1<Tuple0, Object> continuation;
\r
27 public Task(double time, Function1<Tuple0, Object> continuation) {
\r
29 this.continuation = continuation;
\r
33 public int compareTo(Task o) {
\r
34 return Double.compare(time, o.time);
\r
39 public double time() {
\r
44 public void scheduleNow(Function1<Tuple0, Object> continuation) {
\r
45 scheduledNow.add(continuation);
\r
49 public void scheduleNextStep(Function1<Tuple0, Object> continuation) {
\r
50 scheduledNextStep.add(continuation);
\r
54 public void scheduleAt(double time, Function1<Tuple0, Object> continuation) {
\r
55 if(time <= currentTime)
\r
56 scheduleNow(continuation);
\r
58 scheduledAt.add(new Task(time, continuation));
\r
62 public void stop() {
\r
66 public boolean isStopped() {
\r
67 synchronized (this) {
\r
68 return stopped || (scheduledNextStep.isEmpty() && scheduledAt.isEmpty());
\r
72 public double handleStep(double currentTime) {
\r
73 synchronized (this) {
\r
74 this.currentTime = currentTime;
\r
76 ArrayList<Function1<Tuple0, Object>> temp = scheduledNow;
\r
77 scheduledNow = scheduledNextStep;
\r
78 scheduledNextStep = temp;
\r
79 Collections.reverse(scheduledNow);
\r
82 SCLContext context = SCLContext.getCurrent();
\r
83 Object oldActionContext = context.put("sequenceAction", this);
\r
85 Task firstTask = scheduledAt.peek();
\r
87 while(!scheduledNow.isEmpty()) {
\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
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
103 firstTask.continuation.apply(Tuple0.INSTANCE);
\r
104 synchronized (this) {
\r
105 scheduledAt.remove();
\r
107 firstTask = scheduledAt.peek();
\r
111 context.put("sequenceAction", oldActionContext);
\r