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