package net.filebot.util; import static net.filebot.Logging.*; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import com.cedarsoftware.util.io.JsonReader; import com.cedarsoftware.util.io.JsonWriter; public class PreferencesMap implements Map { private final Preferences prefs; private final Adapter adapter; public PreferencesMap(Preferences prefs, Adapter adapter) { this.prefs = prefs; this.adapter = adapter; } @Override public T get(Object key) { return adapter.get(prefs, key.toString()); } @Override public T put(String key, T value) { adapter.put(prefs, key, value); // don't know previous entry return null; } @Override public T remove(Object key) { adapter.remove(prefs, key.toString()); // don't know removed entry return null; } public String[] keys() { try { return adapter.keys(prefs); } catch (BackingStoreException e) { throw new RuntimeException(e); } } @Override public void clear() { for (String key : keys()) { adapter.remove(prefs, key); } } @Override public boolean containsKey(Object key) { if (key instanceof String) { return Arrays.asList(keys()).contains(key); } return false; } @Override public boolean containsValue(Object value) { for (String key : keys()) { if (value.equals(get(key))) return true; } return false; } @Override public Set> entrySet() { Set> entries = new LinkedHashSet>(); for (String key : keys()) { entries.add(new PreferencesEntry(prefs, key, adapter)); } return entries; } @Override public boolean isEmpty() { return size() == 0; } @Override public Set keySet() { return new LinkedHashSet(Arrays.asList(keys())); } @Override public void putAll(Map map) { for (Map.Entry entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } @Override public int size() { return keys().length; } @Override public Collection values() { List values = new ArrayList(); for (String key : keys()) { values.add(get(key)); } return values; } public static PreferencesMap map(Preferences prefs) { return map(prefs, new StringAdapter()); } public static PreferencesMap map(Preferences prefs, Adapter adapter) { return new PreferencesMap(prefs, adapter); } public static interface Adapter { public String[] keys(Preferences prefs) throws BackingStoreException; public T get(Preferences prefs, String key); public void put(Preferences prefs, String key, T value); public void remove(Preferences prefs, String key); } public static abstract class AbstractAdapter implements Adapter { @Override public abstract T get(Preferences prefs, String key); @Override public abstract void put(Preferences prefs, String key, T value); @Override public String[] keys(Preferences prefs) throws BackingStoreException { return prefs.keys(); } @Override public void remove(Preferences prefs, String key) { prefs.remove(key); } } public static class StringAdapter extends AbstractAdapter { @Override public String get(Preferences prefs, String key) { return prefs.get(key, null); } @Override public void put(Preferences prefs, String key, String value) { prefs.put(key, value); } } public static class SimpleAdapter extends AbstractAdapter { private final Constructor constructor; public SimpleAdapter(Class type) { try { constructor = type.getConstructor(String.class); } catch (Exception e) { throw new IllegalArgumentException(e); } } @Override public T get(Preferences prefs, String key) { String value = prefs.get(key, null); if (value != null) { try { return constructor.newInstance(value); } catch (Exception e) { throw new RuntimeException(e); } } return null; } @Override public void put(Preferences prefs, String key, T value) { prefs.put(key, value.toString()); } public static SimpleAdapter forClass(Class type) { return new SimpleAdapter(type); } } public static class JsonAdapter extends AbstractAdapter { private Class type; public JsonAdapter(Class type) { this.type = type; } @Override public T get(Preferences prefs, String key) { String json = prefs.get(key, null); if (json != null) { try { return type.cast(JsonReader.jsonToJava(json)); } catch (Exception e) { debug.log(Level.WARNING, e, e::getMessage); } } return null; } @Override public void put(Preferences prefs, String key, T value) { prefs.put(key, JsonWriter.objectToJson(value)); } } public static class PreferencesEntry implements Entry { private final String key; private final Preferences prefs; private final Adapter adapter; private T defaultValue = null; public PreferencesEntry(Preferences prefs, String key, Adapter adapter) { this.key = key; this.prefs = prefs; this.adapter = adapter; } @Override public String getKey() { return key; } @Override public T getValue() { T value = adapter.get(prefs, key); return value != null ? value : defaultValue; } @Override public T setValue(T value) { adapter.put(prefs, key, value); return null; } public PreferencesEntry defaultValue(T defaultValue) { this.defaultValue = defaultValue; return this; } public void remove() { adapter.remove(prefs, key); } public void flush() { try { prefs.flush(); } catch (Exception e) { debug.log(Level.WARNING, e.getMessage(), e); } } } }