001package jmri.managers;
002
003import java.util.List;
004import java.util.ArrayList;
005import java.util.SortedSet;
006
007import javax.annotation.CheckForNull;
008import javax.annotation.Nonnull;
009
010import jmri.IdTag;
011import jmri.IdTagManager;
012import jmri.Manager;
013import jmri.Reporter;
014import jmri.InstanceManager;
015import jmri.jmrix.internal.InternalSystemConnectionMemo;
016
017/**
018 * Implementation of a IdTagManager that can serve as a proxy for multiple
019 * system-specific implementations.
020 *
021 * @author Bob Jacobsen Copyright (C) 2010, 2018
022 * @author Dave Duchamp Copyright (C) 2004
023 * @author Paul Bender Copyright (C) 2019
024 */
025public class ProxyIdTagManager extends AbstractProvidingProxyManager<IdTag>
026        implements IdTagManager {
027
028    public ProxyIdTagManager() {
029        super();
030    }
031
032    @Override
033    public int getXMLOrder() {
034        return jmri.Manager.IDTAGS;
035    }
036
037    @Override
038    public void init() {
039        if (!isInitialised()) {
040            getDefaultManager().init();
041        }
042    }
043
044    /**
045     * {@inheritDoc}
046     * @return true if All IdTagManagers have initialised.
047     */
048    @Override
049    public boolean isInitialised() {
050        return defaultManager!= null &&
051                getManagerList().stream().allMatch(o->((IdTagManager)o).isInitialised());
052    }
053
054    /**
055     * {@inheritDoc}
056     *
057     * This returns the specific IdTagManager type.
058     */
059    @Override
060    @Nonnull
061    public IdTagManager getDefaultManager() {
062        if(defaultManager != getInternalManager()){
063           defaultManager = getInternalManager();
064        }
065        return (IdTagManager) defaultManager;
066    }
067
068    @Override
069    protected AbstractManager<IdTag> makeInternalManager() {
070        // since this really is an internal tracking mechanisim,
071        // build the new manager and add it here.
072        DefaultIdTagManager tagMan = new DefaultIdTagManager(InstanceManager.getDefault(InternalSystemConnectionMemo.class));
073        InstanceManager.setIdTagManager(tagMan);
074        return tagMan;
075    }
076
077    /**
078     * Locate via user name, then system name if needed.
079     *
080     * @return Null if nothing by that name exists
081     */
082    @CheckForNull
083    @Override
084    public IdTag getIdTag(@Nonnull String name) {
085        init();
086        return super.getNamedBean(name);
087    }
088
089    /** {@inheritDoc} */
090    @Override
091    @Nonnull
092    public SortedSet<IdTag> getNamedBeanSet() {
093        init();
094        return super.getNamedBeanSet();
095    }
096
097    @Nonnull
098    @Override
099    protected IdTag makeBean(Manager<IdTag> manager, String systemName, String userName) throws IllegalArgumentException{
100        init();
101        return ((IdTagManager) manager).newIdTag(systemName, userName);
102    }
103
104    /**
105     * {@inheritDoc}
106     */
107    @Override
108    @Nonnull
109    public IdTag provide(@Nonnull String name) throws IllegalArgumentException {
110        return provideIdTag(name);
111    }
112
113    /**
114     * Locate via user name, then system name if needed. If that fails, create a
115     * new IdTag: If the name is a valid system name, it will be used for the
116     * new IdTag. Otherwise, the makeSystemName method will attempt to turn it
117     * into a valid system name.
118     *
119     * @return Never null under normal circumstances
120     */
121    @Override
122    @Nonnull
123    public IdTag provideIdTag(@Nonnull String name) throws IllegalArgumentException {
124        init();
125        return super.provideNamedBean(name);
126    }
127
128    /**
129     * Get an instance with the specified system and user names. Note that
130     * two calls with the same arguments will get the same instance; there is
131     * only one IdTag object representing a given physical light and therefore
132     * only one with a specific system or user name.
133     * <p>
134     * This will always return a valid object reference for a valid request; a
135     * new object will be created if necessary. In that case:
136     * <ul>
137     * <li>If a null reference is given for user name, no user name will be
138     * associated with the IdTag object created; a valid system name must be
139     * provided
140     * <li>If a null reference is given for the system name, a system name will
141     * _somehow_ be inferred from the user name. How this is done is system
142     * specific. Note: a future extension of this interface will add an
143     * exception to signal that this was not possible.
144     * <li>If both names are provided, the system name defines the hardware
145     * access of the desired turnout, and the user address is associated with
146     * it.
147     * </ul>
148     * Note that it is possible to make an inconsistent request if both
149     * addresses are provided, but the given values are associated with
150     * different objects. This is a problem, and we don't have a good solution
151     * except to issue warnings. This will mostly happen if you're creating
152     * IdTags when you should be looking them up.
153     *
154     * @return requested IdTag object (never null)
155     */
156    @Override
157    @Nonnull
158    public IdTag newIdTag(@Nonnull String systemName, String userName) throws IllegalArgumentException {
159        init();
160        return newNamedBean(systemName, userName);
161    }
162
163    @CheckForNull
164    @Override
165    public IdTag getByTagID(@Nonnull String tagID) {
166        init();
167        return getBySystemName(makeSystemName(tagID));
168    }
169
170    @Override
171    @Nonnull
172    public String getBeanTypeHandled(boolean plural) {
173        return Bundle.getMessage(plural ? "BeanNameIdTags" : "BeanNameIdTag");
174    }
175
176    /**
177     * {@inheritDoc}
178     */
179    @Override
180    public Class<IdTag> getNamedBeanClass() {
181        return IdTag.class;
182    }
183
184    private boolean stateSaved = false;
185
186    @Override
187    public void setStateStored(boolean state) {
188        stateSaved = state;
189        for (Manager<IdTag> mgr : getManagerList()) {
190            ((IdTagManager) mgr).setStateStored(state);
191        }
192    }
193
194    @Override
195    public boolean isStateStored() {
196        stateSaved = true;
197        for (Manager<IdTag> mgr: getManagerList()) {
198            if(!((IdTagManager) mgr).isStateStored()) {
199                stateSaved = false;
200                break;
201            }
202        }
203        return stateSaved;
204    }
205
206    private boolean useFastClock = false;
207
208    @Override
209    public void setFastClockUsed(boolean fastClock) {
210        useFastClock = fastClock;
211        for (Manager<IdTag> mgr : getManagerList()) {
212            ((IdTagManager) mgr).setFastClockUsed(fastClock);
213        }
214    }
215
216    @Override
217    public boolean isFastClockUsed() {
218        useFastClock = true;
219        for (Manager<IdTag> mgr: getManagerList()) {
220            if (!((IdTagManager) mgr).isFastClockUsed()) {
221               useFastClock = false;
222               break;
223            }
224        }
225        return useFastClock;
226    }
227
228    @Override
229    @Nonnull
230    public List<IdTag> getTagsForReporter(@Nonnull Reporter reporter, long threshold) {
231        init();
232        List<IdTag> out = new ArrayList<>();
233        for (Manager<IdTag> mgr: getManagerList()) {
234            out.addAll(((IdTagManager)mgr).getTagsForReporter(reporter, threshold));
235        }
236        return out;
237    }
238
239}