001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.session;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.io.IOException;
007import java.util.Map;
008import java.util.stream.Collectors;
009import java.util.stream.IntStream;
010
011import org.openstreetmap.josm.data.StructUtils;
012import org.openstreetmap.josm.data.imagery.ImageryInfo;
013import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
014import org.openstreetmap.josm.data.imagery.OffsetBookmark;
015import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer;
016import org.openstreetmap.josm.gui.layer.ImageryLayer;
017import org.openstreetmap.josm.gui.layer.Layer;
018import org.openstreetmap.josm.gui.layer.TMSLayer;
019import org.openstreetmap.josm.gui.layer.WMSLayer;
020import org.openstreetmap.josm.gui.layer.WMTSLayer;
021import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
022import org.openstreetmap.josm.gui.progress.ProgressMonitor;
023import org.openstreetmap.josm.io.IllegalDataException;
024import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
025import org.openstreetmap.josm.tools.Logging;
026import org.openstreetmap.josm.tools.Utils;
027import org.w3c.dom.Element;
028import org.w3c.dom.Node;
029import org.w3c.dom.NodeList;
030
031/**
032 * Session importer for {@link TMSLayer}, {@link WMSLayer} and {@link WMTSLayer}.
033 * @since 5391
034 */
035public class ImagerySessionImporter implements SessionLayerImporter {
036
037    @Override
038    public Layer load(Element elem, ImportSupport support, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
039        String version = elem.getAttribute("version");
040        if (!"0.1".equals(version)) {
041            throw new IllegalDataException(tr("Version ''{0}'' of meta data for imagery layer is not supported. Expected: 0.1", version));
042        }
043        Map<String, String> attributes = readProperties(elem);
044
045        ImageryPreferenceEntry prefEntry = StructUtils.deserializeStruct(attributes, ImageryPreferenceEntry.class);
046        ImageryInfo info = new ImageryInfo(prefEntry);
047        ImageryLayer layer = ImageryLayer.create(info);
048        Utils.instanceOfThen(layer, AbstractTileSourceLayer.class, tsLayer -> {
049            tsLayer.getDisplaySettings().applyFromPropertiesMap(attributes);
050            if (!tsLayer.getDisplaySettings().isAutoZoom()) {
051                String zoomStr = attributes.get("zoom-level");
052                if (zoomStr != null) {
053                    support.addPostLayersTask(() -> {
054                        try {
055                            tsLayer.setZoomLevel(Integer.parseInt(zoomStr));
056                        } catch (NumberFormatException e) {
057                            Logging.warn(e);
058                        }
059                    });
060                }
061            }
062            Element offsetEl = getFirstElementByTagName(elem, "offset");
063            if (offsetEl != null) {
064                Map<String, String> offsetAttributes = readProperties(offsetEl);
065                OffsetBookmark offset = OffsetBookmark.fromPropertiesMap(offsetAttributes);
066                tsLayer.getDisplaySettings().setOffsetBookmark(offset);
067            }
068        });
069        Element filtersEl = getFirstElementByTagName(elem, "filters");
070        if (filtersEl != null) {
071            ImageryFilterSettings filterSettings = layer.getFilterSettings();
072            if (filterSettings != null) {
073                Map<String, String> filtersProps = readProperties(filtersEl);
074                filterSettings.getProcessors().stream()
075                        .flatMap(Utils.castToStream(SessionAwareReadApply.class))
076                        .forEach(proc -> proc.applyFromPropertiesMap(filtersProps));
077            }
078        }
079        return layer;
080    }
081
082    private static Element getFirstElementByTagName(Element el, String name) {
083        NodeList nl = el.getElementsByTagName(name);
084        if (nl.getLength() == 0)
085            return null;
086        return (Element) nl.item(0);
087    }
088
089    private static Map<String, String> readProperties(Element elem) {
090        NodeList nodes = elem.getChildNodes();
091        return IntStream.range(0, nodes.getLength()).mapToObj(nodes::item)
092                .filter(node -> node.getNodeType() == Node.ELEMENT_NODE && node.getChildNodes().getLength() <= 1)
093                .map(node -> (Element) node)
094                .collect(Collectors.toMap(Element::getTagName, Node::getTextContent, (a, b) -> b));
095    }
096}