Warning: Can't use blame annotator:
svn blame failed on trunk/src/scriptbuilder/structures/SimulationScript.java: ("Can't find a temporary directory: Internal error", 20014)

source: tmcsimulator-scriptbuilder/trunk/src/scriptbuilder/structures/SimulationScript.java @ 203

Revision 203, 14.1 KB checked in by jdalbey, 6 years ago (diff)

XMLWriter.java name changed to XMLBuilder. Add pretty printing methods (ticket #237).

RevLine 
1package scriptbuilder.structures;
2
3import java.awt.Color;
4import java.io.BufferedWriter;
5import java.io.File;
6import java.io.FileWriter;
7import java.io.IOException;
8import java.util.ArrayList;
9import java.util.List;
10import java.util.Observable;
11import java.util.Vector;
12import javax.xml.parsers.SAXParserFactory;
13import scriptbuilder.structures.ScriptIncident.IncidentFocusedEvent;
14import scriptbuilder.structures.ScriptIncident.SliceChangedEvent;
15import scriptbuilder.structures.events.*;
16import scriptbuilder.structures.units.Unit;
17import java.nio.file.Path;
18import java.nio.file.Paths;
19import java.util.TreeMap;
20import static scriptbuilder.structures.XMLBuilder.prettyPrintXML;
21
22/**
23 * Representation of the script to be run by the TMC Simulator. Holds a list of
24 * incidents, which have start and end times and contain events.
25 *
26 * @author Greg Eddington <geddingt@calpoly.edu>
27 *
28 * @author Bryan McGuffin <bmcguffi@calpoly.edu>
29 * @author Sebastien Danthinne <sdanthin@calpoly.edu>
30 * @version 2017/06/22
31 */
32public class SimulationScript extends Observable implements I_XML_Writable
33{
34
35    /**
36     * Strings to show in the incident color combo box.  Last item should be black,
37     * which will be used if invalid color is provided to lookupColor().
38     */
39    public static final String[] colorNames = {"BLUE", "RED", "CYAN", "GREEN", 
40        "ORANGE", "MAGENTA", "YELLOW", "BLACK"};
41    /**
42     * Allowed color choices for incident display.
43     * These colors must match the items in colorNames.
44     */
45    public static final Color[] incidentColors = {Color.BLUE, Color.RED, Color.CYAN, 
46        Color.GREEN, Color.ORANGE, Color.MAGENTA, Color.YELLOW, Color.BLACK};
47    /**
48     * The file to which this script will be saved.
49     */
50    public File saveFile = null;
51
52    /**
53     * The name of this script.
54     */
55    public String title = "";
56
57    /**
58     * The incidents displayed by the GUI.
59     */
60    public List<ScriptIncident> incidents;
61
62    /**
63     * The units which participate in Unit events.
64     */
65    public List<Unit> units; 
66
67    //Somewhere in the code, something assumes that the list of incidents
68    //contains exactly 10 items. Until I can find and un-break that, this will do.
69    //todo: this incident fill count error
70    private final int INCIDENT_FILL_COUNT = 10;
71
72    /**
73     * Number of incidents currently displayed.
74     */
75    public int numberOfIncidents;
76
77    /**
78     * Script handler for parsing incoming XML files.
79     */
80    private MyScriptHandler sh;
81   
82    public final String audioDirectory = "Audio";
83
84   
85    public boolean saved;
86   
87    //TODO: Pretty much everything in this constructor is dummy data.
88    //Replace all of it.
89    /**
90     * Constructor. Backfill incident list with null objects, to be replaced
91     * later.
92     */
93    public SimulationScript()
94    {
95        sh = new MyScriptHandler(this);
96        incidents = new ArrayList<ScriptIncident>();
97        units = new ArrayList<Unit>();
98        numberOfIncidents = 0;
99        saved = true;
100
101        //Backfill with null incidents
102        for (int i = numberOfIncidents; i < INCIDENT_FILL_COUNT; i++)
103        {
104            incidents.add(null);
105        }
106    }
107   
108    /**
109     * checks and sees if this object has the unit passed.
110     * @param unitID
111     * @return does this SimulationScript have unitnum?
112     */
113    public boolean hasUnit(String unitID){
114        boolean indicator = false;
115        if(units.size()!=0){
116            for(Unit u : units){
117               if(unitID.equals(u.UnitNum)){
118                   indicator = true;
119               }
120            }
121        }
122           
123        return indicator;
124    }
125    /**
126     * creates a dummy unit that only has unit number
127     * @param unitNum
128     */
129    public void addDummyUnit(String unitNum){
130        Unit dummy = new Unit();
131        dummy.UnitNum = unitNum;
132        units.add(dummy);
133    }
134    /**
135     * Update the script's observers.
136     *
137     */
138    public void update()
139    {
140        // The script has changed, notify observers
141        //use to rewrite the save indicator
142        //System.out.println("Script changed");
143        setChanged();
144        notifyObservers(this);
145        saved = false;
146       
147       
148    }
149   
150
151    /**
152     * Tell this script's observers that there is a new slice event.
153     *
154     * @param e the slice focus event
155     */
156    public void broadcastEvent(SliceChangedEvent e)
157    {
158        // The slice focus has changed; pass the message
159        setChanged();
160        notifyObservers(e);
161    }
162
163    /**
164     * Tell this script's observers that there is a new slice event.
165     *
166     * @param e the incident focus event
167     */
168    public void broadcastEvent(IncidentFocusedEvent e)
169    {
170        // The slice focus has changed; pass the message
171        setChanged();
172        notifyObservers(e);
173    }
174
175    /**
176     * Load in an existing script from an XML file.
177     *
178     * @param f the file containing the script
179     */
180    public void loadScriptFromFile(File f)
181    {
182        try
183        {
184
185            SAXParserFactory.newInstance().newSAXParser().parse(f, sh);
186
187            Vector<ScriptIncident> inc = sh.getIncidents();
188            units = sh.getUnits();
189            for (ScriptIncident sci : inc)
190            {
191                addIncident(sci);
192            }
193        }
194        catch (Exception ex)
195        {
196            System.out.println("ERROR LOADING SCRIPT");
197            ex.printStackTrace();
198        }
199        System.out.println("H");
200        for(Unit testUnit : units){
201            System.out.println(testUnit.toXML());
202        }
203        this.update();
204    }
205   
206    /**
207     * Load in an existing list of units from an XML file.
208     * @param inStream the input stream for the file containing the units
209     */
210    public void loadUnitsFromFile(java.io.InputStream inStream){
211        try
212        {
213            SAXParserFactory.newInstance().newSAXParser().parse(inStream, sh);
214            units.addAll(sh.getUnits());
215        }
216        catch (Exception ex)
217        {
218            System.out.println("ERROR LOADING UNITS");
219            ex.printStackTrace();
220        }
221        this.update();
222    }
223
224    /**
225     * Add a new incident to the script.
226     *
227     * @param sci the incident to be added.
228     * @return true if there was enough room to add this incident.
229     */
230    public boolean addIncident(ScriptIncident sci)
231    {
232        if (numberOfIncidents < INCIDENT_FILL_COUNT)
233        {
234            incidents.set(numberOfIncidents++, sci);
235            return true;
236        }
237        return false;
238    }
239
240    /**
241     * Write this script, in proper XML format, to the file in question.
242     *
243     * @param f the destination savefile to be written.
244     */
245    public void saveScriptToFile(File f)
246    {
247        try
248        {
249            f.createNewFile();
250
251            BufferedWriter bw = new BufferedWriter(new FileWriter(f));
252            // convert to XML and remove newlines
253            String xmlOut = (this.toXML()).replace("\n",""); 
254            // pretty print and save to file
255            bw.write(prettyPrintXML(xmlOut));
256            bw.flush();
257            bw.close();
258        }
259        catch (Exception ex)
260        {
261            System.out.println("ERROR SAVING SCRIPT");
262            ex.printStackTrace();
263        }
264        try
265        {
266            createAudioDirectory(Paths.get(f.getCanonicalPath()).getParent());
267        }
268        catch(IOException ex)
269        {
270            System.err.println("there was a problem creating the audio directories.");
271        }
272       
273       
274        saved = true;
275    }
276   
277    /**
278     * Creates the proper audio directory using the I_AudioEvent types.
279     * @param path of audio directory root
280     */
281    private void createAudioDirectory(Path path){
282        String separator = System.getProperty("file.separator");
283        File f = new File(path.toString()+separator+audioDirectory);
284        if(!f.exists())
285        {
286            f.mkdir();
287            //scan through to see what is already there and if there is no existing audio directory, create it.
288        }
289        for(ScriptIncident i : incidents)
290        {
291            if(i!=null)
292            {
293                String name = ((Integer) i.number).toString();
294                File incidentFolder = new File(path.toString()+separator+audioDirectory+separator+name);
295                if(!incidentFolder.exists())
296                {
297                    //create an incidentfolder since one does not already exist
298                    incidentFolder.mkdir();
299                }
300
301               
302                for(TimeSlice slice : i.getSlices())
303                {
304                    for(I_ScriptEvent event : slice.events)
305                    {
306                        if(event instanceof I_AudioEvent)
307                        {
308                            //if the event is a chp radio event
309                            //then add the dummy file to the subdirectory created
310                            //CURRENTLY this ONLY is implemented for CHPRadioEvent, so it will need to be changed later.
311                            CHPRadioEvent radioEvent = (CHPRadioEvent) event;
312
313                            String output = radioEvent.toScriptFile();
314                            //optimally, this line should use the ID, but to account for files being read in, it needs to be the radiofile name
315                            System.out.println("Attempting to create file: "+ path.toString()+
316                                            separator+
317                                            audioDirectory+
318                                            separator+
319                                            name+
320                                            separator+
321                                            radioEvent.radioFile.replaceAll(".mp3","")+
322                                            ".txt");
323                            File newAudioScript = new File(
324                                    path.toString()+
325                                            separator+
326                                            audioDirectory+
327                                            separator+
328                                            name+
329                                            separator+
330                                            radioEvent.radioFile.replaceAll(".mp3","")+
331                                            ".txt");
332                           
333                            try
334                            {
335                                newAudioScript.createNewFile();
336                                BufferedWriter bw = new BufferedWriter(new FileWriter(newAudioScript));
337                                bw.write(output);
338                                bw.flush();
339                                bw.close();
340                            }catch(Exception e)
341                            {
342                                //to find the bug that triggers this Exception, we need to print out the lines that
343                                System.err.println("there was a problem creating your text files for: " + radioEvent.radioFile + "\n" + e.getMessage());
344                            }
345
346                        }
347                    }
348                }
349
350               
351            }
352
353           
354        }
355       
356       
357    }
358    @Override
359    public String toXML()
360    {
361        ArrayList<TimeSlice> slices = arrangeAllSlices();
362        String output = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
363        output += XMLBuilder.externalDTD();
364        output += XMLBuilder.openTag(ELEMENT.TMC_SCRIPT.tag + " title=\"" + this.title + "\"");
365
366        if (units.size() > 0)
367        {
368            output += XMLBuilder.openTag(ELEMENT.SCRIPT_DATA.tag);
369            for (Unit unit : units)
370            {
371                output += unit.toXML();
372            }
373            output += XMLBuilder.closeTag(ELEMENT.SCRIPT_DATA.tag);
374        }
375        for (TimeSlice slice : slices)
376        {
377            output += slice.toXML();
378        }
379        output += XMLBuilder.closeTag(ELEMENT.TMC_SCRIPT.tag);
380        return output;
381    }
382
383    /**
384     * Arranges all timeslices in this script in chronological order, then by
385     * incident number.
386     *
387     * @return a list of all timeslices in the simulation script
388     */
389    public ArrayList<TimeSlice> arrangeAllSlices()
390    {
391        ArrayList<TimeSlice> list = new ArrayList<TimeSlice>();
392        int length = absoluteLength();
393
394        for (int i = 0; i < length; i++)
395        {
396            for (ScriptIncident inc : incidents)
397            {
398
399                if (inc != null && inc.slices.get(i) != null)
400                {
401                    list.add(inc.slices.get(i));
402                }
403            }
404        }
405        return list;
406    }
407
408    /**
409     * Gets the total length of the simulation in seconds.
410     *
411     * @return
412     */
413    public int absoluteLength()
414    {
415        int length = 0;
416        for (ScriptIncident inc : incidents)
417        {
418            if (inc != null)
419            {
420                inc.updateLength();
421                int currentLength = inc.length + inc.offset;
422                if (currentLength > length)
423                {
424                    length = currentLength;
425                }
426            }
427        }
428        return length;
429    }
430
431    /**
432     * Counts the number of incidents currently running.
433     *
434     * @return the number of non-null incidents currently in the script. A
435     * number between 0 and INCIDENT_FILL_COUNT, inclusive.
436     */
437    public int incidentCount()
438    {
439        int count = 0;
440        for (ScriptIncident inc : incidents)
441        {
442            if (inc != null)
443            {
444                count++;
445            }
446        }
447        return count;
448    }
449   
450    /** Given a color, find its index in the incidentColors.
451     * @param color a java color
452     * @return the index of color in incidentColors, or last index if color isn't
453     * in incidentColors.  The last item in incidentColors should be black.
454     */
455    public static int lookupColor(Color color)
456    {
457        int idx = 0;
458        // search color array for target
459        while(idx < incidentColors.length && !incidentColors[idx].equals(color))
460        { 
461            idx++;
462        }
463        // if color not found, return index of last item.
464        if (idx == incidentColors.length) 
465        {
466            return idx-1;
467        }
468        else return idx;
469    }
470}
Note: See TracBrowser for help on using the repository browser.