001package jmri.jmrix.can.cbus.eventtable;
002
003import java.io.File;
004import java.io.IOException;
005import java.text.SimpleDateFormat;
006import java.util.Date;
007import jmri.util.FileUtil;
008import org.jdom2.Document;
009import org.jdom2.Element;
010import org.jdom2.JDOMException;
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014/**
015 * Save / Load routines for the EventTableData.xml file.
016 * @author Steve Young Copyright (C) 2019
017 */
018public class CbusEventTableXmlAction {
019
020    protected static SimpleDateFormat getXmlDateStyle() {
021        return new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
022    }
023
024    // if a CBUS Event xml file is found
025    // import table data into it
026    protected static void restoreEventsFromXmlTablestart(CbusEventTableDataModel model) {
027        log.debug("restore events from conn {}",model._memo);
028        CbusEventTableXmlFile x = new CbusEventTableXmlFile(model._memo);
029        File file = x.getFile(false);
030        if (file == null) {
031            return;
032        }
033
034        try {
035            Element root = x.rootFromFile(file);
036            root.getChildren("Event").forEach((xmlEvent) -> addSingleEventToModel(xmlEvent, model));
037            model.fireTableDataChanged();
038            FileUtil.rotate(file, 10, "bup");  // NOI18N
039
040        } catch (JDOMException | IOException ex) {
041            log.error("File Error", ex);  // NOI18N
042        }
043    }
044
045    private static void addSingleEventToModel(Element xmlEvent, CbusEventTableDataModel model) {
046
047        if (xmlEvent.getAttribute("NodeNum") == null || xmlEvent.getAttribute("EventNum") == null ) { // NOI18N
048            log.error("Node or event number missing in event {}", xmlEvent.getAttributes() );
049        } else try {
050
051            CbusTableEvent tabEv = model.provideEvent(
052             Integer.parseInt( xmlEvent.getAttribute("NodeNum").getValue() ),
053             Integer.parseInt( xmlEvent.getAttribute("EventNum").getValue() )); // NOI18N
054
055            if (xmlEvent.getChild("Name") != null ) { // NOI18N
056                tabEv.setName( xmlEvent.getChild("Name").getValue() ); // NOI18N
057            }
058            if (xmlEvent.getChild("Comment") != null ) { // NOI18N
059                tabEv.setComment( xmlEvent.getChild("Comment").getValue() ); // NOI18N
060            }
061
062            setEventDate(xmlEvent.getChild("LastHeard"), tabEv); // NOI18N
063
064            tabEv.setCounts(getChild(xmlEvent, "On"), getChild(xmlEvent, "Off"),
065                    getChild(xmlEvent, "In"), getChild(xmlEvent, "Out")); // NOI18N
066
067        } catch (java.lang.NumberFormatException ex) {
068            log.error("Incorrect value in event {}", xmlEvent.getAttributes()); // NOI18N
069        }
070
071    }
072
073    private static void setEventDate(Element element, CbusTableEvent tabEv){
074        if ( element != null ) { // NOI18N
075            try {
076                Date newDate = getXmlDateStyle().parse(element.getValue()); // NOI18N
077                tabEv.setDate( newDate );
078            } catch (java.text.ParseException e) {
079                log.error("Unable to parse date {}", element.getValue()); // NOI18N
080            }
081        }
082    }
083
084    private static int getChild(Element element, String child){
085        if (element.getChild(child) != null ) { // NOI18N
086            return  ( Integer.parseInt( element.getChild(child).getValue() ) ); // NOI18N
087        }
088        return 0;
089    }
090
091    /**
092     * Saves table event data to the EventTableData.xml file.
093     * @param model Table Model to save.
094     */
095    protected static void storeEventsToXml(CbusEventTableDataModel model) {
096        layoutEventsToXml(model);
097    }
098
099    private static void layoutEventsToXml(CbusEventTableDataModel model) {
100
101        log.info("Saving {} CBUS Event xml file.", model._memo.getUserName() ); // NOI18N
102        CbusEventTableXmlFile x = new CbusEventTableXmlFile(model._memo);
103
104        Element root = new Element("CbusEventDetails"); // NOI18N
105        root.setAttribute("noNamespaceSchemaLocation",  // NOI18N
106            "https://raw.githubusercontent.com/MERG-DEV/JMRI/master/schema/MergCBUSEventTable.xsd",  // NOI18N
107            org.jdom2.Namespace.getNamespace("xsi",
108            "http://www.w3.org/2001/XMLSchema-instance"));  // NOI18N
109
110        model.getEvents().forEach((event) -> addSingleEventToXml(event, root));
111
112        try {
113            x.writeXML(x.getFile(true), new Document(root));
114        } catch ( IOException ex) {
115            log.error("File Error while writing", ex);  // NOI18N
116        }
117    }
118
119    private static void addSingleEventToXml(CbusTableEvent event, Element root){
120
121        Element values = new Element("Event"); // NOI18N
122        root.addContent(values);
123        values.setAttribute("NodeNum", "" + event.getNn() ); // NOI18N
124        values.setAttribute("EventNum", "" + event.getEn() ); // NOI18N
125        if ( !event.getName().isEmpty() ){
126            values.addContent(new Element("Name").addContent("" + event.getName() )); // NOI18N
127        }
128        if ( !event.getComment().isEmpty() ){
129            values.addContent(new Element("Comment").addContent("" + event.getComment() )); // NOI18N
130        }
131        if ( event.getDate() != null ){
132            values.addContent(new Element("LastHeard").addContent(
133                    "" + getXmlDateStyle().format(  event.getDate() ) )); // NOI18N
134        }
135
136        addIntContent(event.getTotalOnOff(true), "On", values); // NOI18N
137        addIntContent(event.getTotalOnOff(false), "Off", values); // NOI18N
138        addIntContent(event.getTotalInOut(true), "In", values); // NOI18N
139        addIntContent(event.getTotalInOut(false), "Out", values); // NOI18N
140
141    }
142
143    private static void addIntContent(int val, String name, Element values){
144        if (val > 0) {
145            values.addContent(new Element(name).addContent("" + val ));  // NOI18N
146        }
147    }
148
149    private final static Logger log = LoggerFactory.getLogger(CbusEventTableXmlAction.class);
150
151}