package org.deephacks.confit.serialization;
import com.google.common.base.Optional;
import org.deephacks.confit.Config;
import org.deephacks.confit.Id;
import org.deephacks.confit.model.Bean;
import org.deephacks.confit.model.BeanId;
import org.deephacks.confit.model.Events;
import org.deephacks.confit.model.Schema;
import org.deephacks.confit.serialization.ClassToSchemaConverter.ConfigClass;
import org.deephacks.confit.serialization.Conversion.Converter;
import org.deephacks.confit.serialization.Reflections.ClassIntrospector;
import org.deephacks.confit.serialization.Reflections.ClassIntrospector.FieldWrap;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.deephacks.confit.model.Events.CFG102_NOT_CONFIGURABLE;
class ObjectToBeanConverter implements Converter<Object, Bean> {
Conversion conversion = Conversion.get();
@Override
public Bean convert(Object source, Class<? extends Bean> specificType) {
ClassIntrospector i = new ClassIntrospector(source.getClass());
Bean bean = Bean.create(getBeanId(source));
for (FieldWrap field : i.getNonStaticFieldList()) {
field.checkNotPublic();
Object value = field.getValue(source);
if (value == null) {
continue;
}
addProperty(value, bean, field);
}
Schema schema = conversion.convert(source.getClass(), Schema.class);
bean.set(schema);
return bean;
}
@SuppressWarnings("unchecked")
private void addProperty(Object value, Bean bean, FieldWrap fieldwrap) {
Optional<Annotation> optional = fieldwrap.getAnnotation();
ConfigClass field = new ConfigClass();
if (!optional.isPresent()) {
field.name = fieldwrap.getFieldName();
field.desc = "";
} else {
Config config = (Config) optional.get();
field.name = config.name();
field.desc = config.desc();
}
String name = field.name;
if (name == null || "".equals(name)) {
name = fieldwrap.getFieldName();
}
if (fieldwrap.isCollection()) {
Class<?> paramClass = fieldwrap.getType();
Collection<Object> values = (Collection<Object>) value;
if (paramClass.isAnnotationPresent(Config.class)) {
for (Object object : values) {
bean.addReference(name, getRecursiveBeanId(object));
}
} else {
bean.addProperty(name, conversion.convert(values, String.class));
}
} else if (fieldwrap.isMap()) {
Class<?> paramClass = fieldwrap.getMapParamTypes().get(1);
Map<String, Object> values = (Map<String, Object>) value;
if (paramClass.isAnnotationPresent(Config.class)) {
for (Object object : values.values()) {
bean.addReference(name, getRecursiveBeanId(object));
}
}
} else {
if (value.getClass().isAnnotationPresent(Config.class)) {
bean.addReference(name, getRecursiveBeanId(value));
} else {
String converted = conversion.convert(value, String.class);
bean.setProperty(name, converted);
}
}
}
private BeanId getBeanId(Object bean) {
Config config = bean.getClass().getAnnotation(Config.class);
if (config == null) {
throw CFG102_NOT_CONFIGURABLE(bean.getClass());
}
String schemaName = config.name();
if (schemaName == null || "".equals(schemaName.trim())) {
schemaName = bean.getClass().getName();
}
ClassIntrospector i = new ClassIntrospector(bean.getClass());
List<FieldWrap> ids = i.getFieldList(Id.class);
if (ids == null || ids.size() != 1) {
// a lookup
return BeanId.createSingleton(schemaName);
}
FieldWrap id = ids.get(0);
BeanId targetId;
Object idValue = id.getValue(bean);
if (idValue == null) {
throw Events.CFG107_MISSING_ID();
}
targetId = BeanId.create(id.getValue(bean).toString(), schemaName);
return targetId;
}
private BeanId getRecursiveBeanId(Object bean) {
BeanId targetId = getBeanId(bean);
Bean targetBean = conversion.convert(bean, Bean.class);
targetBean.set(conversion.convert(bean.getClass(), Schema.class));
targetId.setBean(targetBean);
return targetId;
}
}