package com.revolsys.collection.map;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.util.JavaBeanUtil;
import com.revolsys.util.Property;
public interface Maps {
public static final Supplier<Map<?, ?>> FACTORY_TREE = () -> {
return new TreeMap<>();
};
public static final Supplier<Map<?, ?>> FACTORY_LINKED_HASH = () -> {
return new LinkedHashMap<>();
};
public static final Supplier<Map<?, ?>> FACTORY_HASH = () -> {
return new HashMap<>();
};
static <K1, V> boolean addAllToSet(final Map<K1, Set<V>> map, final K1 key1,
final Collection<? extends V> values) {
if (Property.hasValue(values)) {
final Set<V> set = getSet(map, key1);
return set.addAll(values);
} else {
return true;
}
}
static <K> Integer addCount(final Map<K, Integer> counts, final K key) {
Integer count = counts.get(key);
if (count == null) {
count = 1;
} else {
count++;
}
counts.put(key, count);
return count;
}
static <K, V, C extends Collection<V>> boolean addToCollection(final Supplier<C> supplier,
final Map<K, C> map, final K key, final V value) {
final C values = get(map, key, supplier);
return values.add(value);
}
static <K1, V> boolean addToList(final Map<K1, List<V>> map, final K1 key1, final V value) {
if (map != null && key1 != null) {
final List<V> values = getList(map, key1);
return values.add(value);
} else {
return false;
}
}
static <K1, K2, V> boolean addToList(final Map<K1, Map<K2, List<V>>> map, final K1 key1,
final K2 key2, final V value) {
final List<V> values = getList(map, key1, key2);
return values.add(value);
}
static <K1, K2, V> boolean addToList(final Supplier<Map<K2, List<V>>> supplier,
final Map<K1, Map<K2, List<V>>> map, final K1 key1, final K2 key2, final V value) {
final List<V> values = getList(supplier, map, key1, key2);
return values.add(value);
}
static <K1, K2, V> V addToMap(final Map<K1, Map<K2, V>> map, final K1 key1, final K2 key2,
final V value) {
final Map<K2, V> mapValue = getMap(map, key1);
return mapValue.put(key2, value);
}
static <K1, K2, V> V addToMap(final Supplier<Map<K2, V>> supplier, final Map<K1, Map<K2, V>> map,
final K1 key1, final K2 key2, final V value) {
final Map<K2, V> mapValue = getMap(supplier, map, key1);
return mapValue.put(key2, value);
}
static <K1, V> boolean addToSet(final Map<K1, Set<V>> map, final K1 key1, final V value) {
final Set<V> values = getSet(map, key1);
return values.add(value);
}
static <K1, V> boolean addToTreeSet(final Map<K1, Set<V>> map, final Comparator<V> comparator,
final K1 key1, final V value) {
final Set<V> values = getTreeSet(map, comparator, key1);
return values.add(value);
}
static <K1, V> boolean addToTreeSet(final Map<K1, Set<V>> map, final K1 key1, final V value) {
final Set<V> values = getTreeSet(map, key1);
if (values == null) {
return false;
} else {
return values.add(value);
}
}
static <K, V> MapBuilder<K, V> buildHash() {
final Map<K, V> map = newHash();
return new MapBuilder<>(map);
}
static <K, V> MapBuilder<K, V> buildHashEx() {
final Map<K, V> map = newHash();
return new MapBuilder<>(map);
}
static <K, V> MapBuilder<K, V> buildLinkedHash() {
final Map<K, V> map = newLinkedHash();
return new MapBuilder<>(map);
}
static <K, V> MapBuilder<K, V> buildLinkedHash(final Map<K, V> values) {
final Map<K, V> map = newLinkedHash(values);
return new MapBuilder<>(map);
}
static <K, V> MapBuilder<K, V> buildTree() {
final Map<K, V> map = newTree();
return new MapBuilder<>(map);
}
static <K, V> boolean collectionContains(final Map<K, ? extends Collection<? extends V>> map,
final K key, final V value) {
if (map == null || key == null) {
return false;
} else {
final Collection<? extends V> collection = map.get(key);
if (collection == null) {
return false;
} else {
return collection.contains(value);
}
}
}
static <K1, V> boolean containsInCollection(final Map<K1, ? extends Collection<V>> map,
final K1 key, final V value) {
final Collection<V> collection = map.get(key);
if (collection == null) {
return false;
} else {
return collection.contains(value);
}
}
static <K1, K2, V> boolean containsKey(final Map<K1, Map<K2, V>> map, final K1 key1,
final K2 key2) {
final Map<K2, V> mapValue = getMap(map, key1);
return mapValue.containsKey(key2);
}
static <T> Integer decrementCount(final Map<T, Integer> counts, final T key) {
Integer count = counts.get(key);
if (count == null) {
return 0;
} else {
count--;
if (count <= 0) {
counts.remove(key);
} else {
counts.put(key, count);
}
return count;
}
}
static boolean equalMap1Keys(final Map<String, Object> map1, final Map<String, Object> map2) {
if (map1 == null) {
return false;
} else if (map2 == null) {
return false;
} else {
for (final String key : map1.keySet()) {
final boolean equals = equals(map1, map2, key);
if (!equals) {
return false;
}
}
return true;
}
}
static boolean equals(final Map<String, Object> map1, final Map<String, Object> map2,
final String key) {
final Object value1 = map1.get(key);
final Object value2 = map2.get(key);
final boolean equals = DataType.equal(value1, value2);
return equals;
}
static boolean equalsNotNull(final Map<Object, Object> map1, final Map<Object, Object> map2) {
final Set<Object> keys = new TreeSet<>();
keys.addAll(map1.keySet());
keys.addAll(map2.keySet());
for (final Object key : keys) {
final Object value1 = map1.get(key);
final Object value2 = map2.get(key);
if (!DataType.equal(value1, value2)) {
return false;
}
}
return true;
}
static boolean equalsNotNull(final Map<Object, Object> map1, final Map<Object, Object> map2,
final Collection<? extends CharSequence> exclude) {
final Set<Object> keys = new TreeSet<>();
keys.addAll(map1.keySet());
keys.addAll(map2.keySet());
keys.removeAll(exclude);
for (final Object key : keys) {
final Object value1 = map1.get(key);
final Object value2 = map2.get(key);
if (!DataType.equal(value1, value2, exclude)) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
static boolean equalsNotNull(final Object map1, final Object map2) {
return equalsNotNull((Map<Object, Object>)map1, (Map<Object, Object>)map2);
}
@SuppressWarnings("unchecked")
static boolean equalsNotNull(final Object map1, final Object map2,
final Collection<? extends CharSequence> exclude) {
return equalsNotNull((Map<Object, Object>)map1, (Map<Object, Object>)map2, exclude);
}
@SuppressWarnings({
"unchecked", "rawtypes"
})
static <K, V> Supplier<Map<K, V>> factoryHash() {
return (Supplier)FACTORY_HASH;
}
@SuppressWarnings({
"unchecked", "rawtypes"
})
static <K, V> Supplier<Map<K, V>> factoryLinkedHash() {
return (Supplier)FACTORY_LINKED_HASH;
}
@SuppressWarnings({
"unchecked", "rawtypes"
})
static <K, V> Supplier<Map<K, V>> factoryTree() {
return (Supplier)FACTORY_TREE;
}
static <V> V first(final Map<?, V> map) {
if (Property.hasValue(map)) {
return map.values().iterator().next();
}
return null;
}
@SuppressWarnings("unchecked")
static <K, V> V get(final Map<K, ? extends Object> map, final K key) {
if (map == null) {
return null;
} else {
return (V)map.get(key);
}
}
/**
* Get the value for the key from the map. If the value was null return
* default Value instead. The default value will be added to the map.
*
* @param map The map.
* @param key The key to return the value for.
* @param defaultValue The default value.
* @return The value.
*/
static <K, V> V get(final Map<K, ? super V> map, final K key, final V defaultValue) {
if (map == null) {
return defaultValue;
} else {
@SuppressWarnings("unchecked")
final V value = (V)map.get(key);
if (value == null) {
map.put(key, defaultValue);
return defaultValue;
} else {
return value;
}
}
}
static <K, V> V get(final Map<K, V> map, final K key, final Function<K, V> defaultFactory) {
V value = map.get(key);
if (value == null) {
value = defaultFactory.apply(key);
map.put(key, value);
}
return value;
}
static <K, V> V get(final Map<K, V> map, final K key, final Supplier<V> defaultFactory) {
V value = map.get(key);
if (value == null) {
value = defaultFactory.get();
map.put(key, value);
}
return value;
}
@SuppressWarnings({
"unchecked", "rawtypes"
})
static <K, V> V get(final Supplier<V> supplier, final Map<K, ? extends Object> map, final K key) {
V value = (V)map.get(key);
if (value == null) {
value = supplier.get();
((Map)map).put(key, value);
}
return value;
}
static boolean getBool(final Map<String, ? extends Object> map, final String name) {
final Object value = get(map, name);
if (value == null) {
return false;
} else if (value instanceof Boolean) {
return (Boolean)value;
} else {
return Boolean.parseBoolean(value.toString());
}
}
static boolean getBool(final Map<String, ? extends Object> map, final String name,
final boolean defaultValue) {
final Object value = get(map, name);
if (value == null) {
return defaultValue;
} else if (value instanceof Boolean) {
return (Boolean)value;
} else {
return Boolean.parseBoolean(value.toString());
}
}
static Boolean getBoolean(final Map<String, ? extends Object> map, final String name) {
final Object value = get(map, name);
if (value == null) {
return null;
} else if (value instanceof Boolean) {
return (Boolean)value;
} else {
return Boolean.valueOf(value.toString());
}
}
static <T> Integer getCount(final Map<T, Integer> counts, final T key) {
final Integer count = counts.get(key);
if (count == null) {
return 0;
} else {
return count;
}
}
static <K> Double getDouble(final Map<K, ? extends Object> map, final K name) {
final Object value = get(map, name);
if (value == null) {
return null;
} else if (value instanceof Number) {
final Number number = (Number)value;
return number.doubleValue();
} else {
final String stringValue = value.toString();
if (Property.hasValue(stringValue)) {
try {
return Double.valueOf(stringValue);
} catch (final NumberFormatException e) {
return null;
}
} else {
return null;
}
}
}
static <K> double getDouble(final Map<K, ? extends Object> object, final K name,
final double defaultValue) {
final Double value = getDouble(object, name);
if (value == null) {
return defaultValue;
} else {
return value;
}
}
static Double getDoubleValue(final Map<String, ? extends Object> map, final String name) {
final Number value = (Number)get(map, name);
if (value == null) {
return null;
} else {
return value.doubleValue();
}
}
static <K> K getFirstKey(final Map<K, ?> map) {
return map.keySet().iterator().next();
}
static <V> V getFirstValue(final Map<?, V> map) {
return map.values().iterator().next();
}
static <K> Integer getInteger(final Map<K, ? extends Object> map, final K name) {
final Object value = get(map, name);
if (value == null) {
return null;
} else if (value instanceof Number) {
final Number number = (Number)value;
return number.intValue();
} else {
final String stringValue = value.toString();
if (Property.hasValue(stringValue)) {
try {
return Integer.valueOf(stringValue);
} catch (final NumberFormatException e) {
return null;
}
} else {
return null;
}
}
}
static <K> int getInteger(final Map<K, ? extends Object> object, final K name,
final int defaultValue) {
final Integer value = getInteger(object, name);
if (value == null) {
return defaultValue;
} else {
return value;
}
}
static <K, V> List<V> getList(final Map<K, List<V>> map, final K key) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList<>();
map.put(key, list);
}
return list;
}
static <K1, K2, V> List<V> getList(final Map<K1, Map<K2, List<V>>> map, final K1 key1,
final K2 key2) {
final Map<K2, List<V>> map2 = getMap(map, key1);
final List<V> list = getList(map2, key2);
return list;
}
static <K1, K2, V> List<V> getList(final Supplier<Map<K2, List<V>>> supplier,
final Map<K1, Map<K2, List<V>>> map, final K1 key1, final K2 key2) {
final Map<K2, List<V>> map2 = getMap(supplier, map, key1);
final List<V> list = getList(map2, key2);
return list;
}
static Long getLong(final Map<String, ? extends Object> map, final String name) {
final Object value = get(map, name);
if (value == null) {
return null;
} else if (value instanceof Number) {
final Number number = (Number)value;
return number.longValue();
} else {
final String stringValue = value.toString();
if (Property.hasValue(stringValue)) {
try {
return Long.valueOf(stringValue);
} catch (final NumberFormatException e) {
return null;
}
} else {
return null;
}
}
}
static long getLong(final Map<String, ? extends Object> map, final String name,
final long defaultValue) {
final Object value = get(map, name);
if (value == null) {
return defaultValue;
} else if (value instanceof Number) {
final Number number = (Number)value;
return number.longValue();
} else {
final String stringValue = value.toString();
if (Property.hasValue(stringValue)) {
try {
return Long.valueOf(stringValue);
} catch (final NumberFormatException e) {
throw new IllegalArgumentException(value + " is not a valid long");
}
} else {
return defaultValue;
}
}
}
static <K1, K2, V> Map<K2, V> getMap(final Map<K1, Map<K2, V>> map, final K1 key) {
Map<K2, V> value = map.get(key);
if (value == null) {
value = newLinkedHash();
map.put(key, value);
}
return value;
}
static <K1, K2, V> V getMap(final Map<K1, Map<K2, V>> map, final K1 key1, final K2 key2) {
final Map<K2, V> values = getMap(map, key1);
return values.get(key2);
}
static <K1, K2, V> V getMap(final Map<K1, Map<K2, V>> map, final K1 key1, final K2 key2,
final Supplier<V> supplier) {
final Map<K2, V> values = getMap(map, key1);
return get(supplier, values, key2);
}
static <K1, K2, V> V getMap(final Map<K1, Map<K2, V>> map, final K1 key1, final K2 key2,
final V defaultValue) {
final Map<K2, V> values = getMap(map, key1);
final V value = values.get(key2);
if (value == null) {
return defaultValue;
} else {
return value;
}
}
static <K1, K2, V> Map<K2, V> getMap(final Supplier<Map<K2, V>> supplier,
final Map<K1, Map<K2, V>> map, final K1 key) {
Map<K2, V> value = map.get(key);
if (value == null) {
value = supplier.get();
map.put(key, value);
}
return value;
}
static <K, V> List<V> getNotNull(final Map<K, V> map, final Collection<K> keys) {
final List<V> values = new ArrayList<>();
if (keys != null) {
for (final K key : keys) {
final V value = map.get(key);
if (value != null) {
values.add(value);
}
}
}
return values;
}
static <K, V> Set<V> getSet(final Map<K, Set<V>> map, final K key) {
Set<V> value = map.get(key);
if (value == null) {
value = new LinkedHashSet<>();
map.put(key, value);
}
return value;
}
static String getString(final Map<String, ? extends Object> map, final String name) {
final Object value = get(map, name);
if (value == null) {
return null;
} else {
return DataTypes.toString(value);
}
}
static String getString(final Map<String, ? extends Object> map, final String name,
final String defaultValue) {
final Object value = get(map, name);
if (value == null) {
return defaultValue;
} else {
return DataTypes.toString(value);
}
}
static <K1, K2, V> Map<K2, V> getTreeMap(final Map<K1, Map<K2, V>> map, final K1 key) {
Map<K2, V> value = map.get(key);
if (value == null) {
value = newTree();
map.put(key, value);
}
return value;
}
static <K, V> Set<V> getTreeSet(final Map<K, Set<V>> map, final Comparator<V> comparator,
final K key) {
Set<V> value = map.get(key);
if (value == null) {
value = new TreeSet<>(comparator);
map.put(key, value);
}
return value;
}
static <K, V> Set<V> getTreeSet(final Map<K, Set<V>> map, final K key) {
if (key == null) {
return null;
} else {
Set<V> value = map.get(key);
if (value == null) {
value = new TreeSet<>();
map.put(key, value);
}
return value;
}
}
static <K> boolean hasValue(final Map<K, ?> map, final K key) {
if (map == null || key == null) {
return false;
} else {
final Object value = map.get(key);
return Property.hasValue(value);
}
}
static boolean isNotNullAndNotZero(final Map<String, Object> object, final String name) {
final Integer value = getInteger(object, name);
if (value == null || value == 0) {
return false;
} else {
return true;
}
}
static <K, V> void mergeCollection(final Map<K, Collection<V>> map,
final Map<K, Collection<V>> otherMap) {
for (final Entry<K, Collection<V>> entry : otherMap.entrySet()) {
final K key = entry.getKey();
Collection<V> collection = map.get(key);
final Collection<V> otherCollection = otherMap.get(key);
if (collection == null) {
collection = JavaBeanUtil.clone(otherCollection);
map.put(key, collection);
} else {
for (final V value : otherCollection) {
if (!collection.contains(value)) {
collection.add(value);
}
}
}
}
}
static <V, K> HashMap<K, V> newHash() {
return new HashMap<>();
}
static <K, V> Map<K, V> newHash(final K key, final V value) {
final Map<K, V> map = newHash();
map.put(key, value);
return map;
}
static <K, V> Map<K, V> newHash(final Map<K, ? extends V> map) {
final Map<K, V> copy = newHash();
if (map != null) {
copy.putAll(map);
}
return copy;
}
static <K, V> LinkedHashMap<K, V> newLinkedHash() {
return new LinkedHashMap<>();
}
static <K, V> Map<K, V> newLinkedHash(final K key, final V value) {
final Map<K, V> map = newLinkedHash();
map.put(key, value);
return map;
}
static <T1, T2> Map<T1, T2> newLinkedHash(final List<T1> sourceValues,
final List<T2> targetValues) {
final Map<T1, T2> map = newLinkedHash();
for (int i = 0; i < sourceValues.size() && i < targetValues.size(); i++) {
final T1 sourceValue = sourceValues.get(i);
final T2 targetValue = targetValues.get(i);
map.put(sourceValue, targetValue);
}
return map;
}
static <K, V> Map<K, V> newLinkedHash(final Map<K, ? extends V> map) {
final Map<K, V> copy = newLinkedHash();
if (map != null) {
copy.putAll(map);
}
return copy;
}
static MapEx newLinkedHashEx(final Map<String, ? extends Object> map) {
final MapEx copy = new LinkedHashMapEx();
if (map != null) {
copy.putAll(map);
}
return copy;
}
static <K, V> Map<K, V> newTree() {
return new TreeMap<>();
}
static <K extends Comparable<K>, V extends Comparable<V>> TreeMap<K, V> newTree(
final Comparator<K> comparator) {
return new TreeMap<>(comparator);
}
static <K, V> Map<K, V> newTree(final Comparator<K> comparator, final Map<K, ? extends V> map) {
final Map<K, V> newMap = newTree();
if (map != null) {
newMap.putAll(map);
}
return newMap;
}
static <K, V> Map<K, V> newTree(final K key, final V value) {
final Map<K, V> map = newTree();
map.put(key, value);
return map;
}
static <K, V> Map<K, V> newTree(final Map<K, ? extends V> map) {
final Map<K, V> newMap = newTree();
if (map != null) {
newMap.putAll(map);
}
return newMap;
}
static <K1, K2, V> V put(final Map<K1, Map<K2, V>> map, final K1 key1, final K2 key2,
final V value) {
final Map<K2, V> values = getMap(map, key1);
return values.put(key2, value);
}
static <K1, K2, V> V put(final Supplier<Map<K2, V>> factory, final Map<K1, Map<K2, V>> map,
final K1 key1, final K2 key2, final V value) {
final Map<K2, V> values = getMap(factory, map, key1);
return values.put(key2, value);
}
static void putAll(final Map<String, Object> map,
final Map<String, ? extends Object> properties) {
if (map != null && properties != null) {
for (final Entry<String, ? extends Object> entry : properties.entrySet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
map.put(key, value);
}
}
}
static void putAll(final Map<String, Object> map, final Properties properties) {
if (map != null && properties != null) {
for (final Entry<Object, Object> entry : properties.entrySet()) {
final String key = (String)entry.getKey();
final Object value = entry.getValue();
map.put(key, value);
}
}
}
static <K, V extends Comparable<V>> void putIfGreaterThan(final Map<K, V> map, final K key,
final V value) {
synchronized (map) {
final V lastValue = map.get(key);
if (lastValue == null || value.compareTo(lastValue) > 1) {
map.put(key, value);
}
}
}
static <K, V> boolean removeFromCollection(final Map<K, ? extends Collection<V>> map, final K key,
final V value) {
final Collection<V> values = map.get(key);
if (values == null) {
return false;
} else {
final boolean removed = values.remove(value);
if (values.isEmpty()) {
map.remove(key);
}
return removed;
}
}
static <K1, K2, V> V removeFromMap(final Map<K1, Map<K2, V>> map, final K1 key1, final K2 key2) {
final Map<K2, V> values = map.get(key1);
if (values == null) {
return null;
} else {
final V value = values.remove(key2);
if (values.isEmpty()) {
map.remove(key1);
}
return value;
}
}
static <K, V> boolean removeFromSet(final Map<K, Set<V>> map, final K key, final V value) {
final Set<V> values = map.get(key);
if (values == null) {
return false;
} else {
final boolean removed = values.remove(value);
if (values.isEmpty()) {
map.remove(key);
}
return removed;
}
}
static <K, V extends Comparable<V>> void removeIfGreaterThanEqual(final Map<K, V> map,
final K key, final V value) {
synchronized (map) {
final V lastValue = map.get(key);
if (lastValue == null || value.compareTo(lastValue) >= 0) {
map.remove(key);
}
}
}
static <K, V extends Comparable<V>> void removeIfLessThanEqual(final Map<K, V> map, final K key,
final V value) {
synchronized (map) {
final V lastValue = map.get(key);
if (lastValue == null || value.compareTo(lastValue) <= 0) {
map.remove(key);
}
}
}
/**
* Retain the value for the key in the map if the map's value is not equal to the value.
* This can be used to create a set of keys values that need to be updated.
*
* @param map
* @param key
* @param value
* @return True if the value was retained (not equal).
*/
static <K, V> boolean retainIfNotEqual(final Map<K, V> map, final K key, final V value) {
final Object currentValue = map.get(key);
if (DataType.equal(currentValue, value)) {
map.remove(key);
return false;
} else {
return true;
}
}
/**
* Retain the value for the key in the map if the map's value is not equal to the value.
* This can be used to create a set of keys values that need to be updated.
*
* @param map
* @param key
* @param value
* @return True if the value was retained (not equal).
*/
static <K, V> void retainIfNotEqual(final Map<K, V> map1, final Map<K, V> map2) {
for (final Entry<K, V> entry : map2.entrySet()) {
final K key = entry.getKey();
final V value = entry.getValue();
retainIfNotEqual(map1, key, value);
}
}
static <K extends Comparable<K>, V extends Comparable<V>> Map<K, V> sortByValues(
final Map<K, V> map) {
final MapValueComparator<K, V> comparator = new MapValueComparator<>(map);
final Map<K, V> sortedMap = newTree(comparator);
sortedMap.putAll(map);
return newLinkedHash(sortedMap);
}
static Map<String, Object> toMap(final Preferences preferences) {
try {
final Map<String, Object> map = newHash();
for (final String name : preferences.keys()) {
final Object value = preferences.get(name, null);
map.put(name, value);
}
return map;
} catch (final BackingStoreException e) {
throw new RuntimeException("Unable to get preferences " + e);
}
}
static Map<String, String> toMap(final String string) {
if (string == null) {
return Collections.emptyMap();
} else {
final Map<String, String> map = newLinkedHash();
for (final String entry : string.split("\n")) {
final String[] pair = entry.split("=");
if (pair.length == 2) {
final String name = pair[0];
final String value = pair[1];
map.put(name, value);
} else {
System.err.println("Invalid entry: " + entry);
}
}
return map;
}
}
}