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    @Override
050    public int compareTo(NamedBean n2) {
051        Objects.requireNonNull(n2);
052        String o1 = this.getSystemName();
053        String o2 = n2.getSystemName();
054        int p1len = Manager.getSystemPrefixLength(o1);
055        int p2len = Manager.getSystemPrefixLength(o2);
056        int comp = o1.substring(0, p1len).compareTo(o2.substring(0, p2len));
057        if (comp != 0) 
058            return comp;
059        comp = o1.compareTo(o2);
060        return comp;
061    }
062
063    @Override
064    public final void setWhereLastSeen(@CheckForNull Reporter r) {
065        Reporter oldWhere = this.whereLastSeen;
066        Date oldWhen = this.whenLastSeen;
067        this.whereLastSeen = r;
068        if (r != null) {
069            this.whenLastSeen = getDateNow();
070        } else {
071            this.whenLastSeen = null;
072        }
073        setCurrentState(r != null ? SEEN : UNSEEN);
074        firePropertyChange("whereLastSeen", oldWhere, this.whereLastSeen); // NOI18N
075        firePropertyChange("whenLastSeen", oldWhen, this.whenLastSeen);    // NOI18N
076    }
077
078    private Date getDateNow() {
079        return InstanceManager.getDefault(IdTagManager.class).isFastClockUsed()
080            ? InstanceManager.getDefault(ClockControl.class).getTime()
081            : Calendar.getInstance().getTime();
082    }
083
084    private void setCurrentState(int state) {
085        try {
086            setState(state);
087        } catch (JmriException ex) {
088            log.warn("Problem setting state of IdTag {} {}", getSystemName(),ex.getMessage());
089        }
090    }
091
092    @Override
093    public void setState(int s) throws JmriException {
094        this.currentState = s;
095    }
096
097    @Override
098    public int getState() {
099        return this.currentState;
100    }
101
102    @Override
103    public Element store(boolean storeState) {
104        Element e = new Element("idtag"); // NOI18N
105        e.addContent(new Element("systemName").addContent(this.mSystemName)); // NOI18N
106        String uName = this.getUserName();
107        if (uName != null && !uName.isEmpty()) {
108            e.addContent(new Element("userName").addContent(uName)); // NOI18N
109        }
110        String comment = this.getComment();
111        if ((comment != null) && (!comment.isEmpty())) {
112            e.addContent(new Element("comment").addContent(comment)); // NOI18N
113        }
114        Reporter whereLast = this.getWhereLastSeen();
115        if (whereLast != null && storeState) {
116            e.addContent(new Element("whereLastSeen").addContent(whereLast.getSystemName())); // NOI18N
117        }
118        if (this.getWhenLastSeen() != null && storeState) {
119            e.addContent(new Element("whenLastSeen").addContent(new StdDateFormat().format(this.getWhenLastSeen())));
120        }
121        return e;
122    }
123
124    /**
125     * Load an idtag xml element.
126     * whenLastSeen formats accepted JMRI 5.3.6 include
127     * yyyy-MM-dd'T'HH:mm:ss.SSSX
128     * yyyy-MM-dd'T'HH:mm:ss.SSS
129     * EEE, dd MMM yyyy HH:mm:ss zzz
130     * 
131     * @param e element to load.
132     */
133    @Override
134    public void load(Element e) {
135        if (e.getName().equals("idtag")) { // NOI18N
136            log.debug("Load IdTag element for {}", this.getSystemName());
137            if (e.getChild("userName") != null) { // NOI18N
138                this.setUserName(e.getChild("userName").getText()); // NOI18N
139            }
140            if (e.getChild("comment") != null) { // NOI18N
141                this.setComment(e.getChild("comment").getText()); // NOI18N
142            }
143            if (e.getChild("whereLastSeen") != null) { // NOI18N
144                try {
145                    Reporter r = InstanceManager.getDefault(ReporterManager.class)
146                                    .provideReporter(e.getChild("whereLastSeen").getText()); // NOI18N
147                    this.setWhereLastSeen(r);
148                    this.whenLastSeen = null;
149                } catch (IllegalArgumentException ex) {
150                    log.warn("Failed to provide Reporter \"{}\" in load of \"{}\"", e.getChild("whereLastSeen").getText(), getDisplayName());
151                }
152            }
153            if (e.getChild("whenLastSeen") != null) { // NOI18N
154                String lastSeenText = e.getChildText("whenLastSeen");
155                log.debug("Loading {} When Last Seen: {}", getDisplayName(), lastSeenText);
156                try { // parse using ISO 8601 date format
157                    this.whenLastSeen = new StdDateFormat().parse(lastSeenText);
158                } catch (ParseException ex) {
159                    log.debug("ParseException in whenLastSeen ISO attempt: \"{}\"", lastSeenText, ex);
160                    // next, try parse using how it was saved by JMRI < 5.3.5
161                    try {
162                        this.whenLastSeen = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).parse(lastSeenText);
163                    } catch (ParseException ex2) {
164                        log.warn("During load of IdTag \"{}\" {}", getDisplayName(), ex.getMessage());
165                    }
166                }
167            }
168        } else {
169            log.error("Not an IdTag element: \"{}\" for Tag \"{}\"", e.getName(), this.getDisplayName());
170        }
171    }
172
173    private static final Logger log = LoggerFactory.getLogger(DefaultIdTag.class);
174
175}