001package jmri.jmrit.timetable.configurexml;
002
003import java.io.File;
004import java.io.FileNotFoundException;
005import java.io.IOException;
006import java.nio.file.Files;
007import java.nio.file.Path;
008import java.nio.file.StandardCopyOption;
009import java.util.ArrayList;
010import java.util.List;
011import jmri.jmrit.XmlFile;
012import jmri.util.FileUtil;
013import org.jdom2.Document;
014import org.jdom2.Element;
015import org.jdom2.JDOMException;
016import org.jdom2.ProcessingInstruction;
017
018import jmri.jmrit.timetable.*;
019
020/**
021 * Load and store the timetable data file: TimeTableData.xml
022 * @author Dave Sand Copyright (C) 2018
023 */
024public class TimeTableXml {
025
026    public static boolean doStore() {
027        TimeTableDataManager dataMgr = TimeTableDataManager.getDataManager();
028        TimeTableXmlFile x = new TimeTableXmlFile();
029        File file = x.getFile(true);
030        try {
031            FileUtil.rotate(file, 4, "bup");  // NOI18N
032        } catch (IOException ex) {
033            log.warn("Rotate failed, reverting to xml backup");  // NOI18N
034            x.makeBackupFile(TimeTableXmlFile.getDefaultFileName());
035        }
036
037        // Create root element
038        Element root = new Element("timetable-data");  // NOI18N
039
040        root.setAttribute("noNamespaceSchemaLocation",  // NOI18N
041                "http://jmri.org/xml/schema/timetable.xsd",  // NOI18N
042                org.jdom2.Namespace.getNamespace("xsi",
043                        "http://www.w3.org/2001/XMLSchema-instance"));  // NOI18N
044        Document doc = new Document(root);
045
046        // add XSLT processing instruction
047        // <?xml-stylesheet href="/xml/XSLT/timetable.xsl" type="text/xsl"?>
048        java.util.Map<String, String> m = new java.util.HashMap<>();
049        m.put("type", "text/xsl");
050        m.put("href", TimeTableXmlFile.xsltLocation + "timetable.xsl");
051        ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m);
052        doc.addContent(0, p);
053
054        Element values;
055
056        root.addContent(values = new Element("layouts"));  // NOI18N
057        for (Layout layout : dataMgr.getLayouts(false)) {
058            Element e = new Element("layout");  // NOI18N
059            e.addContent(new Element("layout_id").addContent("" + layout.getLayoutId()));  // NOI18N
060            e.addContent(new Element("layout_name").addContent(layout.getLayoutName()));  // NOI18N
061            e.addContent(new Element("scale").addContent(layout.getScale().getScaleName()));  // NOI18N
062            e.addContent(new Element("fast_clock").addContent("" + layout.getFastClock()));  // NOI18N
063            e.addContent(new Element("throttles").addContent("" + layout.getThrottles()));  // NOI18N
064            e.addContent(new Element("metric").addContent((layout.getMetric()) ? "yes" : "no"));  // NOI18N
065            values.addContent(e);
066        }
067
068        root.addContent(values = new Element("train_types"));  // NOI18N
069        for (TrainType type : dataMgr.getTrainTypes(0, false)) {
070            Element e = new Element("train_type");  // NOI18N
071            e.addContent(new Element("type_id").addContent("" + type.getTypeId()));  // NOI18N
072            e.addContent(new Element("layout_id").addContent("" + type.getLayoutId()));  // NOI18N
073            e.addContent(new Element("type_name").addContent(type.getTypeName()));  // NOI18N
074            e.addContent(new Element("type_color").addContent(type.getTypeColor()));  // NOI18N
075            values.addContent(e);
076        }
077
078        root.addContent(values = new Element("segments"));  // NOI18N
079        for (Segment segment : dataMgr.getSegments(0, false)) {
080            Element e = new Element("segment");  // NOI18N
081            e.addContent(new Element("segment_id").addContent("" + segment.getSegmentId()));  // NOI18N
082            e.addContent(new Element("layout_id").addContent("" + segment.getLayoutId()));  // NOI18N
083            e.addContent(new Element("segment_name").addContent(segment.getSegmentName()));  // NOI18N
084            values.addContent(e);
085        }
086
087        root.addContent(values = new Element("stations"));  // NOI18N
088        for (Station station : dataMgr.getStations(0, false)) {
089            Element e = new Element("station");  // NOI18N
090            e.addContent(new Element("station_id").addContent("" + station.getStationId()));  // NOI18N
091            e.addContent(new Element("segment_id").addContent("" + station.getSegmentId()));  // NOI18N
092            e.addContent(new Element("station_name").addContent(station.getStationName()));  // NOI18N
093            e.addContent(new Element("distance").addContent("" + station.getDistance()));  // NOI18N
094            e.addContent(new Element("double_track").addContent((station.getDoubleTrack()) ? "yes" : "no"));  // NOI18N
095            e.addContent(new Element("sidings").addContent("" + station.getSidings()));  // NOI18N
096            e.addContent(new Element("staging").addContent("" + station.getStaging()));  // NOI18N
097            values.addContent(e);
098        }
099
100        root.addContent(values = new Element("schedules"));  // NOI18N
101        for (Schedule schedule : dataMgr.getSchedules(0, false)) {
102            Element e = new Element("schedule");  // NOI18N
103            e.addContent(new Element("schedule_id").addContent("" + schedule.getScheduleId()));  // NOI18N
104            e.addContent(new Element("layout_id").addContent("" + schedule.getLayoutId()));  // NOI18N
105            e.addContent(new Element("schedule_name").addContent(schedule.getScheduleName()));  // NOI18N
106            e.addContent(new Element("eff_date").addContent(schedule.getEffDate()));  // NOI18N
107            e.addContent(new Element("start_hour").addContent("" + schedule.getStartHour()));  // NOI18N
108            e.addContent(new Element("duration").addContent("" + schedule.getDuration()));  // NOI18N
109            values.addContent(e);
110        }
111
112        root.addContent(values = new Element("trains"));  // NOI18N
113        for (Train train : dataMgr.getTrains(0, 0, false)) {
114            Element e = new Element("train");  // NOI18N
115            e.addContent(new Element("train_id").addContent("" + train.getTrainId()));  // NOI18N
116            e.addContent(new Element("schedule_id").addContent("" + train.getScheduleId()));  // NOI18N
117            e.addContent(new Element("type_id").addContent("" + train.getTypeId()));  // NOI18N
118            e.addContent(new Element("train_name").addContent(train.getTrainName()));  // NOI18N
119            e.addContent(new Element("train_desc").addContent(train.getTrainDesc()));  // NOI18N
120            e.addContent(new Element("default_speed").addContent("" + train.getDefaultSpeed()));  // NOI18N
121            e.addContent(new Element("start_time").addContent("" + train.getStartTime()));  // NOI18N
122            e.addContent(new Element("throttle").addContent("" + train.getThrottle()));  // NOI18N
123            e.addContent(new Element("route_duration").addContent("" + train.getRouteDuration()));  // NOI18N
124            e.addContent(new Element("train_notes").addContent(train.getTrainNotes()));  // NOI18N
125            values.addContent(e);
126        }
127
128        root.addContent(values = new Element("stops"));  // NOI18N
129        for (Stop stop : dataMgr.getStops(0, 0, false)) {
130            Element e = new Element("stop");  // NOI18N
131            e.addContent(new Element("stop_id").addContent("" + stop.getStopId()));  // NOI18N
132            e.addContent(new Element("train_id").addContent("" + stop.getTrainId()));  // NOI18N
133            e.addContent(new Element("station_id").addContent("" + stop.getStationId()));  // NOI18N
134            e.addContent(new Element("seq").addContent("" + stop.getSeq()));  // NOI18N
135            e.addContent(new Element("duration").addContent("" + stop.getDuration()));  // NOI18N
136            e.addContent(new Element("next_speed").addContent("" + stop.getNextSpeed()));  // NOI18N
137            e.addContent(new Element("arrive_time").addContent("" + stop.getArriveTime()));  // NOI18N
138            e.addContent(new Element("depart_time").addContent("" + stop.getDepartTime()));  // NOI18N
139            e.addContent(new Element("staging_track").addContent("" + stop.getStagingTrack()));  // NOI18N
140            e.addContent(new Element("stop_notes").addContent(stop.getStopNotes()));  // NOI18N
141            values.addContent(e);
142        }
143
144        try {
145            x.writeXML(file, doc);
146        } catch (FileNotFoundException ex) {
147            log.error("File not found when writing", ex);  // NOI18N
148            return false;
149        } catch (IOException ex) {
150            log.error("IO Exception when writing", ex);  // NOI18N
151            return false;
152        }
153
154        log.debug("...done");  // NOI18N
155        return true;
156    }
157
158    public static boolean doLoad() {
159        TimeTableDataManager dataMgr = TimeTableDataManager.getDataManager();
160        TimeTableXmlFile x = new TimeTableXmlFile();
161        File file = x.getFile(false);
162
163        if (file == null) {
164            log.debug("Nothing to load");  // NOI18N
165            return false;
166        }
167
168        // Validate foreign keys
169        List<Integer> checkLayoutIds = new ArrayList<>();
170        List<Integer> checkTypeIds = new ArrayList<>();
171        List<Integer> checkSegmentIds = new ArrayList<>();
172        List<Integer> checkStationIds = new ArrayList<>();
173        List<Integer> checkScheduleIds = new ArrayList<>();
174        List<Integer> checkTrainIds = new ArrayList<>();
175
176        log.debug("Start loading timetable data...");  // NOI18N
177
178        // Find root
179        Element root;
180        try {
181            root = x.rootFromFile(file);
182            if (root == null) {
183                log.debug("File could not be read");  // NOI18N
184                return false;
185            }
186
187            // Layouts
188            Element layouts = root.getChild("layouts");  // NOI18N
189            if (layouts == null) {
190                log.error("Unable to find a layout entry");  // NOI18N
191                return false;
192            }
193            for (Element layout : layouts.getChildren("layout")) {  // NOI18N
194                Element layout_id = layout.getChild("layout_id");  // NOI18N
195                int layoutId = (layout_id == null) ? 0 : Integer.parseInt(layout_id.getValue());
196                Element layout_name = layout.getChild("layout_name");  // NOI18N
197                String layoutName = (layout_name == null) ? "" : layout_name.getValue();
198                Element scaleE = layout.getChild("scale");  // NOI18N
199                jmri.Scale scale = (scaleE == null) ? jmri.ScaleManager.getScale("HO") : jmri.ScaleManager.getScale(scaleE.getValue());  // NOI18N
200                Element fast_clock = layout.getChild("fast_clock");  // NOI18N
201                int fastClock = (fast_clock == null) ? 1 : Integer.parseInt(fast_clock.getValue());
202                Element throttlesE = layout.getChild("throttles");  // NOI18N
203                int throttles = (throttlesE == null) ? 0 : Integer.parseInt(throttlesE.getValue());
204                Element metricE = layout.getChild("metric");  // NOI18N
205                boolean metric = (metricE == null) ? false : metricE.getValue().equals("yes");  // NOI18N
206                log.debug("  Layout: {} - {} - {} - {} - {} - {}",  // NOI18N
207                    layoutId, layoutName, scale, fastClock, throttles, metric);
208
209                // Create a Layout
210                Layout newLayout = new Layout(layoutId, layoutName, scale, fastClock, throttles, metric);
211                dataMgr.addLayout(layoutId, newLayout);
212                checkLayoutIds.add(layoutId);
213            }
214
215            // Train Types
216            Element train_types = root.getChild("train_types");  // NOI18N
217            if (train_types == null) {
218                log.error("Unable to find train types");  // NOI18N
219                return false;
220            }
221            for (Element train_type : train_types.getChildren("train_type")) {  // NOI18N
222                Element type_id = train_type.getChild("type_id");  // NOI18N
223                int typeId = (type_id == null) ? 0 : Integer.parseInt(type_id.getValue());
224                Element layout_id = train_type.getChild("layout_id");  // NOI18N
225                int layoutId = (layout_id == null) ? 0 : Integer.parseInt(layout_id.getValue());
226                Element type_name = train_type.getChild("type_name");  // NOI18N
227                String typeName = (type_name == null) ? "" : type_name.getValue();
228                Element type_color = train_type.getChild("type_color");  // NOI18N
229                String typeColor = (type_color == null) ? "#000000" : type_color.getValue();  // NOI18N
230                log.debug("    Type: {} - {} - {}", typeId, typeName, typeColor);  // NOI18N
231
232                // Validate layoutId
233                if (!checkLayoutIds.contains(layoutId)) {
234                    log.warn("TrainType {} layout id not found", typeName);  // NOI18N
235                    continue;
236                }
237
238                // Create a train type
239                TrainType newType = new TrainType(typeId, layoutId, typeName, typeColor);
240                dataMgr.addTrainType(typeId, newType);
241                checkTypeIds.add(typeId);
242            }
243
244            // Segments
245            Element segments = root.getChild("segments");  // NOI18N
246            if (segments == null) {
247                log.error("Unable to find segments");  // NOI18N
248                return false;
249            }
250            for (Element segment : segments.getChildren("segment")) {  // NOI18N
251                Element segment_id = segment.getChild("segment_id");  // NOI18N
252                int segmentId = (segment_id == null) ? 0 : Integer.parseInt(segment_id.getValue());
253                Element layout_id = segment.getChild("layout_id");  // NOI18N
254                int layoutId = (layout_id == null) ? 0 : Integer.parseInt(layout_id.getValue());
255                Element segment_name = segment.getChild("segment_name");  // NOI18N
256                String segmentName = (segment_name == null) ? "" : segment_name.getValue();
257                log.debug("    Segment: {} - {} - {}", segmentId, layoutId, segmentName);  // NOI18N
258
259                // Validate layoutId
260                if (!checkLayoutIds.contains(layoutId)) {
261                    log.warn("Segment {} layout id not found", segmentName);  // NOI18N
262                    continue;
263                }
264
265                // Create a segment
266                Segment newSegment = new Segment(segmentId, layoutId, segmentName);
267                dataMgr.addSegment(segmentId, newSegment);
268                checkSegmentIds.add(segmentId);
269            }
270
271            // Stations
272            Element stations = root.getChild("stations");  // NOI18N
273            if (stations == null) {
274                log.error("Unable to find stations");  // NOI18N
275                return false;
276            }
277            for (Element station : stations.getChildren("station")) {  // NOI18N
278                Element station_id = station.getChild("station_id");  // NOI18N
279                int stationId = (station_id == null) ? 0 : Integer.parseInt(station_id.getValue());
280                Element segment_id = station.getChild("segment_id");  // NOI18N
281                int segmentId = (segment_id == null) ? 0 : Integer.parseInt(segment_id.getValue());
282                Element station_name = station.getChild("station_name");  // NOI18N
283                String stationName = (station_name == null) ? "" : station_name.getValue();
284                Element distanceE = station.getChild("distance");  // NOI18N
285                double distance = (distanceE == null) ? 1.0 : Double.parseDouble(distanceE.getValue());
286                Element double_track = station.getChild("double_track");  // NOI18N
287                boolean doubleTrack = (double_track == null) ? false : double_track.getValue().equals("yes");  // NOI18N
288                Element sidingsE = station.getChild("sidings");  // NOI18N
289                int sidings = (sidingsE == null) ? 0 : Integer.parseInt(sidingsE.getValue());
290                Element stagingE = station.getChild("staging");  // NOI18N
291                int staging = (stagingE == null) ? 0 : Integer.parseInt(stagingE.getValue());
292                log.debug("      Station: {} - {} - {} - {} - {} - {}", stationId, stationName, distance, doubleTrack, sidings, staging);  // NOI18N
293
294                // Validate segmentId
295                if (!checkSegmentIds.contains(segmentId)) {
296                    log.warn("Station {} segment id not found", stationName);  // NOI18N
297                    continue;
298                }
299
300                // Create a station
301                Station newStation = new Station(stationId, segmentId, stationName, distance, doubleTrack, sidings, staging);
302                dataMgr.addStation(stationId, newStation);
303                checkStationIds.add(stationId);
304            }
305
306            Element schedules = root.getChild("schedules");  // NOI18N
307            if (schedules == null) {
308                log.error("Unable to find schedules");  // NOI18N
309                return false;
310            }
311            for (Element schedule : schedules.getChildren("schedule")) {  // NOI18N
312                Element schedule_id = schedule.getChild("schedule_id");  // NOI18N
313                int scheduleId = (schedule_id == null) ? 0 : Integer.parseInt(schedule_id.getValue());
314                Element layout_id = schedule.getChild("layout_id");  // NOI18N
315                int layoutId = (layout_id == null) ? 0 : Integer.parseInt(layout_id.getValue());
316                Element schedule_name = schedule.getChild("schedule_name");  // NOI18N
317                String scheduleName = (schedule_name == null) ? "" : schedule_name.getValue();
318                Element eff_date = schedule.getChild("eff_date");  // NOI18N
319                String effDate = (eff_date == null) ? "" : eff_date.getValue();
320                Element start_hour = schedule.getChild("start_hour");  // NOI18N
321                int startHour = (start_hour == null) ? 0 : Integer.parseInt(start_hour.getValue());
322                Element durationE = schedule.getChild("duration");  // NOI18N
323                int duration = (durationE == null) ? 0 : Integer.parseInt(durationE.getValue());
324                log.debug("    Schedule: {} - {} - {} - {} - {} - {}", scheduleId, layoutId, scheduleName, effDate, startHour, duration);  // NOI18N
325
326                // Validate layoutId
327                if (!checkLayoutIds.contains(layoutId)) {
328                    log.warn("Schdule {} layout id not found", scheduleName);  // NOI18N
329                    continue;
330                }
331
332                // Create a schedule
333                Schedule newSchedule = new Schedule(scheduleId, layoutId, scheduleName, effDate, startHour, duration);
334                dataMgr.addSchedule(scheduleId, newSchedule);
335                checkScheduleIds.add(scheduleId);
336            }
337
338            Element trains = root.getChild("trains");  // NOI18N
339            if (trains == null) {
340                log.error("Unable to find trains");  // NOI18N
341                return false;
342            }
343            for (Element train : trains.getChildren("train")) {  // NOI18N
344                Element train_id = train.getChild("train_id");  // NOI18N
345                int trainId = (train_id == null) ? 0 : Integer.parseInt(train_id.getValue());
346                Element schedule_id = train.getChild("schedule_id");  // NOI18N
347                int scheduleId = (schedule_id == null) ? 0 : Integer.parseInt(schedule_id.getValue());
348                Element type_id = train.getChild("type_id");  // NOI18N
349                int typeId = (type_id == null) ? 0 : Integer.parseInt(type_id.getValue());
350                Element train_name = train.getChild("train_name");  // NOI18N
351                String trainName = (train_name == null) ? "" : train_name.getValue();
352                Element train_desc = train.getChild("train_desc");  // NOI18N
353                String trainDesc = (train_desc == null) ? "" : train_desc.getValue();
354                Element default_speed = train.getChild("default_speed");  // NOI18N
355                int defaultSpeed = (default_speed == null) ? 1 : Integer.parseInt(default_speed.getValue());
356                Element start_time = train.getChild("start_time");  // NOI18N
357                int startTime = (start_time == null) ? 0 : Integer.parseInt(start_time.getValue());
358                Element throttleE = train.getChild("throttle");  // NOI18N
359                int throttle = (throttleE == null) ? 0 : Integer.parseInt(throttleE.getValue());
360                Element route_duration = train.getChild("route_duration");  // NOI18N
361                int routeDuration = (route_duration == null) ? 0 : Integer.parseInt(route_duration.getValue());
362                Element train_notes = train.getChild("train_notes");  // NOI18N
363                String trainNotes = (train_notes == null) ? "" : train_notes.getValue();
364                log.debug("      Train: {} - {} - {} - {} - {} - {} - {} - {} - {} - {}",  // NOI18N
365                        trainId, scheduleId, typeId, trainName,
366                        trainDesc, defaultSpeed, startTime, throttle,
367                        routeDuration, trainNotes);
368
369                // Validate scheduleId
370                if (!checkScheduleIds.contains(scheduleId)) {
371                    log.warn("Train {} schedule id not found", trainName);  // NOI18N
372                    continue;
373                }
374                // Validate typeId
375                if (!checkTypeIds.contains(typeId)) {
376                    log.warn("Train {} type id not found", trainName);  // NOI18N
377                    continue;
378                }
379
380                // Create a train
381                Train newTrain = new Train(trainId, scheduleId, typeId, trainName, trainDesc,
382                        defaultSpeed, startTime, throttle, routeDuration, trainNotes);
383                dataMgr.addTrain(trainId, newTrain);
384                checkTrainIds.add(trainId);
385            }
386
387            Element stops = root.getChild("stops");  // NOI18N
388            if (stops == null) {
389                log.error("Unable to find stops");  // NOI18N
390                return false;
391            }
392            for (Element stop : stops.getChildren("stop")) {  // NOI18N
393                Element stop_id = stop.getChild("stop_id");  // NOI18N
394                int stopId = (stop_id == null) ? 0 : Integer.parseInt(stop_id.getValue());
395                Element train_id = stop.getChild("train_id");  // NOI18N
396                int trainId = (train_id == null) ? 0 : Integer.parseInt(train_id.getValue());
397                Element station_id = stop.getChild("station_id");  // NOI18N
398                int stationId = (station_id == null) ? 0 : Integer.parseInt(station_id.getValue());
399                Element seqE = stop.getChild("seq");  // NOI18N
400                int seq = (seqE == null) ? 0 : Integer.parseInt(seqE.getValue());
401                Element durationE = stop.getChild("duration");  // NOI18N
402                int duration = (durationE == null) ? 0 : Integer.parseInt(durationE.getValue());
403                Element next_speed = stop.getChild("next_speed");  // NOI18N
404                int nextSpeed = (next_speed == null) ? 0 : Integer.parseInt(next_speed.getValue());
405                Element arrive_time = stop.getChild("arrive_time");  // NOI18N
406                int arriveTime = (arrive_time == null) ? 0 : Integer.parseInt(arrive_time.getValue());
407                Element depart_time = stop.getChild("depart_time");  // NOI18N
408                int departTime = (depart_time == null) ? 0 : Integer.parseInt(depart_time.getValue());
409                Element staging_track = stop.getChild("staging_track");  // NOI18N
410                int stagingTrack = (staging_track == null) ? 0 : Integer.parseInt(staging_track.getValue());
411                Element stop_notes = stop.getChild("stop_notes");  // NOI18N
412                String stopNotes = (stop_notes == null) ? "" : stop_notes.getValue();
413
414                log.debug("        Stop: {} - {} - {} - {} - {} - {} - {} - {} - {} - {}",  // NOI18N
415                        stopId, trainId, stationId, seq, duration, nextSpeed, arriveTime, departTime, stagingTrack, stopNotes);
416
417                // Validate trainId
418                if (!checkTrainIds.contains(trainId)) {
419                    log.warn("Stop train id not found");  // NOI18N
420                    continue;
421                }
422                // Validate stationId
423                if (!checkStationIds.contains(stationId)) {
424                    log.warn("Stop station id not found");  // NOI18N
425                    continue;
426                }
427
428                // Create a stop
429                Stop newStop = new Stop(stopId, trainId, stationId, seq, duration,
430                        nextSpeed, arriveTime, departTime, stagingTrack, stopNotes);
431                dataMgr.addStop(stopId, newStop);
432            }
433        } catch (JDOMException ex) {
434            log.error("File invalid", ex);  // NOI18N
435            return false;
436        } catch (IOException ex) {
437            log.error("Error reading file", ex);  // NOI18N
438            return false;
439        }
440
441        log.debug("...done");  // NOI18N
442        return true;
443    }
444
445
446    public static class TimeTableXmlFile extends XmlFile {
447        private static String fileLocation = FileUtil.getUserFilesPath() + "timetable/";  // NOI18N
448        private static String demoLocation = FileUtil.getProgramPath() + "xml/demoTimetable/";  // NOI18N
449        private static String baseFileName = "TimeTableData.xml";  // NOI18N
450
451        public static String getDefaultFileName() {
452            return getFileLocation() + getFileName();
453        }
454
455        public File getFile(boolean store) {
456            // Verify that preference:timetable exists
457            File chkdir = new File(getFileLocation());
458            if (!chkdir.exists()) {
459                if (!chkdir.mkdirs()) {
460                    log.error("Create {} failed", chkdir);  // NOI18N
461                    return null;
462                }
463            }
464
465            // Verify that the TimeTable data file exists
466            File chkfile = new File(getDefaultFileName());
467            if (!chkfile.exists()) {
468                // Copy the demo file
469                File demoFile = new File(demoLocation + baseFileName);
470                Path toPath = chkdir.toPath();
471                Path fromPath = demoFile.toPath();
472                try {
473                    Files.copy(fromPath, toPath.resolve(fromPath.getFileName()), StandardCopyOption.REPLACE_EXISTING);
474                } catch (IOException ex) {
475                    log.error("Copy TimeTable demo file failed");  // NOI18N
476                    return null;
477                }
478            }
479
480            File file = findFile(getDefaultFileName());
481            if (file == null && store) {
482                log.info("create new file");  // NOI18N
483                file = new File(getDefaultFileName());
484            }
485            return file;
486        }
487
488        public static String getFileName() {
489            if(baseFileName == null) {
490               baseFileName = "TimeTableData.xml";  // NOI18N
491            }
492            return baseFileName;
493        }
494
495        /**
496         * Absolute path to location of TimeTable files.
497         *
498         * @return path to location
499         */
500        public static String getFileLocation() {
501            if(fileLocation==null){
502               fileLocation = FileUtil.getUserFilesPath() + "timetable/";  // NOI18N
503            }
504            return fileLocation;
505        }
506
507        /**
508         * Reset the static file location.
509         * Only required for unit testing purposes.
510         */
511        public static void resetFileLocation() {
512            fileLocation = null;
513        }
514    }
515
516    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TimeTableXml.class);
517}