001package jmri.jmrit.automat;
002
003import java.util.ArrayList;
004
005/**
006 * A singlet providing access to information about existing Automat instances.
007 * <p>
008 * It might not always be a singlet, however, so for now we're going through an
009 * explicit instance() reference.
010 * <p>
011 * This can be invoked from various threads, so switches to the Swing thread to
012 * notify its own listeners.
013 *
014 * @author Bob Jacobsen Copyright (C) 2004, 2007
015 */
016public class AutomatSummary {
017
018    private AutomatSummary() {
019    }
020
021    static volatile private AutomatSummary self = null;
022
023    static public AutomatSummary instance() {
024        if (self == null) {
025            self = new AutomatSummary();
026        }
027        return self;
028    }
029
030    private final ArrayList<AbstractAutomaton> automats = new ArrayList<>();
031
032    java.beans.PropertyChangeSupport prop = new java.beans.PropertyChangeSupport(this);
033
034    public void removePropertyChangeListener(java.beans.PropertyChangeListener p) {
035        prop.removePropertyChangeListener(p);
036    }
037
038    public void addPropertyChangeListener(java.beans.PropertyChangeListener p) {
039        prop.addPropertyChangeListener(p);
040    }
041
042    /**
043     * A newly-created AbstractAutomaton instance uses this method to notify
044     * interested parties of its existence.
045     *
046     * @param a the automaton to register
047     */
048    public void register(AbstractAutomaton a) {
049        synchronized (automats) {
050            automats.add(a);
051        }
052
053        //notify length changed
054        notify("Insert", null, indexOf(a));
055
056    }
057
058    /**
059     * Just before exiting, an AbstractAutomaton instance uses this method to
060     * notify interested parties of its departure.
061     *
062     * @param a the automaton to remove
063     */
064    public void remove(AbstractAutomaton a) {
065        int index = indexOf(a);
066
067        synchronized (automats) {
068            automats.remove(a);
069        }
070
071        //notify length changed
072        notify("Remove", null, index);
073    }
074    
075    public ArrayList<AbstractAutomaton> getAutomats() {
076        return new ArrayList<>(automats);
077    }
078
079    public int length() {
080        int length;
081        synchronized (automats) {
082            length = automats.size();
083        }
084        return length;  // debugging value
085    }
086
087    public AbstractAutomaton get(int i) {
088        AbstractAutomaton retval;
089
090        synchronized (automats) {
091            retval = automats.get(i);
092        }
093
094        return retval;
095    }
096
097    /**
098     * Provide a convenience method to look up a managed object by its name.
099     *
100     * @since 1.7.3
101     * @param name Name of the automat to be located
102     * @return null if name not found
103     */
104    public AbstractAutomaton get(String name) {
105        AbstractAutomaton a;
106        synchronized (automats) {
107            for (int i = 0; i < length(); i++) {
108                a = automats.get(i);
109                if (a.getName().equals(name)) {
110                    return a;
111                }
112            }
113        }
114        return null;
115    }
116
117    public int indexOf(AbstractAutomaton a) {
118        int retval;
119        synchronized (automats) {
120            retval = automats.indexOf(a);
121        }
122        return retval;
123    }
124
125    /**
126     * An AbstractAutomaton instance uses this method to notify interested
127     * parties that it's gone around its handle loop again.
128     *
129     * @param a the looping automaton
130     */
131    public void loop(AbstractAutomaton a) {
132        int i;
133        synchronized (automats) {
134            i = automats.indexOf(a);
135        }
136        notify("Count", null, i);
137    }
138
139    void notify(String property, Object arg1, Object arg2) {
140        Runnable r = new Notifier(property, arg1, arg2);
141        javax.swing.SwingUtilities.invokeLater(r);
142    }
143
144    class Notifier implements Runnable {
145
146        Notifier(String property, Object arg1, Object arg2) {
147            this.property = property;
148            this.arg1 = arg1;
149            this.arg2 = arg2;
150        }
151        Object arg1;
152        Object arg2;
153        String property;
154
155        @Override
156        public void run() {
157            prop.firePropertyChange(property, arg1, arg2);
158        }
159
160    }
161}