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