001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.preferences.sources;
003
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.HashMap;
007import java.util.LinkedHashSet;
008import java.util.List;
009import java.util.Map;
010import java.util.Objects;
011import java.util.Optional;
012import java.util.Set;
013import java.util.stream.Collectors;
014
015import org.openstreetmap.josm.spi.preferences.Config;
016
017/**
018 * Helper class for specialized extensions preferences.
019 * @since 12649 (extracted from gui.preferences package)
020 */
021public abstract class SourcePrefHelper {
022
023    private final String pref;
024    protected final SourceType type;
025
026    /**
027     * Constructs a new {@code SourcePrefHelper} for the given preference key.
028     * @param pref The preference key
029     * @param type The source type
030     * @since 12825
031     */
032    public SourcePrefHelper(String pref, SourceType type) {
033        this.pref = pref;
034        this.type = type;
035    }
036
037    /**
038     * Returns the default sources provided by JOSM core.
039     * @return the default sources provided by JOSM core
040     */
041    public abstract Collection<ExtendedSourceEntry> getDefault();
042
043    /**
044     * Serializes the given source entry as a map.
045     * @param entry source entry to serialize
046     * @return map (key=value)
047     */
048    public Map<String, String> serialize(SourceEntry entry) {
049        Map<String, String> res = new HashMap<>();
050        res.put("url", entry.url == null ? "" : entry.url);
051        res.put("title", entry.title == null ? "" : entry.title);
052        return res;
053    }
054
055    /**
056     * Deserializes the given map as a source entry.
057     * @param entryStr map (key=value)
058     * @return source entry
059     */
060    public SourceEntry deserialize(Map<String, String> entryStr) {
061        return new SourceEntry(type,
062                entryStr.get("url"),
063                entryStr.get("name"),
064                entryStr.get("title"),
065                Optional.ofNullable(entryStr.get("active")).map(Boolean::parseBoolean).orElse(true));
066    }
067
068    /**
069     * Returns the list of sources.
070     * @return The list of sources
071     */
072    public List<SourceEntry> get() {
073        List<Map<String, String>> src = Config.getPref().getListOfMaps(pref, null);
074        if (src == null)
075            return new ArrayList<>(getDefault());
076        return src.stream()
077                .map(sourcePref -> deserialize(new HashMap<>(sourcePref)))
078                .filter(Objects::nonNull)
079                .collect(Collectors.toList());
080    }
081
082    /**
083     * Saves a list of sources to JOSM preferences.
084     * @param entries list of sources
085     * @return {@code true}, if something has changed (i.e. value is different than before)
086     */
087    public boolean put(Collection<? extends SourceEntry> entries) {
088        List<Map<String, String>> setting = serializeList(entries);
089        boolean unset = Config.getPref().getListOfMaps(pref, null) == null;
090        if (unset) {
091            Collection<Map<String, String>> def = serializeList(getDefault());
092            if (setting.equals(def))
093                return false;
094        }
095        return Config.getPref().putListOfMaps(pref, setting);
096    }
097
098    private List<Map<String, String>> serializeList(Collection<? extends SourceEntry> entries) {
099        return new ArrayList<>(entries).stream().map(this::serialize).collect(Collectors.toList());
100    }
101
102    /**
103     * Returns the set of active source URLs.
104     * @return The set of active source URLs.
105     */
106    public final Set<String> getActiveUrls() {
107        return get().stream()
108                .filter(e -> e.active)
109                .map(e -> e.url)
110                .collect(Collectors.toCollection(LinkedHashSet::new)); // LinkedHashSet to retain order
111    }
112}