fadfbe94da54e526ec320989882feac8df54e47f
[Mograsim.git] / LogicUI / src / net / mograsim / logic / ui / LogicExecuter.java
1 package net.mograsim.logic.ui;
2
3 import java.util.concurrent.atomic.AtomicBoolean;
4 import java.util.concurrent.atomic.AtomicLong;
5
6 import net.mograsim.logic.core.timeline.Timeline;
7
8 //TODO maybe move to logic core?
9 public class LogicExecuter
10 {
11         // TODO replace with LogicModel when it exists
12         private final Timeline timeline;
13
14         private final AtomicBoolean shouldBeRunningLive;
15         private final AtomicBoolean isRunningLive;
16         private final AtomicLong nextExecSimulTime;
17         private final Thread simulationThread;
18
19         public LogicExecuter(Timeline timeline)
20         {
21                 this.timeline = timeline;
22
23                 timeline.setTimeFunction(System::currentTimeMillis);
24                 shouldBeRunningLive = new AtomicBoolean();
25                 isRunningLive = new AtomicBoolean();
26                 nextExecSimulTime = new AtomicLong();
27                 simulationThread = new Thread(() ->
28                 {
29                         isRunningLive.set(true);
30                         synchronized (isRunningLive)
31                         {
32                                 isRunningLive.notify();
33                         }
34                         while (shouldBeRunningLive.get())
35                         {
36                                 // always execute to keep timeline from "hanging behind" for too long
37                                 long current = System.currentTimeMillis();
38                                 timeline.executeUntil(timeline.laterThan(current), current + 10);
39                                 long sleepTime;
40                                 if (timeline.hasNext())
41                                         sleepTime = timeline.nextEventTime() - current;
42                                 else
43                                         sleepTime = 10000;
44                                 try
45                                 {
46                                         nextExecSimulTime.set(current + sleepTime);
47                                         if (sleepTime > 0)
48                                                 Thread.sleep(sleepTime);
49                                 }
50                                 catch (@SuppressWarnings("unused") InterruptedException e)
51                                 {// do nothing; it is normal execution flow to be interrupted
52                                 }
53                         }
54                         isRunningLive.set(false);
55                         synchronized (isRunningLive)
56                         {
57                                 isRunningLive.notify();
58                         }
59                 });
60                 timeline.addEventAddedListener(event ->
61                 {
62                         if (isRunningLive.get())
63                                 if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
64                                         simulationThread.interrupt();
65                 });
66         }
67
68         public void executeNextStep()
69         {
70                 timeline.executeNext();
71         }
72
73         public synchronized void startLiveExecution()
74         {
75                 if (shouldBeRunningLive.get())
76                         return;
77                 shouldBeRunningLive.set(true);
78                 simulationThread.start();
79                 waitForIsRunning(true);
80         }
81
82         public synchronized void stopLiveExecution()
83         {
84                 if (!shouldBeRunningLive.get())
85                         return;
86                 shouldBeRunningLive.set(false);
87                 simulationThread.interrupt();
88                 waitForIsRunning(false);
89         }
90
91         private void waitForIsRunning(boolean expectedState)
92         {
93                 while (isRunningLive.get() ^ expectedState)
94                         try
95                         {
96                                 synchronized (isRunningLive)
97                                 {
98                                         isRunningLive.wait();
99                                 }
100                         }
101                         catch (@SuppressWarnings("unused") InterruptedException e)
102                         {// no need to do anything
103                         }
104         }
105 }