package se.dolkow.tangiblexml;
import android.support.annotation.NonNull;
import android.util.Log;
import android.util.Pair;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import static se.dolkow.tangiblexml.Util.TAG;
final class NodeFactory {
static @NonNull <T,V> ParserNode<T> create(@NonNull Putter<T,V> putter, @NonNull Type what)
throws SetupException {
if (what instanceof Class) {
Class cwhat = (Class)what;
if (cwhat.equals(String.class)) {
//noinspection unchecked
return new TextNodes.Str<>((Putter<T,String>) putter);
} else if (cwhat.equals(Integer.class)) {
//noinspection unchecked
return new TextNodes.Int<>((Putter<T,Integer>) putter);
} else {
//noinspection unchecked
return new TangibleNode(putter, cwhat);
}
} else if (what instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) what;
final Class raw, param;
try {
raw = (Class) pt.getRawType();
} catch (ClassCastException e) {
throw new SetupException("Expected the raw type to be a class", e);
}
final Type[] params = pt.getActualTypeArguments();
if (params.length != 1) {
throw new SetupException("Expected exactly one type parameter in " + pt);
}
try {
param = (Class) params[0];
} catch (ClassCastException e) {
throw new SetupException("Type param must be a plain class, was " + params[0]);
}
if (List.class.isAssignableFrom(raw)) {
//noinspection unchecked
return new ListNode(putter, raw, param);
} else {
throw new SetupException("Unhandled type " + pt);
}
} else {
throw new SetupException("Unhandled kind of type: " + what);
}
}
static @NonNull <T> InnerNode<T> createTree(@NonNull Class<? extends T> what)
throws SetupException {
InnerNode<T> root = new InnerNode<>();
TangibleFieldCache cache = TangibleFieldCache.getInstance();
final Pair<Field, TangibleField>[] fields = cache.get(what);
if (fields.length == 0) {
String msg = "Potential bug: Created node tree for "
+ what + ", which has no TangibleFields.";
Log.w(TAG, msg);
}
for (Pair<Field, TangibleField> pair : fields) {
Field f = pair.first;
TangibleField a = pair.second;
//noinspection unchecked
root.extend(a.value().split("/"), new FieldPutter(f), f.getGenericType());
}
return root;
}
}