001package jmri.jmrix.loconet.alm;
002
003import java.awt.FlowLayout;
004import java.awt.Dimension;
005import java.awt.event.KeyEvent;
006
007import javax.swing.JComponent;
008import javax.swing.JPanel;
009import javax.swing.JTabbedPane;
010import javax.swing.ButtonGroup;
011import javax.swing.event.ChangeEvent;
012import javax.swing.BoxLayout;
013
014import jmri.jmrix.loconet.swing.LnPanel;
015import jmri.jmrix.loconet.LnConstants;
016import jmri.jmrix.loconet.LocoNetSystemConnectionMemo;
017import jmri.jmrix.loconet.LocoNetMessage;
018import jmri.jmrix.loconet.ds64.SimpleTurnoutStateEntry;
019
020import org.slf4j.Logger;
021import org.slf4j.LoggerFactory;
022
023/**
024 * Contains all the route of a device.
025 *
026 * @author B. Milhaupt (C) 2024
027 */
028public class LnSimple7thGenDeviceRoutes extends LnPanel {
029    private JComponent[] routePanel;
030    private LnSimple7thGenRoute[] route; // has route info plus swing stuff!
031    private final int deviceNumber;
032    private final int serNum;
033    private int baseAddr;
034    private int howManyRoutes;
035    private final String[] entryName;
036
037    private int opsw1to7;
038
039    private JTabbedPane routesTabbedPane;
040
041    public LnSimple7thGenDeviceRoutes(int deviceType, int serNum) {
042        this.deviceNumber = deviceType;
043        this.serNum = serNum;
044        howManyRoutes = 8;
045        if (this.deviceNumber == LnConstants.RE_IPL_DIGITRAX_HOST_DS78V) {
046            this.howManyRoutes = 16;
047        }
048        route = new LnSimple7thGenRoute[howManyRoutes];
049        for (int i = 0;
050                i < howManyRoutes; ++ i) {
051            route[i] = new LnSimple7thGenRoute();
052        }
053        this.entryName = new String[]{"Top", "2", "3", "4", "5", "6", "7", "8"};
054    }
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    public void initComponents(LocoNetSystemConnectionMemo memo) {
061        super.initComponents(memo);
062    }
063
064    /**
065     * {@inheritDoc}
066     */
067    @Override
068    public void initComponents() {
069        super.initComponents();
070
071        routesTabbedPane = new JTabbedPane();
072        routePanel = new JComponent[howManyRoutes];
073        route = new LnSimple7thGenRoute[howManyRoutes];
074        for (int i = 0; i < howManyRoutes; ++i) {
075            route[i] = new LnSimple7thGenRoute();
076            routePanel[i] = makeTextPanel(i, 8);
077            routesTabbedPane.addTab("Route "+Integer.toString(i+1), null,
078                    routePanel[i] , "");
079            routesTabbedPane.setMnemonicAt(i, KeyEvent.VK_1 +i);
080        }
081        routePanel[howManyRoutes-1].setPreferredSize(new Dimension(460, 50));
082
083        add(routesTabbedPane);
084
085        //The following line enables to use scrolling tabs.
086        routesTabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
087
088        routesTabbedPane.addChangeListener((ChangeEvent e) -> {
089            if (e.getSource() instanceof JTabbedPane) {
090                JTabbedPane pane = (JTabbedPane) e.getSource();
091                int routeNum = pane.getSelectedIndex() + 1;
092                // get the route guiEntry
093                memo.getLnTrafficController().sendLocoNetMessage(new LocoNetMessage(new int[] {
094                    LnConstants.OPC_IMM_PACKET_2, 0x10, 0x02, 0x02,
095                    (routeNum - 1) * 2, 0, 0, 0,
096                    0, 0, 0, 0,
097                    0, 0, 0, 0}));
098            }
099        });
100        routesTabbedPane.repaint();
101
102        // Select device X s/n N for route accesss.
103        memo.getLnTrafficController().sendLocoNetMessage(new LocoNetMessage(new int[] {
104            LnConstants.OPC_IMM_PACKET_2, 0x10, 0x02, 0x0e,
105            0, 0, 0, 0,
106            0, deviceNumber, this.opsw1to7, serNum & 0x7f,
107            (serNum >> 7) & 0x7F, (this.baseAddr-1) & 0x7f,
108            ((this.baseAddr-1) >> 7) & 0x7f,
109            0}));
110    }
111
112    protected JComponent makeTextPanel(int i, int numEntries) {
113        JPanel panel = new JPanel(false);
114        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
115        JPanel jp;
116        for (int j = 0; j < 8; ++j) {
117            jp = new JPanel();
118            jp.setLayout(new FlowLayout());
119            SimpleTurnoutStateEntry stse = route[i].getRouteEntry(j).guiEntry;
120            jp.add(stse.createEntryPanel(entryName[j]));
121
122            jp.add(stse.getAddressField());
123            jp.add(stse.closedRadioButton);
124            jp.add(stse.thrownRadioButton);
125            jp.add(stse.unusedRadioButton);
126            ButtonGroup bg = new ButtonGroup();
127            bg.add(stse.closedRadioButton);
128            bg.add(stse.thrownRadioButton);
129            bg.add(stse.unusedRadioButton);
130
131            stse.unusedRadioButton.setSelected(true);
132            panel.add(jp);
133        }
134
135        return panel;
136    }
137
138    /**
139     * Get the device turnoutNumber (IPL device turnoutNumber) from the device name.
140     * @param name Device name
141     * @return device turnoutNumber
142     */
143    public static int getDeviceType(String name) {
144        String s = name.toUpperCase();
145        switch (s) {
146            case "DS74":
147                return LnConstants.RE_IPL_DIGITRAX_HOST_DS74;
148            case "DS78V":
149                return LnConstants.RE_IPL_DIGITRAX_HOST_DS78V;
150            case "PM74":
151                return LnConstants.RE_IPL_DIGITRAX_HOST_PM74;
152            case "SE74":
153                return LnConstants.RE_IPL_DIGITRAX_HOST_SE74;
154            default:
155                return -1;
156        }
157    }
158
159    /**
160     * Get the device name from the device (IPL) nuber.
161     * @param typeNum device type number
162     * @return String containing the device name
163     */
164    public static String getDeviceName(int typeNum) {
165        switch (typeNum) {
166            case LnConstants.RE_IPL_DIGITRAX_HOST_DS74:
167                return "DS74";
168            case LnConstants.RE_IPL_DIGITRAX_HOST_DS78V:
169                return "DS78V";
170            case LnConstants.RE_IPL_DIGITRAX_HOST_PM74:
171                return "PM74";
172            case LnConstants.RE_IPL_DIGITRAX_HOST_SE74:
173                return "SE74";
174            default:
175                return null;
176        }
177    }
178    /**
179     * Getter.
180     * @return device type turnoutNumber
181     */
182    public int getDeviceType() {
183        return deviceNumber;
184    }
185
186    /**
187     * Getter.
188     * @return  device serial turnoutNumber
189     */
190    public int getSerNum() {
191        return serNum;
192    }
193
194/**
195 * Get the routes.
196 * @return cloned LnSimple7thGenRoute[], if any.
197 */
198    public LnSimple7thGenRoute[] getRoutes() {
199        return route.clone();
200    }
201
202    /**
203     * get a specific route.
204     *
205     * @param routeNumber route number
206     * @return LnSimple7thGenRoute
207     */
208    public LnSimple7thGenRoute getRoutes(int routeNumber) {
209        return route[routeNumber];
210    }
211
212    /**
213     * Set the routes.
214     *
215     * @param newRoutes an array of routes
216     */
217    public void setRoutes(LnSimple7thGenRoute[] newRoutes) {
218        route = newRoutes.clone();
219    }
220
221    /**
222     * Set one route entry.
223     *
224     * @param routeNum route number
225     * @param entryNum entry number
226     * @param turn Turnout number
227     * @param posn Position
228     */
229    public void setOneEntry(int routeNum, int entryNum, int turn,
230            RouteSwitchPositionEnum posn) {
231        LnSimpleRouteEntry entry = new LnSimpleRouteEntry();
232        entry.setNumber(turn);
233        entry.setPosition(posn);
234        route[routeNum].setRouteEntry(entryNum, entry);
235    }
236
237    /**
238     * Set four entries for a route
239     * @param routeNum Route number
240     * @param entrySet Entry set
241     * @param entrya Entry a of the set
242     * @param entryb Entry b of the set
243     * @param entryc Entry c of the set
244     * @param entryd Entry d of the set
245     * @return a route
246     */
247    public LnSimple7thGenRoute setFourEntries(int routeNum, int entrySet,
248            int entrya, int entryb, int entryc, int entryd) {
249        int entry = (entrySet == 1) ? 4 : 0;
250
251        int entryaTurn = (entrya == 0x3fff) ? 0 : (entrya & 0x7ff);
252        RouteSwitchPositionEnum entrya_posn = RouteSwitchPositionEnum.UNUSED ;
253        if (entrya != 0x3fff) {
254            entrya_posn = (((entrya & 0x3800) == 0x1800) ?
255                RouteSwitchPositionEnum.CLOSED : RouteSwitchPositionEnum.THROWN);
256        }
257        setOneEntry(routeNum, entry, entryaTurn, entrya_posn);
258
259        int entrybTurn = (entryb == 0x3fff) ? 0 : (entryb & 0x7ff);
260        RouteSwitchPositionEnum entryb_posn =RouteSwitchPositionEnum.UNUSED ;
261        if (entryb != 0x3fff) {
262            entryb_posn = (((entryb & 0x3800) == 0x1800) ?
263                RouteSwitchPositionEnum.CLOSED : RouteSwitchPositionEnum.THROWN);
264        }
265        setOneEntry(routeNum, entry+1, entrybTurn, entryb_posn);
266
267        int entrycTurn = (entryc == 0x3fff) ? 0 : (entryc & 0x7ff);
268        RouteSwitchPositionEnum entryc_posn =RouteSwitchPositionEnum.UNUSED ;
269        if (entryc != 0x3fff) {
270            entryc_posn = (((entryc & 0x3800) == 0x1800) ?
271                RouteSwitchPositionEnum.CLOSED : RouteSwitchPositionEnum.THROWN);
272        }
273        setOneEntry(routeNum, entry+2, entrycTurn, entryc_posn);
274
275        int entrydTurn = (entryd == 0x3fff) ? 0 : (entryd & 0x7ff);
276        RouteSwitchPositionEnum entryd_posn =RouteSwitchPositionEnum.UNUSED ;
277        if (entryd != 0x3fff) {
278            entryd_posn = (((entryd & 0x3800) == 0x1800) ?
279                RouteSwitchPositionEnum.CLOSED : RouteSwitchPositionEnum.THROWN);
280        }
281        setOneEntry(routeNum, entry+3, entrydTurn, entryd_posn);
282
283        log.debug("setFourEntries: done: route {} entry {} thru {}, {}, {}, {}, {}",
284                routeNum, entry, entry + 3,
285                getOneEntryString(routeNum, entry), getOneEntryString(routeNum, entry+1),
286                getOneEntryString(routeNum, entry+2), getOneEntryString(routeNum, entry+3));
287
288        return getRoute(routeNum);
289    }
290
291    /**
292     * get a route entry as a string.
293     * @param routeNum Route number
294     * @param entryNum Entry number
295     * @return String like "Unused" or "1c" or "2044t"
296     */
297    public String getOneEntryString(int routeNum, int entryNum) {
298        RouteSwitchPositionEnum r = route[routeNum].getRouteEntry(entryNum).getPosition();
299        if (r.equals(RouteSwitchPositionEnum.UNUSED)) {
300            return "Unused";
301        }
302        return Integer.toString(route[routeNum].getRouteEntry(entryNum).getNumber()) + r.toString();
303    }
304
305    /**
306     * Get a route.
307     * @param routeNum Route number
308     * @return LnSimple7thGenRoute, or null if route not defined
309     */
310    public LnSimple7thGenRoute getRoute(int routeNum) {
311        if ((routeNum >=0) && (routeNum < route.length)) {
312            return route[routeNum];
313        } else {
314            log.warn("getRoutes({}): not configured.", routeNum);
315            return null;
316        }
317    }
318
319    /**
320     * Getter.
321     * @return Base Addr
322     */
323    public int getBaseAddr() {
324        return baseAddr;
325    }
326
327    /**
328     * Setter.
329     * @param baseAddr the base address
330     */
331    public void setBaseAddr(int baseAddr) {
332        this.baseAddr = baseAddr;
333    }
334
335    private final static Logger log = LoggerFactory.getLogger(LnSimple7thGenDeviceRoutes.class);
336}