001package jmri.jmrit.logixng.tools.swing;
002
003import java.awt.event.*;
004import java.util.*;
005
006import jmri.Category;
007import jmri.InstanceManager;
008import jmri.jmrit.beantable.BeanTableDataModel;
009import jmri.jmrit.logixng.*;
010import jmri.jmrit.logixng.Module;
011import jmri.jmrit.logixng.implementation.AbstractFemaleSocket;
012import jmri.jmrit.logixng.implementation.DefaultConditionalNG;
013import jmri.jmrit.logixng.swing.SwingConfiguratorInterface;
014import jmri.jmrit.logixng.util.LogixNG_Thread;
015
016/**
017 * Editor of Module
018 *
019 * @author Daniel Bergqvist 2020
020 */
021public class ModuleEditor extends TreeEditor implements AbstractLogixNGEditor<Module> {
022
023    BeanTableDataModel<Module> beanTableDataModel;
024
025//    private final ModuleManager _moduleManager =
026//            InstanceManager.getDefault(ModuleManager.class);
027
028    protected final Module _module;
029
030    /**
031     * Maintain a list of listeners -- normally only one.
032     */
033    private final List<EditorEventListener> listenerList = new ArrayList<>();
034
035    /**
036     * This contains a list of commands to be processed by the listener
037     * recipient.
038     */
039    final HashMap<String, String> moduleData = new HashMap<>();
040
041    /**
042     * Create a new ConditionalNG List View editor.
043     *
044     * @param m the bean table model
045     * @param sName name of the LogixNG being edited
046     */
047    public ModuleEditor(BeanTableDataModel<Module> m, String sName) {
048
049        super(setupRootSocket(null, sName),
050                EnableClipboard.EnableClipboard,
051                EnableRootRemoveCutCopy.DisableRootRemoveCutCopy,
052                EnableRootPopup.EnableRootPopup,
053                EnableExecuteEvaluate.EnableExecuteEvaluate
054        );
055
056        this.beanTableDataModel = m;
057
058        if (!_treePane._femaleRootSocket.isConnected()) {
059            // This should never happen
060            throw new RuntimeException("Module is not connected");
061        }
062        if (!(_treePane._femaleRootSocket.getConnectedSocket().getObject() instanceof Module)) {
063            // This should never happen
064            throw new RuntimeException("Connected socket is not a Module");
065        }
066        _module = (Module) _treePane._femaleRootSocket.getConnectedSocket().getObject();
067
068        if (_module.getUserName() == null) {
069            ModuleEditor.this.setTitle(
070                    Bundle.getMessage("TitleEditModule", _module.getSystemName()));
071        } else {
072            ModuleEditor.this.setTitle(
073                    Bundle.getMessage("TitleEditModule2",
074                            _module.getSystemName(),
075                            _module.getUserName()));
076        }
077    }
078
079    @Override
080    protected void executeEvaluate(SwingConfiguratorInterface swi, MaleSocket maleSocket) {
081        Base b = maleSocket;
082        Module module;
083        if (maleSocket.getObject() instanceof Module) {
084            module = (Module)maleSocket.getObject();
085        } else {
086            while ((b != null) && !(b instanceof Module)) b = b.getParent();
087            if (b == null) throw new RuntimeException("Module is not found");
088            module = (Module)b;
089        }
090
091        LogixNG_Thread.getThread(LogixNG_Thread.DEFAULT_LOGIXNG_THREAD).runOnLogixNGEventually(() -> {
092
093            // We need to create a temporary ConditionalNG to be able to
094            // execute/evaluate a module or a part of a module
095            module.setCurrentConditionalNG(new DefaultConditionalNG("IQC1", null));
096
097            swi.executeEvaluate(maleSocket);
098        });
099    }
100
101    private static FemaleSocket setupRootSocket(Base parent, String sName) {
102        FemaleSocket socket = new RootSocket(parent, new FemaleSocketListener() {
103            @Override
104            public void connected(FemaleSocket socket) {
105                // Do nothing
106            }
107
108            @Override
109            public void disconnected(FemaleSocket socket) {
110                // Do nothing
111            }
112        }, "Root");
113
114        Module module = InstanceManager.getDefault(ModuleManager.class).getBySystemName(sName);
115
116        try {
117            socket.connect(new ModuleEditorMaleSocket(null, module));
118        } catch (SocketAlreadyConnectedException e) {
119            // This should never happen
120            throw new RuntimeException("Socket already connected", e);
121        }
122
123        return socket;
124    }
125
126    /** {@inheritDoc} */
127    @Override
128    public void windowClosed(WindowEvent e) {
129        moduleData.clear();
130        moduleData.put("Finish", _module.getSystemName());  // NOI18N
131        fireModuleEvent();
132    }
133
134    /**
135     * Notify the listeners to check for new data.
136     */
137    void fireModuleEvent() {
138        for (EditorEventListener l : listenerList) {
139            l.editorEventOccurred(moduleData);
140        }
141    }
142
143    @Override
144    public void addEditorEventListener(EditorEventListener listener) {
145        listenerList.add(listener);
146    }
147
148    @Override
149    public void removeEditorEventListener(EditorEventListener listener) {
150        listenerList.remove(listener);
151    }
152
153    @Override
154    public void bringToFront() {
155        this.setVisible(true);
156    }
157
158
159    private static class RootSocket extends AbstractFemaleSocket {
160
161        public RootSocket(Base parent, FemaleSocketListener listener, String name) {
162            super(parent, listener, name);
163        }
164
165        @Override
166        public boolean canDisconnect() {
167            return false;
168        }
169
170        @Override
171        public void disposeMe() {
172            throw new UnsupportedOperationException("Not supported");
173        }
174
175        @Override
176        public boolean isCompatible(MaleSocket socket) {
177            return socket instanceof ModuleEditorMaleSocket;
178        }
179
180        @Override
181        public Map<Category, List<Class<? extends Base>>> getConnectableClasses() {
182//            Map<Category, List<Class<? extends Base>>> map = new HashMap<>();
183//            List<Class<? extends Base>> list = new ArrayList<>();
184//            map.put(Category.OTHER, list);
185//            list.add(Module.class);
186//            return map;
187            throw new UnsupportedOperationException("Not supported");
188        }
189
190        @Override
191        public String getShortDescription(Locale locale) {
192            return Bundle.getMessage(locale, "ModuleEditor_RootSocket_Short");
193        }
194
195        @Override
196        public String getLongDescription(Locale locale) {
197            return Bundle.getMessage(locale, "ModuleEditor_RootSocket_Long", getName());
198        }
199
200    }
201
202}