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