package openmods.config.simpler;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import openmods.reflection.FieldAccess;
import openmods.utils.CachedFactory;
import openmods.utils.io.IStringSerializer;
import openmods.utils.io.TypeRW;
public class ConfigurableClassAdapter<T> {
public static class NoSuchPropertyException extends RuntimeException {
private static final long serialVersionUID = 1L;
public NoSuchPropertyException(String message) {
super(message);
}
}
private static class FieldAdapter<T> {
private final IStringSerializer<T> serializer;
private final FieldAccess<T> access;
public FieldAdapter(IStringSerializer<T> serializer, FieldAccess<T> access) {
this.serializer = serializer;
this.access = access;
}
public void set(Object instance, String value) {
T converted = serializer.readFromString(value);
access.set(instance, converted);
}
public String get(Object instance) {
T value = access.get(instance);
return String.valueOf(value);
}
}
private final Class<? extends T> cls;
private final Map<String, FieldAdapter<?>> fields;
public ConfigurableClassAdapter(Class<? extends T> cls) {
this.cls = cls;
ImmutableMap.Builder<String, FieldAdapter<?>> fields = ImmutableMap.builder();
for (Field f : cls.getFields()) {
Configurable ann = f.getAnnotation(Configurable.class);
if (ann != null) {
String name = ann.name();
if (name.isEmpty()) name = f.getName();
final FieldAccess<?> access = FieldAccess.create(f);
final IStringSerializer<?> serializer = TypeRW.getStringSerializer(f.getType());
Preconditions.checkState(serializer != null, "Can't find serializer for field %s", f);
@SuppressWarnings({ "rawtypes", "unchecked" })
final FieldAdapter<?> adapter = new FieldAdapter(serializer, access);
fields.put(name, adapter);
}
}
this.fields = fields.build();
}
public Set<String> keys() {
return fields.keySet();
}
private FieldAdapter<?> findField(String key) {
final FieldAdapter<?> fieldAdapter = fields.get(key);
if (fieldAdapter == null) throw new NoSuchPropertyException(String.format("Can't find key %s in class %s", key, cls));
return fieldAdapter;
}
public String get(T instance, String key) {
return findField(key).get(instance);
}
public void set(T instance, String key, String value) {
findField(key).set(instance, value);
}
private static final CachedFactory<Class<?>, ConfigurableClassAdapter<?>> CACHE = new CachedFactory<Class<?>, ConfigurableClassAdapter<?>>() {
@Override
protected ConfigurableClassAdapter<?> create(Class<?> key) {
return new ConfigurableClassAdapter<Object>(key);
}
};
@SuppressWarnings("unchecked")
public static <T> ConfigurableClassAdapter<T> getFor(Class<? extends T> cls) {
return (ConfigurableClassAdapter<T>)CACHE.getOrCreate(cls);
}
}