package com.revolsys.io.map;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Supplier;
import com.revolsys.collection.map.LinkedHashMapEx;
import com.revolsys.collection.map.MapEx;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.record.io.format.json.Json;
import com.revolsys.util.Property;
public interface MapSerializer {
default void addAllToMap(final Map<String, Object> map,
final Map<String, ? extends Object> values) {
if (map != null && values != null) {
for (final Entry<String, ? extends Object> entry : values.entrySet()) {
final String name = entry.getKey();
final Object value = entry.getValue();
addToMap(map, name, value);
}
}
}
/**
* <p>Add the value to the map. If the value is a {@link MapSerializer} then add the result of
* {@link MapSerializer#toMap()}. If the value is a supported type add it to the map, otherwise
* convert the value to a string. Null values will be ignored.</p>
*
* @param map
* @param name
* @param value
*/
default void addToMap(final Map<String, Object> map, final String name, final Object value) {
final Object mapValue = toMapValue(value);
if (Property.hasValue(mapValue)) {
map.put(name, mapValue);
} else {
map.remove(mapValue);
}
}
default void addToMap(final Map<String, Object> map, final String name, final Object value,
final Object defaultValue) {
if (DataType.equal(value, defaultValue)) {
map.remove(name);
} else {
final Object mapValue = toMapValue(value);
if (Property.hasValue(mapValue) || defaultValue == null) {
map.put(name, mapValue);
} else {
map.remove(name);
}
}
}
default void addToMap(final Map<String, Object> map, final String name,
final Supplier<Object> supplier) {
final Object value = supplier.get();
addToMap(map, name, supplier);
}
default void addTypeToMap(final Map<String, Object> map, final String type) {
MapObjectFactory.setType(map, type);
}
default MapEx newTypeMap(final String type) {
final MapEx map = new LinkedHashMapEx();
addTypeToMap(map, type);
return map;
}
/**
* <p>Convert the object to a Map of property name, value pairs. The values can be one of
* the following supported types. Other values should be converted to one of these values.</p>
*
* <ul>
* <li>boolean or {@link Boolean}</li>
* <li>byte or {@link Byte}</li>
* <li>short or {@link Short}</li>
* <li>int or {@link Integer}</li>
* <li>long or {@link Long}</li>
* <li>float or {@link Float}</li>
* <li>double or {@link Double}</li>
* <li>{@link String}</li>
* <li>{@link Number} subclasses</li>
* <li>{@link Collection} of supported values</li>
* <li>{@link Map}<String,Object> of supported values</li>
* <li>null</li>
* </ul>
* @return
*/
MapEx toMap();
@SuppressWarnings("rawtypes")
default Object toMapValue(final Object value) {
if (value == null) {
return null;
} else {
if (value instanceof MapSerializer) {
final MapSerializer mapSerializer = (MapSerializer)value;
final Map<String, Object> mapObject = mapSerializer.toMap();
if (mapObject == null || mapObject.isEmpty()) {
return null;
}
return mapObject;
} else if (value instanceof Map) {
final Map<String, Object> mapObject = (Map<String, Object>)value;
if (mapObject.isEmpty()) {
return null;
}
final MapEx map = new LinkedHashMapEx();
for (final Entry<String, Object> entry : mapObject.entrySet()) {
final String name = entry.getKey();
final Object object = entry.getValue();
addToMap(map, name, object);
}
return map;
} else if (value instanceof Collection) {
final Collection collectionObject = (Collection)value;
if (collectionObject.isEmpty()) {
return null;
}
final List<Object> list = new ArrayList<>();
for (final Object object : collectionObject) {
final Object listValue = toMapValue(object);
list.add(listValue);
}
return list;
} else if (value instanceof Boolean) {
return value;
} else if (value instanceof Number) {
return value;
} else if (value instanceof String) {
final String string = (String)value;
if (Property.hasValue(string)) {
return string.trim();
} else {
return null;
}
} else if (value instanceof Component) {
return null;
} else {
final String string = DataTypes.toString(value);
if (Property.hasValue(string)) {
return string.trim();
} else {
return null;
}
}
}
}
default void writeToFile(final Object target) {
if (target != null) {
final MapEx map = toMap();
Json.writeMap(map, target, true);
}
}
}