﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc
13446	Preference cleanup	michael2402	team	"JOSM preferences were a String->String map. They have been enhanced to be a String->whatever map.

Over the time, this system has grown to support multiple data types by converting them to strings.
This includes:
||= Type =||= direct access =||= proxy access =||= notes =||
|| String || pref.get(String) || new StringProperty() ||
|| Boolean || pref.getBoolean(String) || new BooleanProperty() || no type hints
|| Boolean || pref.getInteger(String) || new IntegerProperty() || no type hints
|| Boolean || pref.getDouble(String) || new DoubleProperty() || no type hints
|| Boolean || pref.getLong(String) || new LongProperty() || no type hints
|| Color || pref.getColor(String) || new ColorProperty() || type identified by start with `color.` ||
|| Collection<String> || pref.getCollection(String) || ListSetting class
|| Collection<Collection<String>> || pref.getArray(String) || ListListSetting class
|| Object (Struct) || serializeStruct || - || See @pref annotation
|| List<Object> (Structs) || getListOfStructs || - || See @pref annotation

The interface to all those types differs a lot.

I propose:
1. Remove all public access to the Setting classes -> Make them internal.
1. Support only those internal `Setting` classes:
  - `StringSetting` (represented as simple string)
  - `ListSetting<? extends Setting>` ([0...n-1] -> value map) 
  - `MapSetting<? extends Setting>` (name -> value map)
1. Replace ListListSetting by ListSetting<ListSetting<StringSetting>>
1. Use setting classes during writing/reading the xml file only.
1. Do not expose the string representation of settings to the user. No more Main.pref.get() calls. No more matching-the-default-values, since we can store the property objects as constants.
1. Replace all public access using `..Property` objects.
1. Do type check in the Property objects when registering them.
1. Store the Property objects in a `knownProperties` map. They already contain the default value and the type information.

So we could replace this code:
{{{
#!java
        List<ImageryPreferenceEntry> entries = new ArrayList<>();
        for (ImageryInfo info : layers) {
            entries.add(new ImageryPreferenceEntry(info));
        }
        Main.pref.putListOfStructs(""imagery.entries"", entries, ImageryPreferenceEntry.class);
}}}

{{{
#!java
        // Use the builder pattern here
        // Uses ListCompoundProperty and MapCompoundProperty internally
        CompoundProperty<List<Map<String, String>> pref = CompoundProperty.map().list().for(""imagery.entries"");
        // expects List<Map<String, String>>
        pref.put(layers.stream()
                .map(info -> new ImageryPreferenceEntry(info))
                .map(Preferences::serializeStruct) // < can be moved to utility class
                .collect(Collectors.toList())
}}}

We can also move the serilaization to a Property object:
{{{
#!java
        // Use the builder pattern here
        // Uses ListCompoundProperty and MapCompoundProperty internally
        CompoundProperty<List<ImageryPreferenceEntry> pref = CompoundProperty.serialized(ImageryPreferenceEntry.class).list().for(""imagery.entries"");
        // expects List<Map<String, String>>
        pref.put(layers.stream()
                .map(ImageryPreferenceEntry::new)
                .collect(Collectors.toList())
}}}

Next example:
{{{
#!java
        return Main.pref.getCollection(""imagery.layers.sites"", Arrays.asList(DEFAULT_LAYER_SITES));
}}}

{{{
#!java
        return CompoundProperty.list().for(""imagery.layers.sites"", Arrays.asList(DEFAULT_LAYER_SITES)).get();
}}}
Next example:
{{{
#!java
    private static volatile Collection<String> uninteresting;
    public static Collection<String> getUninterestingKeys() {
        if (uninteresting == null) {
            List<String> l = ...
            uninteresting = Main.pref.getCollection(""tags.uninteresting"", l);
        }
        return uninteresting;
    }
}}}

{{{
#!java
    private static UNINTERESTING = CompoundProperty.list().for(""tags.uninteresting"", l).get().cached();

    public static Collection<String> getUninterestingKeys() {
        return UNINTERESTING.get();
    }
}}}"	enhancement	new	normal		Core			preferences	
