001package jmri.jmrix.rps;
002
003import java.io.File;
004import java.io.IOException;
005import java.util.List;
006import javax.vecmath.Point3d;
007import jmri.jmrit.XmlFile;
008import jmri.util.FileUtil;
009import org.jdom2.Attribute;
010import org.jdom2.Document;
011import org.jdom2.Element;
012import org.jdom2.ProcessingInstruction;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016/**
017 * Persist RPS configuration information.
018 *
019 * @author Bob Jacobsen Copyright 2007, 2008
020 */
021public class PositionFile extends XmlFile {
022
023    Document doc;
024    Element root;
025
026    /**
027     * Initialize for writing information.
028     * <p>
029     * This is followed by multiple "set" calls, then a "store".
030     */
031    public void prepare() {
032        root = new Element("rpsfile");
033        doc = newDocument(root, dtdLocation + "rpsfile.dtd");
034
035        // add XSLT processing instruction
036        // <?xml-stylesheet type="text/xsl" href="XSLT/rpsfile.xsl"?>
037        java.util.Map<String, String> m = new java.util.HashMap<String, String>();
038        m.put("type", "text/xsl");
039        m.put("href", xsltLocation + "rpsfile.xsl");
040        ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m);
041        doc.addContent(0, p);
042
043    }
044
045    public void setConstants(double vSound, int offset, String algorithm) {
046        Element v = new Element("vsound");
047        v.addContent("" + vSound);
048        root.addContent(v);
049
050        Element o = new Element("offset");
051        o.addContent("" + offset);
052        root.addContent(o);
053
054        Element a = new Element("algorithm");
055        a.addContent(algorithm);
056        root.addContent(a);
057    }
058
059    public void setReceiver(int n, Receiver r) {
060        Element e = new Element("receiver");
061        e.setAttribute("number", "" + n);
062        e.setAttribute("active", "" + (r.isActive() ? "true" : "false"));
063        e.setAttribute("mintime", "" + r.getMinTime());
064        e.setAttribute("maxtime", "" + r.getMaxTime());
065        e.addContent(positionElement(r.getPosition()));
066        root.addContent(e);
067    }
068
069    public void setReceiver(int n, Point3d p, boolean active) {
070        // allows defaults for min, max time
071        Element e = new Element("receiver");
072        e.setAttribute("number", "" + n);
073        e.setAttribute("active", "" + (active ? "true" : "false"));
074        e.addContent(positionElement(p));
075        root.addContent(e);
076    }
077
078    public void setCalibrationPoint(Point3d p, Reading r) {
079        Element e = new Element("calibrationpoint");
080        e.addContent(positionElement(p));
081        e.addContent(readingElement(r));
082        root.addContent(e);
083    }
084
085    Element positionElement(Point3d p) {
086        Element e = new Element("position");
087        Element x = new Element("x");
088        x.addContent("" + p.x);
089        e.addContent(x);
090        Element y = new Element("y");
091        y.addContent("" + p.y);
092        e.addContent(y);
093        Element z = new Element("z");
094        z.addContent("" + p.z);
095        e.addContent(z);
096        return e;
097    }
098
099    public Point3d positionFromElement(Element position) {
100        Element e;
101        e = position.getChild("x");
102        float x = Float.parseFloat(e.getText());
103
104        e = position.getChild("y");
105        float y = Float.parseFloat(e.getText());
106
107        e = position.getChild("z");
108        float z = Float.parseFloat(e.getText());
109
110        return new Point3d(x, y, z);
111    }
112
113    Element readingElement(Reading r) {
114        Element e = new Element("reading");
115        Element c = new Element("id");
116        c.addContent("" + r.getId());
117        e.addContent(c);
118        for (int i = 1; i <= r.getNValues(); i++) {
119            e.addContent(timeElement(r.getValue(i)));
120        }
121        return e;
122    }
123
124    public Reading readingFromElement(Element reading) {
125        String id = reading.getChild("id").getText();
126        List<Element> kids = reading.getChildren("time");
127        int count = kids.size();
128        double[] vals = new double[count + 1];
129
130        for (int i = 0; i < count; i++) {
131            Element e = kids.get(i);
132            double val = Double.parseDouble(e.getText());
133            vals[i + 1] = val;  // 1st item goes in element 1
134        }
135
136        return new Reading(id, vals);
137    }
138
139    Element timeElement(double time) {
140        Element e = new Element("time");
141        e.addContent("" + time);
142        return e;
143    }
144
145    public void store(File file) throws IOException {
146        writeXML(file, doc);
147    }
148
149    /**
150     * Read in the file, and make available for examination.
151     * @param f file to load.
152     * @throws org.jdom2.JDOMException other errors
153     * @throws java.io.IOException error accessing file
154     */
155    public void loadFile(File f)
156            throws org.jdom2.JDOMException, java.io.IOException {
157
158        root = rootFromFile(f);
159    }
160
161    public double getVSound() {
162        Element e = root.getChild("vsound");
163        return Double.parseDouble(e.getText());
164    }
165
166    public int getOffset() {
167        Element e = root.getChild("offset");
168        return Integer.parseInt(e.getText());
169    }
170
171    public String getAlgorithm() {
172        Element e = root.getChild("algorithm");
173        return e.getText();
174    }
175
176    /**
177     * FInd the highest numbered receiver in the file
178     * @return highest numbered receiver.
179     */
180    public int maxReceiver() {
181        List<Element> kids = root.getChildren("receiver");
182        int max = -1;
183        for (int i = 0; i < kids.size(); i++) {
184            Attribute a = kids.get(i).getAttribute("number");
185            if (a == null) {
186                continue;
187            }
188            int n = -1;
189            try {
190                n = a.getIntValue();
191            } catch (org.jdom2.DataConversionException e) {
192                log.error("in maxReceiver", e);
193            }
194            max = Math.max(max, n);
195        }
196        return max;
197    }
198
199    /**
200     * Get the nth receiver position in the file.
201     *
202     * @param n receiver index.
203     * @return null if not present
204     */
205    public Point3d getReceiverPosition(int n) {
206        List<Element> kids = root.getChildren("receiver");
207        for (int i = 0; i < kids.size(); i++) {
208            Element e = kids.get(i);
209            Attribute a = e.getAttribute("number");
210            if (a == null) {
211                continue;
212            }
213            int num = -1;
214            try {
215                num = a.getIntValue();
216            } catch (org.jdom2.DataConversionException ex) {
217                log.error("in getReceiverPosition", ex);
218            }
219            if (num == n) {
220                return positionFromElement(e.getChild("position"));
221            }
222        }
223        return null;
224    }
225
226    /**
227     * Get the nth receiver active state in the file.
228     *
229     * @param n receiver index.
230     * @return true if not present
231     */
232    public boolean getReceiverActive(int n) {
233        List<Element> kids = root.getChildren("receiver");
234        for (int i = 0; i < kids.size(); i++) {
235            Element e = kids.get(i);
236            Attribute a = e.getAttribute("number");
237            if (a == null) {
238                continue;
239            }
240            int num = -1;
241            try {
242                num = a.getIntValue();
243            } catch (org.jdom2.DataConversionException ex) {
244                log.error("in getReceiverActive", ex);
245            }
246            if (num != n) {
247                continue;
248            }
249            a = e.getAttribute("active");
250            if (a == null) {
251                return true; // default value
252            }
253            if (a.getValue().equals("false")) {
254                return false;
255            }
256            return true;
257        }
258        return true;
259    }
260
261    /**
262     * Get the nth receiver min time.
263     *
264     * @param n receiver index.
265     * @return 0 if not present
266     */
267    public int getReceiverMin(int n) {
268        List<Element> kids = root.getChildren("receiver");
269        for (int i = 0; i < kids.size(); i++) {
270            Element e = kids.get(i);
271            Attribute a = e.getAttribute("number");
272            if (a == null) {
273                continue;
274            }
275            int num = -1;
276            try {
277                num = a.getIntValue();
278            } catch (org.jdom2.DataConversionException ex1) {
279                log.error("in getReceiverMin", ex1);
280            }
281            if (num != n) {
282                continue;
283            }
284            a = e.getAttribute("mintime");
285            if (a == null) {
286                return 0; // default value
287            }
288            try {
289                return a.getIntValue();
290            } catch (org.jdom2.DataConversionException ex2) {
291                return 0;
292            }
293        }
294        return 0;
295    }
296
297    /**
298     * Get the nth receiver max time.
299     *
300     * @param n receiver index.
301     * @return 0 if not present
302     */
303    public int getReceiverMax(int n) {
304        List<Element> kids = root.getChildren("receiver");
305        for (int i = 0; i < kids.size(); i++) {
306            Element e = kids.get(i);
307            Attribute a = e.getAttribute("number");
308            if (a == null) {
309                continue;
310            }
311            int num = -1;
312            try {
313                num = a.getIntValue();
314            } catch (org.jdom2.DataConversionException ex1) {
315                log.error("in getReceiverMax", ex1);
316            }
317            if (num != n) {
318                continue;
319            }
320            a = e.getAttribute("maxtime");
321            if (a == null) {
322                return 99999; // default value
323            }
324            try {
325                return a.getIntValue();
326            } catch (org.jdom2.DataConversionException ex2) {
327                return 99999;
328            }
329        }
330        return 99999;
331    }
332
333    /**
334     * Get the nth calibration position in the file.
335     *
336     * @param n calibration index.
337     * @return null if not present
338     */
339    public Point3d getCalibrationPosition(int n) {
340        List<Element> kids = root.getChildren("calibrationpoint");
341        if (n >= kids.size()) {
342            return null;
343        }
344        Element e = kids.get(n);
345        return positionFromElement(e.getChild("position"));
346    }
347
348    /**
349     * Get the nth calibration reading in the file.
350     *
351     * @param n reading index.
352     * @return null if not present
353     */
354    public Reading getCalibrationReading(int n) {
355        List<Element> kids = root.getChildren("calibrationpoint");
356        if (n >= kids.size()) {
357            return null;
358        }
359        Element e = kids.get(n);
360        return readingFromElement(e.getChild("reading"));
361    }
362
363    static public String defaultLocation() {
364        String location = FileUtil.getUserFilesPath() + "rps" + File.separator;
365        FileUtil.createDirectory(location);
366        return location;
367    }
368
369    static public String defaultFilename() {
370        return defaultLocation() + "positions.xml";
371    }
372
373    // initialize logging
374    private final static Logger log = LoggerFactory.getLogger(PositionFile.class);
375
376}