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 @ 201

Revision 201, 13.9 KB checked in by jdalbey, 6 years ago (diff)

XMLWriter.java Change from embedding DTD to using a link to external DTD (ticket #236)

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