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