001package jmri.jmrit.simpleclock.configurexml;
002
003import java.text.ParseException;
004import java.text.SimpleDateFormat;
005import java.util.Locale;
006import jmri.InstanceManager;
007import jmri.Timebase;
008import org.jdom2.Element;
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012import static jmri.Timebase.ClockInitialRunState.DO_NOTHING;
013import static jmri.Timebase.ClockInitialRunState.DO_START;
014import static jmri.Timebase.ClockInitialRunState.DO_STOP;
015
016/**
017 * Handle XML persistance of SimpleTimebase objects.
018 *
019 * @author Bob Jacobsen Copyright (c) 2003, 2008, 2017
020 */
021public class SimpleTimebaseXml extends jmri.configurexml.AbstractXmlAdapter {
022
023    public SimpleTimebaseXml() {
024    }
025
026    /**
027     * Default implementation for storing the contents of a SimpleTimebase.
028     *
029     * @param o Object to start process, but not actually used
030     * @return Element containing the complete info
031     */
032    @Override
033    public Element store(Object o) {
034
035        Timebase clock = InstanceManager.getDefault(jmri.Timebase.class);
036
037        Element elem = new Element("timebase");
038        elem.setAttribute("class", this.getClass().getName());
039
040        var loadAndStorePreferences = InstanceManager.getDefault(jmri.configurexml.LoadAndStorePreferences.class);
041        if (! loadAndStorePreferences.isExcludeTimebase() ) {
042            elem.setAttribute("time", clock.getStartTime().toString());
043        }
044
045        elem.setAttribute("rate", "" + clock.userGetRate());
046        elem.setAttribute("startrate", "" + clock.getStartRate());
047        elem.setAttribute("run", (clock.getClockInitialRunState() == DO_START ? "yes" : "no"));
048        elem.setAttribute("master", (clock.getInternalMaster() ? "yes" : "no"));
049        if (!clock.getInternalMaster()) {
050            elem.setAttribute("mastername", clock.getMasterName());
051        }
052        elem.setAttribute("sync", (clock.getSynchronize() ? "yes" : "no"));
053        elem.setAttribute("correct", (clock.getCorrectHardware() ? "yes" : "no"));
054        elem.setAttribute("display", (clock.use12HourDisplay() ? "yes" : "no"));
055        elem.setAttribute("startstopped", (clock.getClockInitialRunState() == DO_STOP ? "yes" : "no"));
056        elem.setAttribute("startrunning", ((clock.getClockInitialRunState() == DO_START) ? "yes" : "no"));
057        elem.setAttribute("startsettime", (clock.getStartSetTime() ? "yes" : "no"));
058        elem.setAttribute("startclockoption", Integer.toString(
059                clock.getStartClockOption()));
060        elem.setAttribute("showbutton", (clock.getShowStopButton() ? "yes" : "no"));
061        elem.setAttribute("startsetrate", (clock.getSetRateAtStart() ? "yes" : "no"));
062
063        return elem;
064    }
065
066    @Override
067    public boolean load(Element shared, Element perNode) {
068        boolean result = true;
069        Timebase clock = InstanceManager.getDefault(jmri.Timebase.class);
070        String val, val2;
071        if (shared.getAttribute("master") != null) {
072            val = shared.getAttributeValue("master");
073            if (val.equals("yes")) {
074                clock.setInternalMaster(true, false);
075            }
076            if (val.equals("no")) {
077                clock.setInternalMaster(false, false);
078                if (shared.getAttribute("mastername") != null) {
079                    clock.setMasterName(shared.getAttributeValue("mastername"));
080                }
081            }
082        }
083        if (shared.getAttribute("sync") != null) {
084            val = shared.getAttributeValue("sync");
085            if (val.equals("yes")) {
086                clock.setSynchronize(true, false);
087            }
088            if (val.equals("no")) {
089                clock.setSynchronize(false, false);
090            }
091        }
092        if (shared.getAttribute("correct") != null) {
093            val = shared.getAttributeValue("correct");
094            if (val.equals("yes")) {
095                clock.setCorrectHardware(true, false);
096            }
097            if (val.equals("no")) {
098                clock.setCorrectHardware(false, false);
099            }
100        }
101        if (shared.getAttribute("display") != null) {
102            val = shared.getAttributeValue("display");
103            if (val.equals("yes")) {
104                clock.set12HourDisplay(true, false);
105            }
106            if (val.equals("no")) {
107                clock.set12HourDisplay(false, false);
108            }
109        }
110        if (shared.getAttribute("showbutton") != null) {
111            val = shared.getAttributeValue("showbutton");
112            if (val.equals("yes")) {
113                clock.setShowStopButton(true);
114            }
115            if (val.equals("no")) {
116                clock.setShowStopButton(false);
117            }
118        }
119        if ("yes".equals(shared.getAttributeValue("startrunning"))) {
120            clock.setRun(true);
121            clock.setClockInitialRunState(DO_START);
122        } else if ("yes".equals(shared.getAttributeValue("startstopped"))) {
123            clock.setRun(false);
124            clock.setClockInitialRunState(DO_STOP);
125        } else if (shared.getAttribute("startrunning") != null){
126            clock.setClockInitialRunState(DO_NOTHING);
127        } else {
128            // legacy XML
129            if (shared.getAttribute("run") != null) {
130                val = shared.getAttributeValue("run");
131                if (val.equals("yes")) {
132                    clock.setRun(true);
133                    clock.setClockInitialRunState(DO_START);
134                }
135                if (val.equals("no")) {
136                    clock.setRun(false);
137                    clock.setClockInitialRunState(DO_STOP);
138                }
139            }
140        }
141        if (shared.getAttribute("startsetrate") != null) {
142            val = shared.getAttributeValue("startsetrate");
143            clock.setSetRateAtStart(!val.equals("no"));
144        }
145        boolean hasRate = false;
146        if (shared.getAttribute("startrate") != null) {
147            try {
148                double r = shared.getAttribute("startrate").getDoubleValue();
149                clock.setStartRate(r);
150                hasRate = true;
151            } catch (org.jdom2.DataConversionException e2) {
152                log.error("Cannot convert start rate", e2);
153                result = false;
154            }
155        }
156        if (!hasRate && shared.getAttribute("rate") != null) {
157            try {
158                double r = shared.getAttribute("rate").getDoubleValue();
159                clock.setStartRate(r);
160                hasRate = true;
161            } catch (org.jdom2.DataConversionException e2) {
162                log.error("Cannot convert rate", e2);
163                result = false;
164            }
165        }
166        if (clock.getSetRateAtStart() && hasRate) {
167            try {
168                clock.userSetRate(clock.getStartRate());
169            } catch (jmri.TimebaseRateException e1) {
170                log.error("Cannot restore rate: {}", clock.getStartRate(), e1);
171                result = false;
172            }
173        }
174        if (shared.getAttribute("startsettime") != null) {
175            val = shared.getAttributeValue("startsettime");
176            if (val.equals("yes")) {
177                if (shared.getAttribute("time") != null) {
178                    val2 = shared.getAttributeValue("time");
179                    try {
180                        clock.setStartSetTime(true, format.parse(val2));
181                        clock.setTime(format.parse(val2));
182                    } catch (ParseException e) {
183                        // if non-invertable date format, just skip
184                        log.warn("Cannot set date using value stored in file: {}", val2);
185                        result = false;
186                    }
187                }
188            } else if (val.equals("no")) {
189                if (shared.getAttribute("time") != null) {
190                    val2 = shared.getAttributeValue("time");
191                    try {
192                        clock.setStartSetTime(false, format.parse(val2));
193                    } catch (ParseException e) {
194                        // if non-invertable date format, just skip
195                        log.warn("Cannot set date using value stored in file: {}", val2);
196                        result = false;
197                    }
198                }
199            }
200        } else if (shared.getAttribute("time") != null) {
201            // this only to preserve previous behavior for preexisting files
202            val2 = shared.getAttributeValue("time");
203            try {
204                clock.setStartSetTime(true, format.parse(val2));
205                clock.setTime(format.parse(val2));
206            } catch (ParseException e) {
207                // if non-invertable date format, just skip
208                log.warn("Cannot set date using value stored in file: {}", val2);
209                result = false;
210            }
211        }
212        if (shared.getAttribute("startclockoption") != null) {
213            int option = Integer.parseInt(shared.getAttribute(
214                    "startclockoption").getValue());
215            clock.setStartClockOption(option);
216            clock.initializeClock();
217        }
218        clock.initializeHardwareClock();
219        return result;
220    }
221
222    // Conversion format for dates created by Java Date.toString().
223    // The Locale needs to be always US, irrelevant from computer's and program's settings!
224    final SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
225
226    @Override
227    public int loadOrder() {
228        return jmri.Manager.TIMEBASE;
229    }
230
231    private final static Logger log = LoggerFactory.getLogger(SimpleTimebaseXml.class);
232
233}