001package jmri.jmrit.display.layoutEditor;
002
003import java.util.ArrayList;
004import java.util.List;
005import jmri.*;
006import jmri.NamedBean.BadNameException;
007
008/**
009 * The transit creation tool, is designed to be used by higher level tools to
010 * create transits between Beans. The higher level tools would already have a
011 * valid knowledge of the track layout and Sections, therefore this tool does
012 * little validation of sections being added to the transit.
013 * <hr>
014 * The tool currently only deals with SignalMasts, that have had logic created
015 * and also have a section associated between them.
016 * <hr>
017 * This file is part of JMRI.
018 * <p>
019 * JMRI is free software; you can redistribute it and/or modify it under the
020 * terms of version 2 of the GNU General Public License as published by the Free
021 * Software Foundation. See the "COPYING" file for a copy of this license.
022 * <p>
023 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
024 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
025 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
026 *
027 * @author Kevin Dickerson Copyright (C) 2011
028 * @author George Warner Copyright (c) 2017-2018
029 */
030final public class TransitCreationTool {
031
032    public TransitCreationTool() {
033    }
034
035    ArrayList<NamedBean> list = new ArrayList<>();
036
037    public void addNamedBean(NamedBean nb) throws JmriException {
038        if (!list.isEmpty()) {
039            if (list.get(list.size() - 1) == nb) {
040                log.debug("Bean is the same as the last one so will not add or error");
041                return;
042            }
043            //Run through a series of checks that this bean is reachable from the previous
044            if ((nb instanceof SignalMast) && (list.get(list.size() - 1) instanceof SignalMast)) {
045                SignalMastLogicManager smlm = InstanceManager.getDefault(SignalMastLogicManager.class);
046                SignalMastLogic sml = smlm.getSignalMastLogic(((SignalMast) list.get(list.size() - 1)));
047                if (sml == null || !sml.isDestinationValid((SignalMast) nb)) {
048                    String error = Bundle.getMessage("TCTErrorMastPairsNotValid", nb.getDisplayName(), list.get(list.size() - 1).getDisplayName());
049                    log.error("will throw {}", error);
050                    throw new JmriException(error);
051                }
052                if (sml.getAssociatedSection((SignalMast) nb) == null) {
053                    String error = Bundle.getMessage("TCTErrorMastPairsNoSection", list.get(list.size() - 1).getDisplayName(), nb.getDisplayName());
054                    log.error("will throw {}", error);
055                    throw new JmriException(error);
056                }
057            } else {
058                //Need to add the method to get layout block connectivity.  Also work checking that the Layout Block routing has been initialised.
059            }
060        }
061        list.add(nb);
062    }
063
064    public Transit createTransit() throws JmriException {
065        TransitManager tm = InstanceManager.getDefault(TransitManager.class);
066        String transitName = "From " + list.get(0).getDisplayName() + " to " + list.get(list.size() - 1).getDisplayName();
067        Transit t;
068        try {
069            t = tm.createNewTransit(transitName);
070        } catch (BadNameException ex) {
071            log.error("Unable to create transit {} {}", transitName,ex.getMessage());
072            throw new JmriException(Bundle.getMessage("TCTErrorUnableToCreate", transitName) + " " + ex.getLocalizedMessage());
073        }
074        if (list.get(0) instanceof SignalMast) {
075            SignalMastLogicManager smlm = InstanceManager.getDefault(SignalMastLogicManager.class);
076            int seqNo = 1;
077            // Add stub block section if applicable
078            SignalMastLogic smlForFirstMast = smlm.getSignalMastLogic((SignalMast) list.get(0));
079            if (smlForFirstMast != null) {
080                LayoutBlock layoutBlock = smlForFirstMast.getFacingBlock();
081                if (layoutBlock!=null && layoutBlock.getNumberOfNeighbours() == 1) {
082                    // A stub track block has one neighbor
083                    SectionManager sectionManager = InstanceManager.getDefault(SectionManager.class);
084                    for (Section section : sectionManager.getNamedBeanSet()) {
085                        // Look for a user defined section that has one block that matches the layout block
086                        if (section.getSectionType() == Section.USERDEFINED) {
087                            if (section.getNumBlocks() == 1 && layoutBlock.getBlock().equals(section.getEntryBlock())) {
088                                t.addTransitSection(new TransitSection(section, seqNo, Section.FORWARD));
089                                seqNo++;
090                                break;
091                            }
092                        }
093                    }
094                    if (seqNo == 1) {
095                        log.warn("Unable to find a stub block section for {}", layoutBlock.getDisplayName());
096                    }
097                }
098            }
099            for (int i = 1; i <= list.size() - 1; i++) {
100                SignalMastLogic sml = smlm.getSignalMastLogic((SignalMast) list.get(i - 1));
101                if (sml==null){
102                    String error = "Cannot locate SML for SM " + list.get(i - 1).getDisplayName();
103                    log.error("will throw {}", error);
104                    tm.deregister(t);
105                    t.dispose();
106                    cancelTransitCreate();
107                    throw new JmriException(error);
108                }
109                Section sec = sml.getAssociatedSection((SignalMast) list.get(i));
110                //In theory sec being null would already have been tested when the signal was added.
111                if (sec == null) {
112                    String error = Bundle.getMessage("TCTErrorMastPairsNoSection", list.get(i - 1).getDisplayName(), list.get(i).getDisplayName());
113                    log.error("will throw {}", error);
114                    tm.deregister(t);
115                    t.dispose();
116                    cancelTransitCreate();
117                    throw new JmriException(error);
118                }
119                t.addTransitSection(new TransitSection(sec, seqNo, Section.FORWARD));
120                seqNo++;
121            }
122        }
123        //Once created clear the list for a fresh start.
124        list = new ArrayList<>();
125        return t;
126    }
127
128    public void cancelTransitCreate() {
129        list = new ArrayList<>();
130    }
131
132    public List<NamedBean> getBeans() {
133        return list;
134    }
135
136    public boolean isToolInUse() {
137        return !list.isEmpty();
138    }
139
140    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TransitCreationTool.class);
141}