001package jmri.jmrit.logix;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.beans.PropertyChangeSupport;
006import java.util.*;
007import javax.annotation.Nonnull;
008import javax.annotation.OverridingMethodsMustInvokeSuper;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013/**
014 * Basic implementation of a PortalManager.
015 * <p>
016 * Note that this does not enforce any particular system naming convention.
017 * <p>
018 * Note this is an 'after thought' manager. Portals have been in use since 2009.
019 * Their use has now expanded well beyond what was expected. A Portal factory is
020 * needed for development to continue.
021 *
022 * Portal system names will be numbers and they will not be shown to users. The
023 * UI will treat Portal names as it does now as user names.
024 *
025 * <hr>
026 * This file is part of JMRI.
027 * <p>
028 * JMRI is free software; you can redistribute it and/or modify it under the
029 * terms of version 2 of the GNU General Public License as published by the Free
030 * Software Foundation. See the "COPYING" file for a copy of this license.
031 * <p>
032 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
033 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
034 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
035 *
036 * @author Pete Cressman Copyright (C) 2014
037 */
038public class PortalManager implements jmri.InstanceManagerAutoDefault, PropertyChangeListener {
039
040    private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
041    private ArrayList<Portal> _nameList = new ArrayList<>();          // stores Portal in loaded order
042    private HashMap<String, Portal> _portalMap = new HashMap<>(); // stores portal by current name
043    private Integer _nextIndex = 1;
044
045    public PortalManager() {
046        // no setup currently required
047    }
048
049    public int getPortalCount() {
050        return _nameList.size();
051    }
052
053    public Portal getPortal(int idx) {
054        return _nameList.get(idx);
055    }
056
057    public int getIndexOf(Portal portal) {
058        return _nameList.indexOf(portal);
059    }
060
061    public Portal getPortal(String name) {
062        return _portalMap.get(name);
063    }
064
065    public Collection<Portal> getPortalSet() {
066        return Collections.unmodifiableCollection(_nameList);
067    }
068
069    /*
070     * Create a new Portal with a given user name.
071     *
072     * @return null if a Portal with the same userName already exists,
073     * or if an empty userName was requested
074     */
075    public Portal createNewPortal(@Nonnull String userName) {
076        java.util.Objects.requireNonNull(userName, "Name cannot be null");
077        // Check that Portal does not already exist
078        Portal portal;
079        if (userName.trim().length() > 0) {
080            portal = _portalMap.get(userName);
081            if (portal != null) {
082                return null;
083            }
084        } else {  // must have a user name for backward compatibility
085            return null;
086        }
087        // Portal does not exist, create a new Portal
088        portal = new Portal(userName);
089        // save in the maps
090        _nameList.add(portal);
091        _portalMap.put(userName, portal);
092        _nextIndex = _nextIndex + 1;
093        pcs.firePropertyChange("numPortals", null, _nameList.size());
094        // listen for name and state changes to forward
095        portal.addPropertyChangeListener(this);
096        return portal;
097    }
098
099    public Portal providePortal(String name) {
100        if (name == null || name.trim().length() == 0) {
101            return null;
102        }
103        Portal portal = getPortal(name);
104        if (portal == null) {
105            portal = createNewPortal(name);
106        }
107        return portal;
108    }
109
110    private synchronized void deletePortal(Portal portal) {
111        String name = portal.getName();
112        _nameList.remove(portal);
113        _portalMap.remove(name);
114        pcs.firePropertyChange("numPortals", portal, _nameList.size());
115    }
116
117    @OverridingMethodsMustInvokeSuper
118    public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
119        pcs.addPropertyChangeListener(l);
120    }
121
122    @OverridingMethodsMustInvokeSuper
123    public synchronized void removePropertyChangeListener(PropertyChangeListener l) {
124        pcs.removePropertyChangeListener(l);
125    }
126
127    @Override
128    public void propertyChange(PropertyChangeEvent e) {
129        if (!(e.getSource() instanceof Portal)) {
130            return;
131        }
132        Portal portal = (Portal)e.getSource();
133        String propertyName = e.getPropertyName();
134        log.debug("property = {}", propertyName);
135        if (propertyName.equals("portalDelete")) {
136            deletePortal(portal);
137        }
138    }
139
140    private static final Logger log = LoggerFactory.getLogger(PortalManager.class);
141
142}