001package jmri.jmrix;
002
003import java.util.List;
004import javax.annotation.CheckForNull;
005import javax.annotation.Nonnull;
006import jmri.InstanceManager;
007import jmri.InstanceManagerAutoDefault;
008import jmri.beans.Bean;
009import jmri.jmrix.internal.InternalSystemConnectionMemo;
010import jmri.SystemConnectionMemo;
011
012/**
013 * Manager for SystemConnectionMemos. Manages SystemConnectionMemos and
014 * SystemConnectionMemo registration with the InstanceManager, ensuring that no
015 * two SystemConnectionMemos have the same username or system connection prefix.
016 * Also provides an object that other objects can listen to for notification of
017 * changes in SystemConnectionMemos.
018 *
019 * @author Randall Wood      Copyright 2017
020 * @author Daniel Bergqvist  Copyright 2022
021 */
022public class SystemConnectionMemoManager extends Bean implements InstanceManagerAutoDefault {
023
024    /**
025     * Property name change fired when a connection is registered. The fired
026     * event has a null old value and the added connection as the new value.
027     */
028    public final static String CONNECTION_ADDED = "ConnectionAdded";
029    /**
030     * Property name change fired when a connection is deregistered. The fired
031     * event has the removed connection as the old value and a null new value.
032     */
033    public final static String CONNECTION_REMOVED = "ConnectionRemoved";
034
035    /**
036     * Register a SystemConnectionMemo in the InstanceManager.
037     *
038     * @param memo the SystemConnectionMemo to register
039     */
040    public void register(SystemConnectionMemo memo) {
041        log.debug("registering connection {}", memo.getUserName());
042
043        // check for special case
044        List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class);
045        int size = list.size();
046        if (size > 0 && (list.get(size - 1) instanceof InternalSystemConnectionMemo)) {
047            // last is internal, so insert before that one
048            log.debug("   putting one before end");
049            SystemConnectionMemo internal = list.get(size - 1);
050            InstanceManager.deregister(internal, SystemConnectionMemo.class);
051            InstanceManager.store(memo, SystemConnectionMemo.class);
052            InstanceManager.store(internal, SystemConnectionMemo.class);
053        } else {
054            // just add on end
055            InstanceManager.store(memo, SystemConnectionMemo.class);
056        }
057        log.trace("fire CONNECTION_ADDED for {}", memo);
058        this.firePropertyChange(CONNECTION_ADDED, null, memo);
059    }
060
061    public void deregister(SystemConnectionMemo memo) {
062        InstanceManager.deregister(memo, SystemConnectionMemo.class);
063        log.trace("fire CONNECTION_REMOVED for {}", memo);
064        firePropertyChange(CONNECTION_REMOVED, memo, null);
065    }
066
067    /**
068     * For a given System UserName AND System Prefix, get the Connection Memo.
069     * Both must match to return the memo.
070     * @param systemPrefix System Prefix to search for.
071     * @param userName system UserName to search for.
072     * @return connection memo, else null if no memo located.
073     */
074    @CheckForNull
075    public synchronized SystemConnectionMemo getSystemConnectionMemo(@Nonnull String systemPrefix, @Nonnull String userName) {
076        for (SystemConnectionMemo memo: InstanceManager.getList(SystemConnectionMemo.class)) {
077            if (memo.getSystemPrefix().equals(systemPrefix) && memo.getUserName().equals(userName)) {
078                return memo;
079            }
080        }
081        return null;
082    }
083
084    /**
085     * For a given System UserName, get the Connection Memo.
086     * @param userName system UserName to search for.
087     * @return connection memo, else null if no memo located.
088     */
089    @CheckForNull
090    public synchronized SystemConnectionMemo getSystemConnectionMemoForUserName(@Nonnull String userName) {
091        for (SystemConnectionMemo memo: InstanceManager.getList(SystemConnectionMemo.class)) {
092            if (memo.getUserName().equals(userName)) {
093                return memo;
094            }
095        }
096        return null;
097    }
098
099    /**
100     * For a given System Prefix, get the Connection Memo.
101     * @param systemPrefix System Prefix to search for.
102     * @return connection memo, else null if no memo located.
103     */
104    @CheckForNull
105    public synchronized SystemConnectionMemo getSystemConnectionMemoForSystemPrefix(@Nonnull String systemPrefix) {
106        for (SystemConnectionMemo memo: InstanceManager.getList(SystemConnectionMemo.class)) {
107            if (memo.getSystemPrefix().equals(systemPrefix)) {
108                return memo;
109            }
110        }
111        return null;
112    }
113
114    /**
115     * Check if a system connection user name is available to be used.
116     *
117     * @param userName the user name to check
118     * @return true if available; false if already in use
119     */
120    public synchronized boolean isUserNameAvailable(@Nonnull String userName) {
121        return InstanceManager.getList(SystemConnectionMemo.class).stream().noneMatch((memo) -> (userName.equals(memo.getUserName())));
122    }
123
124    /**
125     * Check if a system connection prefix for the system names of other objects
126     * is available to be used.
127     *
128     * @param systemPrefix the system prefix to check
129     * @return true if available; false if already in use
130     */
131    public synchronized boolean isSystemPrefixAvailable(@Nonnull String systemPrefix) {
132        return InstanceManager.getList(SystemConnectionMemo.class).stream().noneMatch((memo) -> (memo.getSystemPrefix().equals(systemPrefix)));
133    }
134
135    /**
136     * Get the default instance of this manager.
137     *
138     * @return the default instance, created if needed
139     */
140    public static SystemConnectionMemoManager getDefault() {
141        return InstanceManager.getDefault(SystemConnectionMemoManager.class);
142    }
143
144    /**
145     * Find the connection by its name.
146     * <p>
147     * Example:<br>
148     * LocoNetSystemConnectionMemo memo = getConnection("L2", LocoNetSystemConnectionMemo.class);
149     * </p>
150     * @param <T>                   The type of connection
151     * @param systemConnectionName  The connection name
152     * @param clazz                 The class of the connection type
153     * @return                      The memo if found, null otherwise
154     */
155    @CheckForNull
156    public static <T extends SystemConnectionMemo> T getConnection(
157            @Nonnull String systemConnectionName,
158            @Nonnull Class<T> clazz) {
159
160        List<T> systemConnections = jmri.InstanceManager.getList(clazz);
161
162        for (T memo : systemConnections) {
163            if (memo.getSystemPrefix().equals(systemConnectionName)) {
164                return memo;
165            }
166        }
167
168        // Connection is not found
169        return null;
170    }
171
172    /**
173     * Find the connection by its user name.
174     * <p>
175     * Example:<br>
176     * LocoNetSystemConnectionMemo memo = getConnectionByUserName("LocoNet", LocoNetSystemConnectionMemo.class);
177     * </p>
178     * @param <T>       The type of connection
179     * @param userName  The connection user name
180     * @param clazz     The class of the connection type
181     * @return          The memo if found, null otherwise
182     */
183    @CheckForNull
184    public static <T extends SystemConnectionMemo> T getConnectionByUserName(
185            @Nonnull String userName,
186            @Nonnull Class<T> clazz) {
187
188        List<T> systemConnections = jmri.InstanceManager.getList(clazz);
189
190        for (T memo : systemConnections) {
191            if (memo.getUserName().equals(userName)) {
192                return memo;
193            }
194        }
195
196        // Connection is not found
197        return null;
198    }
199
200    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SystemConnectionMemoManager.class);
201}