Added listener and event structure to ProjectMachineContexts
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / nature / MachineContext.java
1 package net.mograsim.plugin.nature;
2
3 import java.io.IOException;
4 import java.util.HashSet;
5 import java.util.Objects;
6 import java.util.Optional;
7 import java.util.Set;
8
9 import org.eclipse.core.resources.IProject;
10 import org.eclipse.jface.util.PropertyChangeEvent;
11 import org.eclipse.ui.preferences.ScopedPreferenceStore;
12
13 import net.mograsim.machine.Machine;
14 import net.mograsim.machine.MachineDefinition;
15 import net.mograsim.machine.MachineRegistry;
16 import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType;
17
18 public class MachineContext
19 {
20         IProject owner;
21         ScopedPreferenceStore prefs;
22         Optional<String> machineId;
23         Optional<MachineDefinition> machineDefinition;
24         Optional<Machine> activeMachine;
25
26         private final Set<ActiveMachineListener> observers = new HashSet<>();
27
28         public MachineContext(IProject owner)
29         {
30                 this.owner = Objects.requireNonNull(owner);
31                 prefs = ProjectMachineContext.getProjectPrefs(owner);
32                 prefs.addPropertyChangeListener(this::preferenceListener);
33                 machineId = ProjectMachineContext.getMachineIdFrom(prefs);
34                 updateDefinition();
35         }
36
37         public final IProject getProject()
38         {
39                 return owner;
40         }
41
42         public final ScopedPreferenceStore getPreferences()
43         {
44                 return prefs;
45         }
46
47         /**
48          * Returns true if the project configuration is valid in the current environment
49          */
50         public final boolean isCurrentyValid()
51         {
52                 return machineDefinition.isPresent();
53         }
54
55         /**
56          * Returns true if the persisted project configuration itself is intact
57          */
58         public final boolean isIntact()
59         {
60                 return machineId.isPresent();
61         }
62
63         /**
64          * Returns true if a machine is instantiated and (possibly) running
65          */
66         public final boolean isActive()
67         {
68                 return activeMachine.isPresent();
69         }
70
71         /**
72          * Sets the projects machineId. Will likely break things, if the {@link MachineContext} {@link #isActive()}.
73          */
74         public final boolean setMachineId(String machineId)
75         {
76                 prefs.setValue(ProjectMachineContext.MACHINE_PROPERTY, machineId);
77                 try
78                 {
79                         prefs.save();
80                 }
81                 catch (IOException e)
82                 {
83                         e.printStackTrace();
84                         return false;
85                 }
86                 return true;
87         }
88
89         /**
90          * Sets the active machine in the {@link MachineContext}'s project scope.
91          */
92         public final void setActiveMachine(Machine machine)
93         {
94                 activeMachine = Optional.ofNullable(machine);
95                 notifyObservers();
96         }
97
98         public final Optional<String> getMachineId()
99         {
100                 return machineId;
101         }
102
103         public final Optional<MachineDefinition> getMachineDefinition()
104         {
105                 return machineDefinition;
106         }
107
108         public final Optional<Machine> getActiveMachine()
109         {
110                 return activeMachine;
111         }
112
113         final void updateDefinition()
114         {
115                 machineDefinition = machineId.map(MachineRegistry::getMachine);
116                 machineDefinition.ifPresent(md -> setActiveMachine(md.createNew()));
117                 ProjectMachineContext.notifyListeners(new ProjectContextEvent(this, ProjectContextEventType.MACHINE_DEFINITION_CHANGE));
118         }
119
120         private void preferenceListener(PropertyChangeEvent changeEvent)
121         {
122                 if (changeEvent.getProperty().equals(ProjectMachineContext.MACHINE_PROPERTY))
123                 {
124                         machineId = Optional.ofNullable((String) changeEvent.getNewValue());
125                         updateDefinition();
126                 }
127         }
128
129         public void registerObserver(ActiveMachineListener ob)
130         {
131                 observers.add(ob);
132                 ob.setMachine(activeMachine);
133         }
134
135         public void deregisterObserver(ActiveMachineListener ob)
136         {
137                 observers.remove(ob);
138         }
139
140         private void notifyObservers()
141         {
142                 observers.forEach(ob -> ob.setMachine(activeMachine));
143         }
144
145         @FunctionalInterface
146         public static interface ActiveMachineListener
147         {
148                 void setMachine(Optional<Machine> machine);
149         }
150 }