001package jmri.managers.configurexml;
002
003// import java.util.ArrayList;
004import java.util.List;
005import java.util.SortedSet;
006
007import jmri.*;
008import jmri.implementation.DefaultLightControl;
009
010import org.jdom2.Element;
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014/**
015 * Provides the abstract base and store functionality for configuring
016 * LightManagers, working with AbstractLightManagers.
017 * <p>
018 * Typically, a subclass will just implement the load(Element sensors) class,
019 * relying on implementation here to load the individual lights. Note that these
020 * are stored explicitly, so the resolution mechanism doesn't need to see *Xml
021 * classes for each specific Light or AbstractLight subclass at store time.
022 * <p>
023 * Based on AbstractSensorManagerConfigXML.java
024 *
025 * @author Dave Duchamp Copyright (c) 2004, 2008, 2010
026 */
027public abstract class AbstractLightManagerConfigXML extends AbstractNamedBeanManagerConfigXML {
028
029    public AbstractLightManagerConfigXML() {
030    }
031
032    /**
033     * Default implementation for storing the contents of a LightManager.
034     *
035     * @param o Object to store, of type LightManager
036     * @return Element containing the complete info
037     */
038    @Override
039    public Element store(Object o) {
040        Element lights = new Element("lights");
041        setStoreElementClass(lights);
042        LightManager lm = (LightManager) o;
043        if (lm != null) {
044            SortedSet<Light> lightList = lm.getNamedBeanSet();
045            // don't return an element if there are no lights to include
046            if (lightList.isEmpty()) {
047                return null;
048            }
049            for (Light lgt : lightList) {
050                // store the lights
051                String lName = lgt.getSystemName();
052                log.debug("system name is {}", lName);
053                Element elem = new Element("light");
054                elem.addContent(new Element("systemName").addContent(lName));
055
056                // store common parts
057                storeCommon(lgt, elem);
058
059                // write variable intensity attributes
060                if (lgt instanceof VariableLight) {
061                    elem.setAttribute("minIntensity", "" + ((VariableLight)lgt).getMinIntensity());
062                    elem.setAttribute("maxIntensity", "" + ((VariableLight)lgt).getMaxIntensity());
063
064                    // write transition attribute
065                    elem.setAttribute("transitionTime", "" + ((VariableLight)lgt).getTransitionTime());
066                } else {
067                    elem.setAttribute("minIntensity", "0.0");
068                    elem.setAttribute("maxIntensity", "1.0");
069
070                    // write transition attribute
071                    elem.setAttribute("transitionTime", "0.0");
072                }
073
074                // save child lightcontrol entries
075                List<LightControl> lcList = lgt.getLightControlList();
076                for (LightControl lc : lcList) {
077                    if (lc != null) {
078                        Element lcElem = new Element("lightcontrol");
079                        int type = lc.getControlType();
080                        lcElem.setAttribute("controlType", "" + type);
081                        if (type == Light.SENSOR_CONTROL) {
082                            lcElem.setAttribute("controlSensor", lc.getControlSensorName());
083                            lcElem.setAttribute("sensorSense", "" + lc.getControlSensorSense());
084                        } else if (type == Light.FAST_CLOCK_CONTROL) {
085                            lcElem.setAttribute("fastClockOnHour", "" + lc.getFastClockOnHour());
086                            lcElem.setAttribute("fastClockOnMin", "" + lc.getFastClockOnMin());
087                            lcElem.setAttribute("fastClockOffHour", "" + lc.getFastClockOffHour());
088                            lcElem.setAttribute("fastClockOffMin", "" + lc.getFastClockOffMin());
089                        } else if (type == Light.TURNOUT_STATUS_CONTROL) {
090                            lcElem.setAttribute("controlTurnout", lc.getControlTurnoutName());
091                            lcElem.setAttribute("turnoutState", "" + lc.getControlTurnoutState());
092                        } else if (type == Light.TIMED_ON_CONTROL) {
093                            lcElem.setAttribute("timedControlSensor", lc.getControlTimedOnSensorName());
094                            lcElem.setAttribute("duration", "" + lc.getTimedOnDuration());
095                        }
096                        if (type == Light.TWO_SENSOR_CONTROL) {
097                            lcElem.setAttribute("controlSensor", lc.getControlSensorName());
098                            lcElem.setAttribute("controlSensor2", lc.getControlSensor2Name());
099                            lcElem.setAttribute("sensorSense", "" + lc.getControlSensorSense());
100                        }
101                        elem.addContent(lcElem);
102                    }
103                }
104                lights.addContent(elem);
105            }
106        }
107        return lights;
108    }
109
110    /**
111     * Subclass provides implementation to create the correct top element,
112     * including the type information. Default implementation is to use the
113     * local class here.
114     *
115     * @param lights The top-level element being created
116     */
117    abstract public void setStoreElementClass(Element lights);
118
119    /**
120     * Utility method to load the individual Light objects. If there's no
121     * additional info needed for a specific light type, invoke this with the
122     * parent of the set of Light elements.
123     *
124     * @param lights Element containing the Light elements to load.
125     * @return true when complete, false on error.
126     */
127    public boolean loadLights(Element lights) {
128        boolean result = true;
129        List<Element> lightList = lights.getChildren("light");
130        log.debug("Found {} lights", lightList.size());
131        LightManager lm = InstanceManager.lightManagerInstance();
132        lm.setPropertyChangesSilenced("beans", true);
133
134        for (Element el : lightList) {
135            String sysName = getSystemName(el);
136            if (sysName == null) {
137                log.warn("unexpected null in systemName {} {}", el, el.getAttributes());
138                result = false;
139                break;
140            }
141
142            String userName = getUserName(el);
143
144            checkNameNormalization(sysName, userName, lm);
145
146            log.debug("create light: ({})({})", sysName, (userName == null ? "<null>" : userName));
147            
148            Light lgt = null;
149            try {
150                lgt = lm.newLight(sysName, userName);
151            } catch (IllegalArgumentException e) {
152                log.error("failed to create Light: {}", sysName);
153                return false;
154            }
155
156            // load common parts
157            loadCommon(lgt, el);
158
159            if (lgt instanceof VariableLight) {
160                // variable intensity, transition attributes
161                double value;
162                value = Double.parseDouble(el.getAttribute("minIntensity").getValue());
163                ((VariableLight)lgt).setMinIntensity(value);
164
165                value = Double.parseDouble(el.getAttribute("maxIntensity").getValue());
166                ((VariableLight)lgt).setMaxIntensity(value);
167
168                value = Double.parseDouble(el.getAttribute("transitionTime").getValue());
169                ((VariableLight)lgt).setTransitionTime(value);
170            }
171
172            // provide for legacy light control - panel files written by 2.9.5 or before
173            if (el.getAttribute("controlType") != null) {
174                // this is a legacy Light - create a LightControl from the input
175                String temString = el.getAttribute("controlType").getValue();
176                int type;
177                try {
178                    type = Integer.parseInt(temString);
179                } catch (NumberFormatException e) {
180                    log.error("error when converting control type in legacy Light load support");
181                    type = Light.NO_CONTROL;
182                }
183                if (type != Light.NO_CONTROL) {
184                    // this legacy light has a control - capture it
185                    LightControl lc = new DefaultLightControl(lgt);
186                    lc.setControlType(type);
187                    if (type == Light.SENSOR_CONTROL) {
188                        lc.setControlSensorName(el.getAttribute("controlSensor").getValue());
189                        try {
190                            lc.setControlSensorSense(Integer.parseInt(el.
191                                    getAttribute("sensorSense").getValue()));
192                        } catch (NumberFormatException e) {
193                            log.error("error when converting control sensor sense in legacy Light load");
194                        }
195                    } else if (type == Light.FAST_CLOCK_CONTROL) {
196                        int onHour = 0;
197                        int onMin = 0;
198                        int offHour = 0;
199                        int offMin = 0;
200                        try {
201                            onHour = Integer.parseInt(el.
202                                    getAttribute("fastClockOnHour").getValue());
203                            onMin = Integer.parseInt(el.
204                                    getAttribute("fastClockOnMin").getValue());
205                            offHour = Integer.parseInt(el.
206                                    getAttribute("fastClockOffHour").getValue());
207                            offMin = Integer.parseInt(el.
208                                    getAttribute("fastClockOffMin").getValue());
209                        } catch (NumberFormatException e) {
210                            log.error("error when converting fast clock items in legacy Light load");
211                        }
212                        lc.setFastClockControlSchedule(onHour, onMin, offHour, offMin);
213                    } else if (type == Light.TURNOUT_STATUS_CONTROL) {
214                        lc.setControlTurnout(el.
215                                getAttribute("controlTurnout").getValue());
216                        try {
217                            lc.setControlTurnoutState(Integer.parseInt(el.
218                                    getAttribute("turnoutState").getValue()));
219                        } catch (NumberFormatException e) {
220                            log.error("error when converting turnout state in legacy Light load");
221                        }
222                    } else if (type == Light.TIMED_ON_CONTROL) {
223                        lc.setControlTimedOnSensorName(el.
224                                getAttribute("timedControlSensor").getValue());
225                        try {
226                            lc.setTimedOnDuration(Integer.parseInt(el.
227                                    getAttribute("duration").getValue()));
228                        } catch (NumberFormatException e) {
229                            log.error("error when converting timed sensor items in legacy Light load");
230                        }
231
232                    }
233                    lgt.addLightControl(lc);
234                }
235            }
236
237            // load lightcontrol children, if any
238            List<Element> lightControlList = el.getChildren("lightcontrol");
239            for (Element elem : lightControlList) {
240                boolean noErrors = true;
241                LightControl lc = new DefaultLightControl(lgt);
242                String tem = elem.getAttribute("controlType").getValue();
243                int type = Light.NO_CONTROL;
244                try {
245                    type = Integer.parseInt(tem);
246                    lc.setControlType(type);
247                } catch (NumberFormatException e) {
248                    log.error("error when converting control type while loading light {}", sysName);
249                    noErrors = false;
250                }
251                if (type == Light.SENSOR_CONTROL) {
252                    lc.setControlSensorName(elem.getAttribute("controlSensor").getValue());
253                    try {
254                        lc.setControlSensorSense(Integer.parseInt(elem.
255                                getAttribute("sensorSense").getValue()));
256                    } catch (NumberFormatException e) {
257                        log.error("error when converting control sensor sense while loading light {}", sysName);
258                        noErrors = false;
259                    }
260                } else if (type == Light.FAST_CLOCK_CONTROL) {
261                    int onHour = 0;
262                    int onMin = 0;
263                    int offHour = 0;
264                    int offMin = 0;
265                    try {
266                        onHour = Integer.parseInt(elem.
267                                getAttribute("fastClockOnHour").getValue());
268                        onMin = Integer.parseInt(elem.
269                                getAttribute("fastClockOnMin").getValue());
270                        offHour = Integer.parseInt(elem.
271                                getAttribute("fastClockOffHour").getValue());
272                        offMin = Integer.parseInt(elem.
273                                getAttribute("fastClockOffMin").getValue());
274                        lc.setFastClockControlSchedule(onHour, onMin, offHour, offMin);
275                    } catch (NumberFormatException e) {
276                        log.error("error when converting fast clock items while loading light {}", sysName);
277                        noErrors = false;
278                    }
279                } else if (type == Light.TURNOUT_STATUS_CONTROL) {
280                    lc.setControlTurnout(elem.getAttribute("controlTurnout").getValue());
281                    try {
282                        lc.setControlTurnoutState(Integer.parseInt(elem.
283                                getAttribute("turnoutState").getValue()));
284                    } catch (NumberFormatException e) {
285                        log.error("error when converting turnout state while loading light {}", sysName);
286                        noErrors = false;
287                    }
288                } else if (type == Light.TIMED_ON_CONTROL) {
289                    lc.setControlTimedOnSensorName(elem.getAttribute("timedControlSensor").getValue());
290                    try {
291                        lc.setTimedOnDuration(Integer.parseInt(elem.
292                                getAttribute("duration").getValue()));
293                    } catch (NumberFormatException e) {
294                        log.error("error when converting timed sensor items while loading light {}", sysName);
295                        noErrors = false;
296                    }
297                } else if (type == Light.TWO_SENSOR_CONTROL) {
298                    lc.setControlSensorName(elem.getAttribute("controlSensor").getValue());
299                    lc.setControlSensor2Name(elem.getAttribute("controlSensor2").getValue());
300                    try {
301                        lc.setControlSensorSense(Integer.parseInt(elem.
302                                getAttribute("sensorSense").getValue()));
303                    } catch (NumberFormatException e) {
304                        log.error("error when converting control sensor2 sense while loading light {}", sysName);
305                        noErrors = false;
306                    }
307                }
308                if (noErrors) {
309                    lgt.addLightControl(lc);
310                }
311            }
312
313            // done, start it working
314            lgt.activateLight();
315        }
316
317        lm.setPropertyChangesSilenced("beans", false);
318        return result;
319    }
320
321    @Override
322    public int loadOrder() {
323        return InstanceManager.lightManagerInstance().getXMLOrder();
324    }
325
326    private final static Logger log = LoggerFactory.getLogger(AbstractLightManagerConfigXML.class);
327
328}