package scriptbuilder.structures; import java.awt.Color; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.util.ArrayList; import java.util.TreeMap; import scriptbuilder.structures.events.I_ScriptEvent; /** * A script incident. It has an ID number, a name, and a description. It may * contain several script events. It also has a color in the GUI window, and is * collapsible. Incidents may start as soon as the script begins to run, or they * can be offset from the start of the script. * * @author Greg Eddington * @author Bryan McGuffin * @version 2017/06/29 */ public class ScriptIncident implements I_XML_Writable { /** * The moments in time which have associated events. */ public TreeMap slices; /** * GUI display color of this slice. */ public Color color; /** * ID number for this incident. */ public int number; /** * Name of the incident. */ public String name; /** * Description of the incident. */ public String description; /** * Length, in seconds, of the incident. */ public int length = 0; /** * If true, incident appears minimized. */ public boolean collapsed = false; /** * Number of seconds between start of simulation and start of this incident. */ public int offset = 0; /** * Start position of the latest timeslice. */ private int latestStart = 0; /** * Number of events in this incident. */ public int eventCount = 0; SimulationScript script; /** * Basic constructor. * * @param number The incident ID number * @param name The name of the incident * @param description The description of the incident * @param script The script object holding this incident */ public ScriptIncident(int number, String name, String description, SimulationScript script) { color = Color.BLACK; this.number = number; this.name = name; this.description = description; this.script = script; slices = new TreeMap(); } /** * Constructor with color parameter. * * @param color The color to use in the GUI for this event * @param number The incident ID number * @param name The name of the incident * @param description The description of the incident * @param script The script object holding this incident */ public ScriptIncident(Color color, int number, String name, String description, SimulationScript script) { this.color = color; this.number = number; this.name = name; this.description = description; this.script = script; slices = new TreeMap(); } /** * Constructor with color and offset parameters. * * @param color The color to use in the GUI for this event * @param number The incident ID number * @param name The name of the incident * @param description The description of the incident * @param script The script object holding this incident * @param offset Number of seconds after 00:00:00 that this incident begins */ public ScriptIncident(Color color, int number, String name, String description, SimulationScript script, int offset) { this.color = color; this.number = number; this.name = name; this.description = description; this.script = script; slices = new TreeMap(); this.setOffset(offset); } /** * Set whether or not the incident is fully visible or in a compacted state. * * @param collapsed True if the event is compacted */ public void setCollapsed(boolean collapsed) { this.collapsed = collapsed; script.update(); } /** * Set the delay time between the start of the script and the start of this * incident. * * @param offset Number of seconds after 00:00:00 that this incident begins */ public void setOffset(int offset) { int old = this.offset; this.offset = offset; TreeMap newSlices = new TreeMap(); for(Integer k : slices.keySet()) { newSlices.put(k + (offset - old), slices.get(k)); } for (TimeSlice ts : slices.values()) { ts.shift(offset - old); } slices = newSlices; script.update(); } /** * Add a new script event to this incident. * * @param ev The new event * @param start Start time of this event, in seconds, from the beginning of * the simulation */ public void addNewEvent(I_ScriptEvent ev, int start) { TimeSlice t = slices.get(start); if (t == null) { //System.out.println("Generating new slice at time " + start); t = new TimeSlice(start, this); t.addEvent(ev); slices.put(start, t); } else { t.addEvent(ev); } eventCount++; if (start > latestStart) { latestStart = start; //System.out.println("Latest Start: " + latestStart); } if (start < offset) { offset = start; //System.out.println("Offset: " + offset); } updateLength(); } /** * Get an array of all valid timeSlices. * * @return List of timeSlices which are not null */ public ArrayList getSlices() { ArrayList arr = new ArrayList(); for (int i = 0; i <= latestStart; i++) { TimeSlice ts = slices.get(i); if (ts != null) { arr.add(ts); } } return arr; } /** * Write this incident, in proper XML form, to the file in question. * * @param f the destination savefile */ public void saveIncidentToFile(File f) { try { f.createNewFile(); BufferedWriter bw = new BufferedWriter(new FileWriter(f)); bw.write(this.toXML()); bw.flush(); bw.close(); } catch (Exception ex) { System.out.println("ERROR SAVING SCRIPT"); ex.printStackTrace(); } } @Override public String toXML() { String output = "\n"; output += "\n"; output += XMLWriter.openTag(ELEMENT.TMC_SCRIPT.tag + " title=\"" + this.script.title + "\""); for (TimeSlice slice : slices.values()) { output += slice.toXML(); } output += XMLWriter.closeTag(ELEMENT.TMC_SCRIPT.tag); return output; } void insertCadData(long currentEventTime, CadData cad) { int time = (int) currentEventTime; TimeSlice slice; if (slices.get(time) == null) { slices.put(time, new TimeSlice(time, this)); } slice = slices.get(time); slice.cadData = cad; } /** * Update the offset and apparent length of this incident. The offset is the * start time of the earliest event in the incident. The length is the time * that the latest, longest-lasting event ends, minus the offset. */ public void updateLength() { int lengthSoFar = 0; for (int i = 0; i <= latestStart; i++) { TimeSlice ts = slices.get(i); if (ts != null) { int reach = ts.getTime() + ts.getEffectiveDuration() - offset; if (reach > lengthSoFar) { lengthSoFar = reach; } } } length = lengthSoFar; } /** * An event which is fired if the focused slice changes. */ public static class SliceChangedEvent { /** * The slice which has received focus in this event. */ public TimeSlice slice; SliceChangedEvent(TimeSlice slice) { this.slice = slice; } } /** * Update and cause the system to focus on the given timeslice. * * @param i Index of the slice to focus on */ public void setSliceActive(int i) { if (this.slices.get(i) != null) { script.broadcastEvent(new SliceChangedEvent(this.slices.get(i))); } } /** * An event which is fired if the focused incident changes. */ public static class IncidentFocusedEvent { /** * The incident which has received focus in this event. */ public ScriptIncident incident; IncidentFocusedEvent(ScriptIncident i) { incident = i; } } /** * Update and cause the system to focus on this incident. */ public void setIncidentActive() { script.broadcastEvent(new IncidentFocusedEvent(this)); } /** * String representation of this incident. * * @return String of the form "[Incident number] - [Incident name]" */ @Override public String toString() { return this.number + " - " + this.name; } }