source: tmcsimulator-scriptbuilder/trunk/src/scriptbuilder/structures/ScriptIncident.java @ 131

Revision 131, 11.4 KB checked in by bmcguffin, 9 years ago (diff)

DTD file for XML writing is now internal, so script.dtd file is no longer necessary. XML files are now readable on their own.

Line 
1package scriptbuilder.structures;
2
3import java.awt.Color;
4import java.io.BufferedWriter;
5import java.io.File;
6import java.io.FileWriter;
7import java.util.ArrayList;
8import java.util.TreeMap;
9import scriptbuilder.structures.events.I_ScriptEvent;
10
11/**
12 * A script incident. It has an ID number, a name, and a description. It may
13 * contain several script events. It also has a color in the GUI window, and is
14 * collapsible. Incidents may start as soon as the script begins to run, or they
15 * can be offset from the start of the script.
16 *
17 * @author Greg Eddington <geddingt@calpoly.edu>
18 * @author Bryan McGuffin
19 * @version 2017/06/29
20 */
21public class ScriptIncident implements I_XML_Writable
22{
23
24    /**
25     * The moments in time which have associated events.
26     */
27    public TreeMap<Integer, TimeSlice> slices;
28
29    /**
30     * GUI display color of this slice.
31     */
32    public Color color;
33
34    /**
35     * ID number for this incident.
36     */
37    public int number;
38
39    /**
40     * Name of the incident.
41     */
42    public String name;
43
44    /**
45     * Description of the incident.
46     */
47    public String description;
48
49    /**
50     * Length, in seconds, of the incident.
51     */
52    public int length = 0;
53
54    /**
55     * If true, incident appears minimized.
56     */
57    public boolean collapsed = false;
58
59    /**
60     * Number of seconds between start of simulation and start of this incident.
61     */
62    public int offset = 0;
63
64    /**
65     * Start position of the latest timeslice.
66     */
67    private int latestStart = 0;
68
69    /**
70     * Number of events in this incident.
71     */
72    public int eventCount = 0;
73
74    SimulationScript script;
75
76    /**
77     * Basic constructor.
78     *
79     * @param number The incident ID number
80     * @param name The name of the incident
81     * @param description The description of the incident
82     * @param script The script object holding this incident
83     */
84    public ScriptIncident(int number, String name, String description,
85            SimulationScript script)
86    {
87        color = Color.BLACK;
88        this.number = number;
89        this.name = name;
90        this.description = description;
91        this.script = script;
92        slices = new TreeMap<Integer, TimeSlice>();
93    }
94
95    /**
96     * Constructor with color parameter.
97     *
98     * @param color The color to use in the GUI for this event
99     * @param number The incident ID number
100     * @param name The name of the incident
101     * @param description The description of the incident
102     * @param script The script object holding this incident
103     */
104    public ScriptIncident(Color color, int number, String name,
105            String description, SimulationScript script)
106    {
107        this.color = color;
108        this.number = number;
109        this.name = name;
110        this.description = description;
111        this.script = script;
112        slices = new TreeMap<Integer, TimeSlice>();
113    }
114
115    /**
116     * Constructor with color and offset parameters.
117     *
118     * @param color The color to use in the GUI for this event
119     * @param number The incident ID number
120     * @param name The name of the incident
121     * @param description The description of the incident
122     * @param script The script object holding this incident
123     * @param offset Number of seconds after 00:00:00 that this incident begins
124     */
125    public ScriptIncident(Color color, int number, String name,
126            String description, SimulationScript script,
127            int offset)
128    {
129        this.color = color;
130        this.number = number;
131        this.name = name;
132        this.description = description;
133        this.script = script;
134        slices = new TreeMap<Integer, TimeSlice>();
135        this.setOffset(offset);
136    }
137
138    /**
139     * Set whether or not the incident is fully visible or in a compacted state.
140     *
141     * @param collapsed True if the event is compacted
142     */
143    public void setCollapsed(boolean collapsed)
144    {
145        this.collapsed = collapsed;
146        script.update();
147    }
148
149    /**
150     * Set the delay time between the start of the script and the start of this
151     * incident.
152     *
153     * @param offset Number of seconds after 00:00:00 that this incident begins
154     */
155    public void setOffset(int offset)
156    {
157        int old = this.offset;
158        this.offset = offset;
159        TreeMap<Integer, TimeSlice> newSlices = new TreeMap<Integer, TimeSlice>();
160
161        int latest = 0;
162
163        for (Integer k : slices.keySet())
164        {
165            newSlices.put(k + (offset - old), slices.get(k));
166            latest = k + (offset - old);
167        }
168
169        latestStart = latest;
170
171        for (TimeSlice ts : newSlices.values())
172        {
173            ts.shift(offset - old);
174        }
175
176        slices = newSlices;
177        updateLength();
178        script.update();
179    }
180
181    /**
182     * Add a new script event to this incident.
183     *
184     * @param ev The new event
185     * @param start Start time of this event, in seconds, from the beginning of
186     * the simulation
187     */
188    public void addNewEvent(I_ScriptEvent ev, int start)
189    {
190        /*
191        int leftoverSeconds = start % 60;
192       
193        //round start time to the nearest minute
194        if(leftoverSeconds != 0)
195        {
196            if(leftoverSeconds > 30)
197            {
198                start += (60 - leftoverSeconds);
199            }
200            else
201            {
202                start -= leftoverSeconds;
203            }
204        }
205        */
206       
207        //Check to see if there's already a timeslice here
208        TimeSlice t = slices.get(start);
209        //If not, make one; then, add the event to it
210        if (t == null)
211        {
212            t = new TimeSlice(start, this);
213            t.addEvent(ev);
214            slices.put(start, t);
215        }
216        else
217        {
218            t.addEvent(ev);
219        }
220        eventCount++;
221
222        //If this is the latest start time in the incident, update that number
223        if (start > latestStart)
224        {
225            latestStart = start;
226        }
227        //If this event is earlier than all previous events, or if there are
228        //no other events, the offset is equal to this event's start time
229        if (start < offset || eventCount == 1)
230        {
231            offset = start;
232            //System.out.println("Offset: " + offset);
233        }
234        updateLength();
235    }
236
237    /**
238     * Get an array of all valid timeSlices.
239     *
240     * @return List of timeSlices which are not null
241     */
242    public ArrayList<TimeSlice> getSlices()
243    {
244        ArrayList<TimeSlice> arr = new ArrayList<TimeSlice>();
245        for (int i = 0; i <= latestStart; i++)
246        {
247            TimeSlice ts = slices.get(i);
248            if (ts != null)
249            {
250                arr.add(ts);
251            }
252        }
253        return arr;
254    }
255
256    /**
257     * Write this incident, in proper XML form, to the file in question.
258     *
259     * @param f the destination savefile
260     */
261    public void saveIncidentToFile(File f)
262    {
263        try
264        {
265            f.createNewFile();
266
267            BufferedWriter bw = new BufferedWriter(new FileWriter(f));
268            bw.write(this.toXML());
269            bw.flush();
270            bw.close();
271
272        }
273        catch (Exception ex)
274        {
275            System.out.println("ERROR SAVING SCRIPT");
276            ex.printStackTrace();
277        }
278    }
279
280    @Override
281    public String toXML()
282    {
283        String output = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
284        output += XMLWriter.internalDTD();
285        output += XMLWriter.openTag(ELEMENT.TMC_SCRIPT.tag + " title=\"" + this.script.title + "\"");
286
287        for (TimeSlice slice : slices.values())
288        {
289            output += slice.toXML();
290        }
291        output += XMLWriter.closeTag(ELEMENT.TMC_SCRIPT.tag);
292        return output;
293    }
294
295    void insertCadData(long currentEventTime, CadData cad)
296    {
297        int time = (int) currentEventTime;
298
299        TimeSlice slice;
300
301        if (slices.get(time) == null)
302        {
303            slices.put(time, new TimeSlice(time, this));
304        }
305        slice = slices.get(time);
306        slice.cadData = cad;
307    }
308
309    /**
310     * Update the offset and apparent length of this incident. The offset is the
311     * start time of the earliest event in the incident. The length is the time
312     * that the latest, longest-lasting event ends, minus the offset.
313     */
314    public void updateLength()
315    {
316        int lengthSoFar = 0;
317        for (int i = 0; i <= latestStart; i++)
318        {
319            TimeSlice ts = slices.get(i);
320            if (ts != null)
321            {
322                int reach = ts.getTime() + ts.getEffectiveDuration() - offset;
323                if (reach > lengthSoFar)
324                {
325                    lengthSoFar = reach;
326                }
327            }
328        }
329        length = lengthSoFar;
330    }
331
332    /**
333     * An event which is fired if the focused slice changes.
334     */
335    public static class SliceChangedEvent
336    {
337
338        /**
339         * The slice which has received focus in this event.
340         */
341        public TimeSlice slice;
342
343        SliceChangedEvent(TimeSlice slice)
344        {
345            this.slice = slice;
346        }
347    }
348
349    /**
350     * Update and cause the system to focus on the given timeslice.
351     *
352     * @param i Index of the slice to focus on
353     */
354    public void setSliceActive(int i)
355    {
356        if (this.slices.get(i) != null)
357        {
358            script.broadcastEvent(new SliceChangedEvent(this.slices.get(i)));
359        }
360    }
361
362    /**
363     * An event which is fired if the focused incident changes.
364     */
365    public static class IncidentFocusedEvent
366    {
367
368        /**
369         * The incident which has received focus in this event.
370         */
371        public ScriptIncident incident;
372
373        IncidentFocusedEvent(ScriptIncident i)
374        {
375            incident = i;
376        }
377    }
378
379    /**
380     * Update and cause the system to focus on this incident.
381     */
382    public void setIncidentActive()
383    {
384        script.broadcastEvent(new IncidentFocusedEvent(this));
385    }
386
387    /**
388     * String representation of this incident.
389     *
390     * @return String of the form "[Incident number] - [Incident name]"
391     */
392    @Override
393    public String toString()
394    {
395        return this.number + " - " + this.name;
396    }
397
398    /**
399     * Remove the timeslice at the given position.
400     *
401     * @param seconds absolute start time of the timeslice to remove.
402     */
403    public void removeTimeSlice(int seconds)
404    {
405        //remove the timeslice
406        this.slices.remove(seconds);
407
408        //offset is equivalent to start time of earliest slice
409        if (seconds == offset)
410        {
411            if (slices.size() > 0)
412            {
413                offset = slices.firstKey();
414            }
415            else
416            {
417                offset = 0;
418            }
419        }
420        this.updateLength();
421        script.update();
422    }
423
424    /**
425     * Shifts the start time of a given event in this incident. The first event
426     * in the incident cannot be shifted.
427     *
428     * @param evt the event to be relocated
429     * @param oldTime the current start time of the event
430     * @param newTime the destination start time of the event
431     * @return true if the event is shifted over properly
432     * @pre the event in question exists
433     * @pre oldTime != newTime
434     */
435    public boolean changeEventStart(I_ScriptEvent evt, int oldTime, int newTime)
436    {
437        if (!(oldTime == 0 && newTime > oldTime))
438        {
439            this.slices.get(oldTime).events.remove(evt);
440            this.addNewEvent(evt, newTime);
441            return true;
442        }
443        return false;
444    }
445}
Note: See TracBrowser for help on using the repository browser.