001package jmri.implementation;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004import java.util.List;
005import jmri.AddressedProgrammer;
006import jmri.Programmer;
007import org.jdom2.Element;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * Utility to load a specific ProgrammerFacade from an XML element.
013 *
014 * @see jmri.jmrix.AbstractProgrammerFacade
015 *
016 * @author Bob Jacobsen Copyright (C) 2013
017 */
018public class ProgrammerFacadeSelector {
019
020    /**
021     * Add facades specified in an XML decoder definition element to the front
022     * of a programmer.
023     *
024     * @param element    Contains "capability" elements that define the Facades
025     * @param programmer Programmer implementation to decorate
026     * @param allowCache Passed to facades that optionally cache
027     * @param baseProg   The original underlying programmer, less any facades
028     * @return the programmer with added facades
029     */
030    @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST",
031            justification = "cast is checked by conditional surrounding the code block")  // NOI18N
032    public static Programmer loadFacadeElements(
033            Element element, Programmer programmer, boolean allowCache, Programmer baseProg) {
034        // iterate over any facades and add them
035        List<Element> facades = element.getChildren("capability");
036        if (log.isDebugEnabled()) {
037            log.debug("Found {} capability elements", facades.size());
038        }
039        for (Element facade : facades) {
040            String fname = facade.getChild("name").getText();
041            if (log.isDebugEnabled()) {
042                log.debug("Process capability facade: {}", fname);
043            }
044
045            List<Element> parameters = facade.getChildren("parameter");
046            if (log.isDebugEnabled()) {
047                log.debug("Found {} capability parameters", facades.size());
048            }
049            for (Element parameter : parameters) {
050                String pname = parameter.getAttributeValue("name");
051                String pval = parameter.getText();
052                log.debug("Found parameter name=\"{}\", value=\"{}\" ", pname, pval);
053            }
054
055            switch (fname) {
056
057                case "High Access via Double Index": {
058                    String top = parameters.get(0).getText();
059                    String addrCVhigh = parameters.get(1).getText();
060                    String addrCVlow = parameters.get(2).getText();
061                    String valueCV = parameters.get(3).getText();
062                    String modulo = parameters.get(4).getText();
063                    jmri.implementation.AddressedHighCvProgrammerFacade pf
064                            = new jmri.implementation.AddressedHighCvProgrammerFacade(programmer, top, addrCVhigh, addrCVlow, valueCV, modulo);
065                    log.debug("new programmer '{}' {}", fname, pf);
066                    programmer = pf; // to go around and see if there are more
067                    break;
068                }
069
070                case "High Access via Partial Index": {
071                    String top = parameters.get(0).getText();
072                    String addrCV = parameters.get(1).getText();
073                    String factor = parameters.get(2).getText();
074                    String modulo = parameters.get(3).getText();
075                    jmri.implementation.OffsetHighCvProgrammerFacade pf
076                            = new jmri.implementation.OffsetHighCvProgrammerFacade(programmer, top, addrCV, factor, modulo);
077                    log.debug("new programmer '{}' {}", fname, pf);
078                    programmer = pf; // to go around and see if there are more
079                    break;
080                }
081
082                case "High Access via Partial Index with Reset": {
083                    String top = parameters.get(0).getText();
084                    String addrCV = parameters.get(1).getText();
085                    String factor = parameters.get(2).getText();
086                    String modulo = parameters.get(3).getText();
087                    String indicator = parameters.get(4).getText();
088                    jmri.implementation.ResettingOffsetHighCvProgrammerFacade pf
089                            = new jmri.implementation.ResettingOffsetHighCvProgrammerFacade(programmer, top, addrCV, factor, modulo, indicator);
090                    log.debug("new programmer '{}' {}", fname, pf);
091                    programmer = pf; // to go around and see if there are more
092                    break;
093                }
094
095                case "Indexed CV access": {
096                    String PI = parameters.get(0).getText();
097                    String SI = (parameters.size() > 1) ? parameters.get(1).getText() : null;
098                    boolean cvFirst = (parameters.size() > 2) ? (!parameters.get(2).getText().equals("false")) : true;
099                    boolean skipDupIndexWrite = (parameters.size() > 3) ? (parameters.get(3).getText().equals("false") ? false : allowCache) : allowCache; // if not present, use default
100                    jmri.implementation.MultiIndexProgrammerFacade pf
101                            = new jmri.implementation.MultiIndexProgrammerFacade(programmer, PI, SI, cvFirst, skipDupIndexWrite);
102                    log.debug("new programmer '{}' {}", fname, pf);
103                    programmer = pf; // to go around and see if there are more
104                    break;
105                }
106
107                case "TCS 4 CV access": {
108                    jmri.implementation.TwoIndexTcsProgrammerFacade pf
109                            = new jmri.implementation.TwoIndexTcsProgrammerFacade(programmer);
110                    log.debug("new programmer '{}' {}", fname, pf);
111                    programmer = pf; // to go around and see if there are more
112                    break;
113                }
114
115                case "Ops Mode Accessory Programming":
116                    if (AddressedProgrammer.class.isAssignableFrom(baseProg.getClass())) {  // create if relevant to current mode, otherwise silently ignore
117                        String addrType = "decoder";
118                        int delay = 500;
119                        for (Element x : parameters) {
120                            switch (x.getAttributeValue("name")) {
121                                case "Address Type":
122                                    addrType = x.getText();
123                                    break;
124                                case "Delay":
125                                    delay = Integer.parseInt(x.getText());
126                                    break;
127                                default:
128                                    log.error("Unknown parameter \"{}\" for \"{}\"", fname, x.getText());
129                                    break;
130                            }
131                        }
132                        log.debug("\"{}\": addrType=\"{}\", delay=\"{}\", baseProg=\"{}\"", fname, addrType, delay, baseProg);
133
134                        jmri.implementation.AccessoryOpsModeProgrammerFacade pf
135                                = new jmri.implementation.AccessoryOpsModeProgrammerFacade(programmer, addrType, delay, (AddressedProgrammer) baseProg);
136                        log.debug("new programmer '{}' {}", fname, pf);
137                        programmer = pf; // to go around and see if there are more
138                    }
139                    break;
140
141                case "Ops Mode Delayed Programming":
142                    if (AddressedProgrammer.class.isAssignableFrom(baseProg.getClass())) {  // create if relevant to current mode, otherwise silently ignore
143                        int delay = 500;
144                        for (Element x : parameters) {
145                            switch (x.getAttributeValue("name")) {
146                                case "Delay":
147                                    delay = Integer.parseInt(x.getText());
148                                    break;
149                                default:
150                                    log.error("Unknown parameter \"{}\" for \"{}\"", fname, x.getText());
151                                    break;
152                            }
153                        }
154                        log.debug("\"{}\": delay=\"{}\"", fname, delay);
155                        jmri.implementation.OpsModeDelayedProgrammerFacade pf
156                                = new jmri.implementation.OpsModeDelayedProgrammerFacade(programmer, delay);
157                        log.debug("new programmer '{}' {}", fname, pf);
158                        programmer = pf; // to go around and see if there are more
159                    }
160                    break;
161
162                case "Digitrax OpSw Word Programming":
163                    var pf = new jmri.implementation.DigitraxOpSwWordFacade(programmer);
164                    log.debug("new programmer '{}' {}", fname, pf);
165                    programmer = pf; // to go around and see if there are more
166                    break;
167                    
168                default:
169                    log.error("Cannot create programmer capability named: \"{}\"", fname);
170                    break;
171            }
172        }
173
174        return programmer;
175    }
176
177    private static final Logger log = LoggerFactory.getLogger(ProgrammerFacadeSelector.class);
178}