001package jmri.jmrit.operations;
002
003import java.io.*;
004
005import org.jdom2.JDOMException;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009import jmri.InstanceManager;
010import jmri.jmrit.XmlFile;
011import jmri.jmrit.operations.locations.LocationManagerXml;
012import jmri.jmrit.operations.rollingstock.cars.CarManagerXml;
013import jmri.jmrit.operations.rollingstock.engines.EngineManagerXml;
014import jmri.jmrit.operations.routes.RouteManagerXml;
015import jmri.jmrit.operations.setup.OperationsSetupXml;
016import jmri.jmrit.operations.trains.TrainManagerXml;
017import jmri.util.FileUtil;
018
019/**
020 * Loads and stores the operation setup using xml files.
021 *
022 * @author Daniel Boudreau Copyright (C) 2008
023 */
024public abstract class OperationsXml extends XmlFile {
025
026    /**
027     * Store the all of the operation train objects in the default place,
028     * including making a backup if needed
029     */
030    public void writeOperationsFile() {
031        createFile(getDefaultOperationsFilename(), true); // make backup
032        try {
033            writeFile(getDefaultOperationsFilename());
034        } catch (IOException e) {
035            log.error("Exception while writing operation file, may not be complete: {}", e.getLocalizedMessage());
036        }
037    }
038
039    protected void load() {
040        try {
041            readFile(getDefaultOperationsFilename());
042        } catch (IOException | JDOMException e) {
043            log.error("Exception during operations file reading: {}", e.getLocalizedMessage());
044        }
045    }
046
047    protected File createFile(String fullPathName, boolean backupFile) {
048        if (backupFile) {
049            makeBackupFile(fullPathName);
050        }
051        File file = null;
052        try {
053            if (!checkFile(fullPathName)) {
054                // log.debug("File "+fullPathName+ " does not exist, creating it");
055                // The file does not exist, create it before writing
056                file = new File(fullPathName);
057                File parentDir = file.getParentFile();
058                if (!parentDir.exists()) {
059                    if (!parentDir.mkdir()) {
060                        log.error("Directory wasn't created");
061                    }
062                }
063                if (file.createNewFile()) {
064                    log.debug("File created {}", fullPathName);
065                }
066            } else {
067                file = new File(fullPathName);
068            }
069        } catch (IOException e) {
070            log.error("Exception while creating operations file, may not be complete: {}", e.getLocalizedMessage());
071        }
072        return file;
073    }
074
075    protected void writeFile(String filename) throws FileNotFoundException, IOException {
076        log.error("writeFile not overridden");
077    }
078
079    /**
080     * @param filename The string file name.
081     * @throws org.jdom2.JDOMException Due to XML parsing error
082     * @throws java.io.IOException     Due to trouble accessing named file
083     */
084    abstract public void readFile(String filename) throws org.jdom2.JDOMException, java.io.IOException;
085
086    private boolean dirty = false;
087
088    public void setDirty(boolean b) {
089        dirty = b;
090    }
091
092    public boolean isDirty() {
093        return dirty;
094    }
095
096    public void writeFileIfDirty() {
097        if (isDirty()) {
098            writeOperationsFile();
099        }
100    }
101
102    public String getDefaultOperationsFilename() {
103        return getFileLocation() + getOperationsDirectoryName() + File.separator + getOperationsFileName();
104    }
105
106    public static void setOperationsDirectoryName(String name) {
107        operationsDirectoryName = name;
108    }
109
110    public static String getOperationsDirectoryName() {
111        return operationsDirectoryName;
112    }
113
114    private static String operationsDirectoryName = "operations"; // NOI18N
115
116    public void setOperationsFileName(String name) {
117        operationsFileName = name;
118    }
119
120    public String getOperationsFileName() {
121        return operationsFileName;
122    }
123
124    private String operationsFileName = "DefaultOperations.xml"; // should be overridden // NOI18N
125
126    /**
127     * Absolute path to location of Operations files.
128     * <p>
129     * Default is in the user's files path, but can be set to anything.
130     *
131     * @return The string path name.
132     *
133     * @see jmri.util.FileUtil#getUserFilesPath()
134     */
135    public static String getFileLocation() {
136        return fileLocation;
137    }
138
139    /**
140     * Set path to location of Operations files.
141     * <p>
142     * Default is in the user's files path, but can be set to anything.
143     *
144     * @param location path to file, including trailing file separator.
145     */
146    public static void setFileLocation(String location) {
147        fileLocation = location;
148    }
149
150    private static String fileLocation = FileUtil.getUserFilesPath();
151
152    /**
153     * Checks name for the file control characters:
154     *
155     * @param name The string to check for a valid file name.
156     * @return true if name is okay, false if name contains a control character.
157     */
158    public static boolean checkFileName(String name) {
159        if (name.contains(".") || name.contains("<") || name.contains(">") // NOI18N
160                || name.contains(":") || name.contains("\"") || name.contains("\\") // NOI18N
161                || name.contains("/") || name.contains("|") || name.contains("?") // NOI18N
162                || name.contains("*")) { // NOI18N
163            return false;
164        }
165        return true;
166    }
167
168    /**
169     * Saves operation files that have been modified.
170     */
171    public static void save() {
172        InstanceManager.getDefault(OperationsSetupXml.class).writeFileIfDirty();
173        InstanceManager.getDefault(LocationManagerXml.class).writeFileIfDirty(); // Need to save "moves" for track location
174        InstanceManager.getDefault(RouteManagerXml.class).writeFileIfDirty(); // Only if user used setX&Y
175        InstanceManager.getDefault(CarManagerXml.class).writeFileIfDirty(); // save train assignments
176        InstanceManager.getDefault(EngineManagerXml.class).writeFileIfDirty(); // save train assignments
177        InstanceManager.getDefault(TrainManagerXml.class).writeFileIfDirty(); // save train changes
178    }
179
180    /**
181     * Checks to see if any operations files are dirty
182     *
183     * @return True if any operations parameters have been modified.
184     */
185    public static boolean areFilesDirty() {
186        return InstanceManager.getDefault(OperationsSetupXml.class).isDirty()
187                || InstanceManager.getDefault(LocationManagerXml.class).isDirty()
188                || InstanceManager.getDefault(RouteManagerXml.class).isDirty()
189                || InstanceManager.getDefault(CarManagerXml.class).isDirty()
190                || InstanceManager.getDefault(EngineManagerXml.class).isDirty()
191                || InstanceManager.getDefault(TrainManagerXml.class).isDirty();
192    }
193
194    private final static Logger log = LoggerFactory.getLogger(OperationsXml.class);
195
196}