001package jmri.jmrit.logixng.implementation;
002
003import java.util.*;
004
005import jmri.*;
006import jmri.jmrit.logixng.ConditionalNG;
007import jmri.jmrit.logixng.GlobalVariable;
008import jmri.jmrit.logixng.GlobalVariableManager;
009import jmri.jmrit.logixng.Module.Parameter;
010import jmri.jmrit.logixng.Stack;
011import jmri.jmrit.logixng.SymbolTable;
012
013/**
014 * The default implementation of a NamedTable
015 *
016 * @author Daniel Bergqvist 2020
017 */
018public class DefaultSymbolTable implements SymbolTable {
019
020    private final SymbolTable _prevSymbolTable;
021    private final Stack _stack;
022    private final int _firstSymbolIndex;
023    private final Map<String, Symbol> _symbols = new HashMap<>();
024
025
026    /**
027     * Create a new instance of DefaultSymbolTable with no previous symbol table.
028     */
029    public DefaultSymbolTable() {
030        _prevSymbolTable = null;
031        _stack = new DefaultStack();
032        _firstSymbolIndex = _stack.getCount();
033    }
034
035    /**
036     * Create a new instance of DefaultSymbolTable with previous symbol table
037     * and the stack from a ConditionalNG.
038     * @param currentConditionalNG the ConditionalNG
039     */
040    public DefaultSymbolTable(ConditionalNG currentConditionalNG) {
041        _prevSymbolTable = currentConditionalNG.getSymbolTable();
042        _stack = currentConditionalNG.getStack();
043        _firstSymbolIndex = _stack.getCount();
044    }
045
046    /**
047     * Create a new instance of DefaultSymbolTable from a previous symbol table
048     * and a stack.
049     * @param prevSymbolTable the previous symbol table
050     */
051    public DefaultSymbolTable(SymbolTable prevSymbolTable) {
052        _prevSymbolTable = null;
053        _symbols.putAll(prevSymbolTable.getSymbols());
054        _stack = new DefaultStack();
055        for (Symbol symbol : _symbols.values()) {
056            _stack.setValueAtIndex(symbol.getIndex(),
057                    prevSymbolTable.getValue(symbol.getName()));
058
059        }
060        _firstSymbolIndex = _stack.getCount();
061    }
062
063    /**
064     * Get the previous symbol table
065     * @return the symbol table
066     */
067    public SymbolTable getPrevSymbolTable() {
068        return _prevSymbolTable;
069    }
070
071    /** {@inheritDoc} */
072    @Override
073    public Map<String, Symbol> getSymbols() {
074        return Collections.unmodifiableMap(_symbols);
075    }
076
077    /** {@inheritDoc} */
078    @Override
079    public Map<String, Object> getSymbolValues() {
080        Map<String, Object> symbolValues = new HashMap<>();
081        for (Symbol symbol : _symbols.values()) {
082            Object value = _stack.getValueAtIndex(_firstSymbolIndex + symbol.getIndex());
083            symbolValues.put(symbol.getName(), value);
084        }
085        return Collections.unmodifiableMap(symbolValues);
086    }
087
088    /** {@inheritDoc} */
089    @Override
090    public Object getValue(String name) {
091        Symbol symbol = _symbols.get(name);
092        if (symbol != null) {
093            return _stack.getValueAtIndex(_firstSymbolIndex + symbol.getIndex());
094        }
095        GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name);
096        if (globalVariable != null) {
097            return globalVariable.getValue();
098        }
099        throw new SymbolNotFound(String.format("Symbol '%s' does not exist in symbol table", name));
100    }
101
102    /** {@inheritDoc} */
103    @Override
104    public boolean hasValue(String name) {
105        if (_symbols.containsKey(name)) return true;
106        GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name);
107        return globalVariable != null;
108    }
109
110    /** {@inheritDoc} */
111    @Override
112    public void setValue(String name, Object value) {
113        if (_symbols.get(name) != null) {
114            _stack.setValueAtIndex(_firstSymbolIndex + _symbols.get(name).getIndex(), value);
115        } else {
116            GlobalVariable globalVariable = InstanceManager.getDefault(GlobalVariableManager.class).getByUserName(name);
117            if (globalVariable != null) {
118                globalVariable.setValue(value);
119            } else {
120                throw new IllegalArgumentException(Bundle.getMessage("ExceptionSymbolNotInSymbolTable", name));
121            }
122        }
123    }
124
125    /** {@inheritDoc} */
126    @Override
127    public void printSymbolTable(java.io.PrintWriter stream) {
128        stream.format("printSymbolTable:%n");
129        for (Map.Entry<String, Symbol> entry : _symbols.entrySet()) {
130            stream.format("Key: %s, Name: %s, Index: %d, Value: %s%n",
131                    entry.getKey(),
132                    entry.getValue().getName(),
133                    entry.getValue().getIndex(),
134                    _stack.getValueAtIndex(_firstSymbolIndex + entry.getValue().getIndex()));
135        }
136        stream.format("printSymbolTable done%n");
137    }
138
139    /** {@inheritDoc} */
140    @Override
141    public void createSymbols(Collection<? extends SymbolTable.VariableData> symbolDefinitions) throws JmriException {
142        createSymbols(this, symbolDefinitions);
143    }
144
145    /** {@inheritDoc} */
146    @Override
147    public void createSymbols(SymbolTable symbolTable,
148            Collection<? extends SymbolTable.VariableData> symbolDefinitions)
149            throws JmriException {
150
151        for (SymbolTable.VariableData variable : symbolDefinitions) {
152            Symbol symbol = new DefaultSymbol(variable.getName(), _stack.getCount() - _firstSymbolIndex);
153
154            if (_symbols.containsKey(symbol.getName())) {
155                throw new IllegalArgumentException("Symbol table already contains the variable " + symbol.getName());
156            }
157
158            Object initialValue = SymbolTable.getInitialValue(
159                    variable.getInitialValueType(),
160                    variable.getInitialValueData(),
161                    symbolTable,
162                    _symbols);
163
164//            System.out.format("Add symbol: %s = %s%n", symbol.getName(), initialValue);
165
166            _stack.push(initialValue);
167            _symbols.put(symbol.getName(), symbol);
168        }
169    }
170
171    /** {@inheritDoc} */
172    @Override
173    public void removeSymbols(Collection<? extends SymbolTable.VariableData> symbolDefinitions) throws JmriException {
174        symbolDefinitions.forEach((parameter) -> {
175            _symbols.remove(parameter.getName());
176        });
177    }
178
179    /** {@inheritDoc} */
180    @Override
181    public Stack getStack() {
182        return _stack;
183    }
184
185
186    public static class DefaultSymbol implements Symbol {
187
188        private final String _name;
189        private final int _index;
190
191        public DefaultSymbol(String name, int index) {
192            _name = name;
193            _index = index;
194        }
195
196        /** {@inheritDoc} */
197        @Override
198        public String getName() {
199            return _name;
200        }
201
202        /** {@inheritDoc} */
203        @Override
204        public int getIndex() {
205            return _index;
206        }
207
208    }
209
210
211    public static class DefaultParameter implements Parameter {
212
213        private String _name;
214        private boolean _isInput;
215        private boolean _isOutput;
216
217        public DefaultParameter(String name, boolean isInput, boolean isOutput) {
218            _name = name;
219            _isInput = isInput;
220            _isOutput = isOutput;
221        }
222
223        public DefaultParameter(Parameter parameter) {
224            _name = parameter.getName();
225            _isInput = parameter.isInput();
226            _isOutput = parameter.isOutput();
227        }
228
229        /** {@inheritDoc} */
230        @Override
231        public String getName() {
232            return _name;
233        }
234
235        public void setName(String name) {
236            _name = name;
237        }
238
239        /** {@inheritDoc} */
240        @Override
241        public boolean isInput() {
242            return _isInput;
243        }
244
245        public void setIsInput(boolean value) {
246            _isInput = value;
247        }
248
249        /** {@inheritDoc} */
250        @Override
251        public boolean isOutput() {
252            return _isOutput;
253        }
254
255        public void setIsOutput(boolean value) {
256            _isOutput = value;
257        }
258
259    }
260
261
262//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultSymbolTable.class);
263
264}