001package jmri.implementation;
002
003import com.fasterxml.jackson.databind.util.StdDateFormat;
004
005import java.text.*;
006import java.util.Calendar;
007import java.util.Date;
008import java.util.Objects;
009
010import javax.annotation.CheckForNull;
011
012import jmri.*;
013
014import org.jdom2.Element;
015import org.slf4j.Logger;
016import org.slf4j.LoggerFactory;
017
018/**
019 * Concrete implementation of the {@link jmri.IdTag} interface for the Internal
020 * system.
021 * <hr>
022 * This file is part of JMRI.
023 * <p>
024 * JMRI is free software; you can redistribute it and/or modify it under the
025 * terms of version 2 of the GNU General Public License as published by the Free
026 * Software Foundation. See the "COPYING" file for a copy of this license.
027 * <p>
028 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
029 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
030 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
031 *
032 * @author Matthew Harris Copyright (C) 2011
033 * @since 2.11.4
034 */
035public class DefaultIdTag extends AbstractIdTag {
036
037    private int currentState = UNKNOWN;
038
039    public DefaultIdTag(String systemName) {
040        super(systemName);
041        setWhereLastSeen(null);
042    }
043
044    public DefaultIdTag(String systemName, String userName) {
045        super(systemName, userName);
046        setWhereLastSeen(null);
047    }
048
049    public final static String PROPERTY_WHEN_LAST_SEEN = "whenLastSeen";
050    public final static String PROPERTY_WHERE_LAST_SEEN = "whereLastSeen";
051
052    @Override
053    public int compareTo(NamedBean n2) {
054        Objects.requireNonNull(n2);
055        String o1 = this.getSystemName();
056        String o2 = n2.getSystemName();
057        int p1len = Manager.getSystemPrefixLength(o1);
058        int p2len = Manager.getSystemPrefixLength(o2);
059        int comp = o1.substring(0, p1len).compareTo(o2.substring(0, p2len));
060        if (comp != 0) 
061            return comp;
062        comp = o1.compareTo(o2);
063        return comp;
064    }
065
066    @Override
067    public final void setWhereLastSeen(@CheckForNull Reporter r) {
068        Reporter oldWhere = this.whereLastSeen;
069        Date oldWhen = this.whenLastSeen;
070        this.whereLastSeen = r;
071        if (r != null) {
072            this.whenLastSeen = getDateNow();
073        } else {
074            this.whenLastSeen = null;
075        }
076        setCurrentState(r != null ? SEEN : UNSEEN);
077        firePropertyChange(PROPERTY_WHERE_LAST_SEEN, oldWhere, this.whereLastSeen);
078        firePropertyChange(PROPERTY_WHEN_LAST_SEEN, oldWhen, this.whenLastSeen);
079    }
080
081    private Date getDateNow() {
082        return InstanceManager.getDefault(IdTagManager.class).isFastClockUsed()
083            ? InstanceManager.getDefault(ClockControl.class).getTime()
084            : Calendar.getInstance().getTime();
085    }
086
087    private void setCurrentState(int state) {
088        try {
089            setState(state);
090        } catch (JmriException ex) {
091            log.warn("Problem setting state of IdTag {} {}", getSystemName(),ex.getMessage());
092        }
093    }
094
095    @Override
096    public void setState(int s) throws JmriException {
097        this.currentState = s;
098    }
099
100    @Override
101    public int getState() {
102        return this.currentState;
103    }
104
105    @Override
106    public Element store(boolean storeState) {
107        Element e = new Element("idtag"); // NOI18N
108        e.addContent(new Element("systemName").addContent(this.mSystemName)); // NOI18N
109        String uName = this.getUserName();
110        if (uName != null && !uName.isEmpty()) {
111            e.addContent(new Element("userName").addContent(uName)); // NOI18N
112        }
113        String comment = this.getComment();
114        if ((comment != null) && (!comment.isEmpty())) {
115            e.addContent(new Element("comment").addContent(comment)); // NOI18N
116        }
117        Reporter whereLast = this.getWhereLastSeen();
118        if (whereLast != null && storeState) {
119            e.addContent(new Element(PROPERTY_WHERE_LAST_SEEN).addContent(whereLast.getSystemName()));
120        }
121        if (this.getWhenLastSeen() != null && storeState) {
122            e.addContent(new Element(PROPERTY_WHEN_LAST_SEEN).addContent(new StdDateFormat().format(this.getWhenLastSeen())));
123        }
124        return e;
125    }
126
127    /**
128     * Load an idtag xml element.
129     * whenLastSeen formats accepted JMRI 5.3.6 include
130     * yyyy-MM-dd'T'HH:mm:ss.SSSX
131     * yyyy-MM-dd'T'HH:mm:ss.SSS
132     * EEE, dd MMM yyyy HH:mm:ss zzz
133     * 
134     * @param e element to load.
135     */
136    @Override
137    public void load(Element e) {
138        if (e.getName().equals("idtag")) { // NOI18N
139            log.debug("Load IdTag element for {}", this.getSystemName());
140            if (e.getChild("userName") != null) { // NOI18N
141                this.setUserName(e.getChild("userName").getText()); // NOI18N
142            }
143            if (e.getChild("comment") != null) { // NOI18N
144                this.setComment(e.getChild("comment").getText()); // NOI18N
145            }
146            if (e.getChild(PROPERTY_WHERE_LAST_SEEN) != null) {
147                try {
148                    Reporter r = InstanceManager.getDefault(ReporterManager.class)
149                                    .provideReporter(e.getChild(PROPERTY_WHERE_LAST_SEEN).getText());
150                    this.setWhereLastSeen(r);
151                    this.whenLastSeen = null;
152                } catch (IllegalArgumentException ex) {
153                    log.warn("Failed to provide Reporter \"{}\" in load of \"{}\"", e.getChild(PROPERTY_WHERE_LAST_SEEN).getText(), getDisplayName());
154                }
155            }
156            if (e.getChild(PROPERTY_WHEN_LAST_SEEN) != null) {
157                String lastSeenText = e.getChildText(PROPERTY_WHEN_LAST_SEEN);
158                log.debug("Loading {} When Last Seen: {}", getDisplayName(), lastSeenText);
159                try { // parse using ISO 8601 date format
160                    this.whenLastSeen = new StdDateFormat().parse(lastSeenText);
161                } catch (ParseException ex) {
162                    log.debug("ParseException in whenLastSeen ISO attempt: \"{}\"", lastSeenText, ex);
163                    // next, try parse using how it was saved by JMRI < 5.3.5
164                    try {
165                        this.whenLastSeen = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).parse(lastSeenText);
166                    } catch (ParseException ex2) {
167                        log.warn("During load of IdTag \"{}\" {}", getDisplayName(), ex.getMessage());
168                    }
169                }
170            }
171        } else {
172            log.error("Not an IdTag element: \"{}\" for Tag \"{}\"", e.getName(), this.getDisplayName());
173        }
174    }
175
176    private static final Logger log = LoggerFactory.getLogger(DefaultIdTag.class);
177
178}