001package jmri.configurexml;
002
003import java.io.File;
004import java.io.FileNotFoundException;
005import java.io.IOException;
006
007import jmri.jmrit.XmlFile;
008import jmri.util.FileUtil;
009
010import org.jdom2.Document;
011import org.jdom2.Element;
012import org.jdom2.JDOMException;
013
014/**
015 * Load and store scale xml data files.
016 * <p>
017 * Custom changes to scale information result in the scale data being stored
018 * at the user files location.  Subsequent scale data loading uses the custom
019 * data file.  The default scale data file is part of the JMRI distribution.
020 * @author Dave Sand Copyright (C) 2018
021 * @since 4.13.6
022 */
023public class ScaleConfigXML {
024
025    /**
026     * Prevent public Construction, class only supplies static methods.
027     */
028    private ScaleConfigXML(){}
029
030    /**
031     * Store the Scales to file.
032     * @return true on success, else false.
033     */
034    public static boolean doStore() {
035        ScaleXmlFile x = new ScaleXmlFile();
036        File file = x.getStoreFile();
037        if (file == null) {
038            log.warn("Unable to create local scale file");
039            return false;
040        }
041
042        // Create root element
043        Element root = new Element("scale-data");  // NOI18N
044        root.setAttribute("noNamespaceSchemaLocation",  // NOI18N
045                "http://jmri.org/xml/schema/scale.xsd",  // NOI18N
046                org.jdom2.Namespace.getNamespace("xsi",
047                        "http://www.w3.org/2001/XMLSchema-instance"));  // NOI18N
048        Document doc = new Document(root);
049        Element values = new Element("scales");
050
051        root.addContent(values);
052        for (jmri.Scale scale : jmri.ScaleManager.getScales()) {
053            Element e = new Element("scale");  // NOI18N
054            e.addContent(new Element("scale_name").addContent(scale.getScaleName()));  // NOI18N
055            e.addContent(new Element("user_name").addContent(scale.getUserName()));  // NOI18N
056            e.addContent(new Element("scale_ratio").addContent(Double.toString(scale.getScaleRatio())));  // NOI18N
057            values.addContent(e);
058        }
059
060        try {
061            x.writeXML(file, doc);
062        } catch (FileNotFoundException ex) {
063            log.error("File not found when writing", ex);  // NOI18N
064            return false;
065        } catch (IOException ex) {
066            log.error("IO Exception when writing", ex);  // NOI18N
067            return false;
068        }
069
070        return true;
071    }
072
073    /**
074     * Load the Scales from file.
075     * Checks userFilesPath then programPath for resources/scales/ScaleData.xml
076     * @return true on success, else false.
077     */
078    public static boolean doLoad() {
079        ScaleXmlFile x = new ScaleXmlFile();
080        File file = x.getLoadFile();
081        if ( file == null ) {
082            log.error("Scale File {} not located", ScaleXmlFile.FILENAME);
083            return false;
084        }
085
086        // Find root
087        Element root;
088        try {
089            root = x.rootFromFile(file);
090            if (root == null) {
091                log.debug("File could not be read");  // NOI18N
092                return false;
093            }
094
095            Element scales = root.getChild("scales");  // NOI18N
096            if (scales == null) {
097                log.error("Unable to find a scale entry");  // NOI18N
098                return false;
099            }
100            Element e;
101            for (Element scale : scales.getChildren("scale")) {  // NOI18N
102                e = scale.getChild("scale_name");  // NOI18N
103                String scaleName = (e == null) ? "" : e.getValue();
104                e = scale.getChild("user_name");  // NOI18N
105                String userName = (e == null) ? "" : e.getValue();
106                e = scale.getChild("scale_ratio");  // NOI18N
107                double scaleRatio = (e == null) ? 1.0 : Double.parseDouble(e.getValue());
108
109                jmri.ScaleManager.addScale(scaleName, userName, scaleRatio);
110            }
111
112        } catch (JDOMException ex) {
113            log.error("File invalid", ex);  // NOI18N
114            return false;
115        } catch (IOException ex) {
116            log.error("Error reading file", ex);  // NOI18N
117            return false;
118        }
119
120        return true;
121    }
122
123    private static class ScaleXmlFile extends XmlFile {
124        private static final String PROG_PATH = FileUtil.getProgramPath() + "resources/scales/";  // NOI18N
125        private static final String USER_PATH = FileUtil.getUserFilesPath() + "resources/scales/";  // NOI18N
126        private static final String FILENAME = "ScaleData.xml";  // NOI18N
127
128        static String getStoreFileName() {
129            return USER_PATH + FILENAME;
130        }
131
132        @javax.annotation.CheckForNull
133        File getStoreFile() {
134            File chkdir = new File(USER_PATH);
135            if (!chkdir.exists() && !chkdir.mkdirs()) {
136                return null;
137            }
138            File file = findFile(getStoreFileName());
139            if (file == null) {
140                log.info("Create new scale file");  // NOI18N
141                file = new File(getStoreFileName());
142            } else {
143                try {
144                    FileUtil.rotate(file, 4, "bup");  // NOI18N
145                } catch (IOException ex) {
146                    log.warn("Rotate failed, reverting to xml backup");  // NOI18N
147                    makeBackupFile(getStoreFileName());
148                }
149            }
150            return file;
151        }
152
153        @javax.annotation.CheckForNull
154        File getLoadFile() {
155            File file = findFile(USER_PATH + FILENAME);
156            if (file == null) {
157                file = findFile(PROG_PATH + FILENAME);
158            }
159            return file;
160        }
161    }
162
163    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ScaleConfigXML.class);
164
165}