001package jmri.jmrix.openlcb;
002
003import java.util.ArrayList;
004import java.util.List;
005import javax.annotation.Nonnull;
006import jmri.BooleanPropertyDescriptor;
007import jmri.Light;
008import jmri.NamedBean;
009import jmri.NamedBeanPropertyDescriptor;
010import jmri.managers.AbstractLightManager;
011import jmri.jmrix.can.CanSystemConnectionMemo;
012import org.openlcb.OlcbInterface;
013
014/**
015 *
016 * @author jcollell
017 */
018public class OlcbLightManager extends AbstractLightManager {
019
020    public OlcbLightManager(CanSystemConnectionMemo memo) {
021        super(memo);
022    }
023    
024    // Whether we accumulate partially loaded lights in pendingLights.
025    private boolean isLoading = false;
026    // Lights that are being loaded from XML.
027    private final ArrayList<OlcbLight> pendingLights = new ArrayList<>();
028
029    /**
030     * {@inheritDoc}
031     */
032    @Override
033    @Nonnull
034    public CanSystemConnectionMemo getMemo() {
035        return (CanSystemConnectionMemo) memo;
036    }
037
038    @Override
039    @Nonnull
040    public List<NamedBeanPropertyDescriptor<?>> getKnownBeanProperties() {
041        List<NamedBeanPropertyDescriptor<?>> l = new ArrayList<>();
042        l.add(new BooleanPropertyDescriptor(OlcbUtils.PROPERTY_IS_AUTHORITATIVE, OlcbLight
043                .DEFAULT_IS_AUTHORITATIVE) {
044            @Override
045            public String getColumnHeaderText() {
046                return Bundle.getMessage("OlcbStateAuthHeader");
047            }
048
049            @Override
050            public boolean isEditable(NamedBean bean) {
051                return OlcbUtils.isOlcbBean(bean);
052            }
053        });
054        l.add(new BooleanPropertyDescriptor(OlcbUtils.PROPERTY_LISTEN, OlcbLight
055                .DEFAULT_LISTEN) {
056            @Override
057            public String getColumnHeaderText() {
058                return Bundle.getMessage("OlcbStateListenHeader");
059            }
060
061            @Override
062            public boolean isEditable(NamedBean bean) {
063                return OlcbUtils.isOlcbBean(bean);
064            }
065        });
066        return l;
067    }
068
069    /**
070     * Internal method to invoke the factory, after all the logic for returning
071     * an existing method has been invoked.
072     *
073     * @return never null
074     */
075    @Override
076    @Nonnull
077    protected Light createNewLight(@Nonnull String systemName, String userName) throws IllegalArgumentException {
078        String addr = systemName.substring(getSystemPrefix().length() + 1);
079        OlcbLight l = new OlcbLight(getSystemPrefix(), addr, memo.get(OlcbInterface.class));
080        l.setUserName(userName);
081        synchronized (pendingLights) {
082            if (isLoading) {
083                pendingLights.add(l);
084            } else {
085                l.finishLoad();
086            }
087        }
088        return l;
089    }
090
091    /**
092     * This function is invoked before an XML load is started. We defer initialization of the
093     * newly created lights until finishLoad because the feedback type might be changing as we
094     * are parsing the XML.
095     */
096    public void startLoad() {
097        synchronized (pendingLights) {
098            isLoading = true;
099        }
100    }
101
102    /**
103     * This function is invoked after the XML load is complete and all lights are instantiated
104     * and their feedback type is read in. We use this hook to finalize the construction of the
105     * OpenLCB objects whose instantiation was deferred until the feedback type was known.
106     */
107    public void finishLoad() {
108        synchronized (pendingLights) {
109            for (OlcbLight l : pendingLights) {
110                l.finishLoad();
111            }
112            pendingLights.clear();
113            isLoading = false;
114        }
115    }
116
117    @Override
118    public boolean allowMultipleAdditions(@Nonnull String systemName) {
119        return false;
120    }
121
122    @Override
123    public boolean validSystemNameConfig(@Nonnull String address) throws IllegalArgumentException {
124        
125        if (address.startsWith("+") || address.startsWith("-")) {
126            return false;
127        }
128        try {
129            OlcbAddress.validateSystemNameFormat(address,java.util.Locale.getDefault(),getSystemNamePrefix());
130        }
131        catch ( jmri.NamedBean.BadSystemNameException ex ){
132            throw new IllegalArgumentException(ex.getMessage());
133        }
134        return true;
135    }
136    
137    /**
138     * Validates to OpenLCB format.
139     * {@inheritDoc}
140     */
141    @Override
142    @Nonnull
143    public String validateSystemNameFormat(@Nonnull String name, @Nonnull java.util.Locale locale) throws jmri.NamedBean.BadSystemNameException {
144        super.validateSystemNameFormat(name,locale);
145        name = OlcbAddress.validateSystemNameFormat(name,locale,getSystemNamePrefix());
146        return name;
147    }
148    
149    /**
150     * {@inheritDoc}
151     */
152    @Override
153    public String getEntryToolTip() {
154        return Bundle.getMessage("AddLightEntryToolTip");
155    }
156}