001package jmri.jmrix.openlcb;
002
003import java.util.*;
004
005import javax.annotation.Nonnull;
006
007import jmri.StringIO;
008import jmri.jmrix.can.CanSystemConnectionMemo;
009
010/**
011 * Implement a StringIOManager for OpenLCB StringIOs.
012 *
013 * @author Bob Jacobsen      Copyright (C) 2024
014 * @author Daniel Bergqvist  Copyright (C) 2020
015 */
016public class OlcbStringIOManager extends jmri.managers.AbstractStringIOManager {
017
018    // Whether we accumulate partially loaded objects in pendingStringIOs.
019    private boolean isLoading = false;
020    // Turnouts that are being loaded from XML.
021    private final ArrayList<OlcbStringIO> pendingStringIOs = new ArrayList<>();
022
023    public OlcbStringIOManager(CanSystemConnectionMemo memo) {
024        super(memo);
025    }
026
027    /**
028     * {@inheritDoc}
029     */
030    @Override
031    @Nonnull
032    public CanSystemConnectionMemo getMemo() {
033        return (CanSystemConnectionMemo) memo;
034    }
035
036    @Override
037    @Nonnull
038    public StringIO provideStringIO(@Nonnull String sName) throws IllegalArgumentException {
039        String name = sName.substring(getSystemPrefix().length()+1);
040        return new OlcbStringIO(getSystemPrefix(), name, (CanSystemConnectionMemo) memo);
041    }
042
043    /** {@inheritDoc} */
044    @Override
045    @Nonnull
046    public StringIO provide(@Nonnull String name) throws IllegalArgumentException { 
047        return provideStringIO(name); 
048    }
049
050    @Override
051    @Nonnull
052    public StringIO createNewStringIO(String sName, String uName) {
053        String name = sName.substring(getSystemPrefix().length()+1);  // plus one for type letter
054        var s = new OlcbStringIO(getSystemPrefix(), name, (CanSystemConnectionMemo) memo);
055        if (uName != null) s.setUserName(uName);
056        synchronized (pendingStringIOs) {
057            if (isLoading) {
058                pendingStringIOs.add(s);
059            } else {
060                s.finishLoad();
061            }
062        }
063        return s;
064    }
065    
066    /**
067     * This function is invoked before an XML load is started. We defer initialization of the
068     * newly created Sensors until finishLoad because the feedback type might be changing as we
069     * are parsing the XML.
070     */
071    public void startLoad() {
072        log.debug("StringIO manager : start load");
073        synchronized (pendingStringIOs) {
074            isLoading = true;
075        }
076    }
077
078    /**
079     * This function is invoked after the XML load is complete and all Sensors are instantiated
080     * and their feedback type is read in. We use this hook to finalize the construction of the
081     * OpenLCB objects whose instantiation was deferred until the feedback type was known.
082     */
083    public void finishLoad() {
084        log.debug("StringIO manager : finish load");
085        synchronized (pendingStringIOs) {
086            pendingStringIOs.forEach(OlcbStringIO::finishLoad);
087            pendingStringIOs.clear();
088            isLoading = false;
089        }
090    }
091
092    /** {@inheritDoc} */
093    @Override
094    public String getEntryToolTip() {
095        return Bundle.getMessage("AddStringIOEntryToolTip");
096    }
097
098    /**
099     * Validates to OpenLCB format.
100     * {@inheritDoc}
101     */
102    @Override
103    @Nonnull
104    public String validateSystemNameFormat(@Nonnull String name, @Nonnull java.util.Locale locale) throws jmri.NamedBean.BadSystemNameException {
105        name = super.validateSystemNameFormat(name,locale);
106        name = OlcbAddress.validateSystemNameFormat(name,locale,getSystemNamePrefix(), (CanSystemConnectionMemo) memo);
107        return name;
108    }
109
110    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OlcbStringIOManager.class);
111}