package com.github.florent37.rxandroidorm;
import com.github.florent37.rxandroidorm.annotations.Id;
import com.github.florent37.rxandroidorm.annotations.Ignore;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
/**
* Created by florentchampigny on 17/01/16.
*/
public class ProcessUtils {
public static List<VariableElement> filterIgnore(List<VariableElement> elements) {
List<VariableElement> filtered = new ArrayList<>();
for (VariableElement variableElement : elements) {
if (variableElement.getAnnotation(Ignore.class) == null && !Constants.PARCEL_CREATOR.equals(
ProcessUtils.getObjectName(variableElement)) || ProcessUtils.isNotVariable(variableElement)) {
filtered.add(variableElement);
}
}
return filterStaticFinal(filtered);
}
private static boolean isNotVariable(VariableElement variableElement) {
return variableElement.getKind() == ElementKind.ENUM ||
variableElement.getKind() == ElementKind.INTERFACE ||
variableElement.getKind() == ElementKind.CLASS;
}
public static List<VariableElement> filterStaticFinal(List<VariableElement> elements) {
List<VariableElement> filtered = new ArrayList<>();
for (VariableElement variableElement : elements) {
final Set<Modifier> modifiers = variableElement.getModifiers();
if (!modifiers.containsAll(Arrays.asList(Modifier.FINAL, Modifier.STATIC))) {
filtered.add(variableElement);
}
} return filtered;
}
public static List<VariableElement> getFields(Element element) {
return filterIgnore(ElementFilter.fieldsIn(element.getEnclosedElements()));
}
public static List<VariableElement> getPrimitiveFields(Element element) {
List<VariableElement> primitives = new ArrayList<>();
for (VariableElement e : getFields(element)) {
if (isPrimitive(e) && !isCollectionOfPrimitive(e) && !isNotVariable(e)) {
primitives.add(e);
}
}
return filterIgnore(primitives);
}
public static List<VariableElement> getCollectionsOfPrimitiveFields(Element element) {
List<VariableElement> collectionsOfPrimitives = new ArrayList<>();
for (VariableElement e : getFields(element)) {
if (isCollectionOfPrimitive(e) && !isNotVariable(e)) {
collectionsOfPrimitives.add(e);
}
}
return filterIgnore(collectionsOfPrimitives);
}
public static List<VariableElement> getNonPrimitiveClassFields(Element element) {
List<VariableElement> nonPrimitive = new ArrayList<>();
for (VariableElement e : getFields(element)) {
if (!isPrimitive(e) && !isCollectionOfPrimitive(e) && !isNotVariable(e)) {
nonPrimitive.add(e);
}
}
return filterIgnore(nonPrimitive);
}
public static boolean hasIdField(Element element) {
return getIdField(element) != null;
}
public static Element getIdField(Element element) {
for (VariableElement e : getFields(element)) {
if (isIdField(e)) {
return e;
}
}
return null;
}
public static String getFieldType(VariableElement variableElement) {
TypeName typeName = getFieldClass(variableElement);
if (typeName == TypeName.INT || typeName == TypeName.BOOLEAN || typeName == TypeName.BYTE) {
return "Int";
} else if (typeName == TypeName.LONG) {
return "Long";
} else if (typeName == TypeName.FLOAT) {
return "Float";
} else if (typeName == TypeName.DOUBLE) {
return "Double";
} else if (ClassName.get(String.class).equals(typeName)) {
return "String";
}
return "";
}
public static String getFieldCast(VariableElement variableElement) {
TypeName typeName = getFieldClass(variableElement);
if (typeName == TypeName.BOOLEAN) {
return "(1 == %s)";
}
return "%s";
}
public static String getFieldTableType(Element variableElement) {
TypeName typeName = getFieldClass(variableElement);
if (typeName == TypeName.INT
|| typeName == TypeName.BOOLEAN
|| typeName == TypeName.LONG
|| typeName == TypeName.BYTE) {
return "integer";
}
if (typeName == TypeName.FLOAT) {
return "real";
} else if (ClassName.get(String.class).equals(typeName) || isDate(typeName)) {
return "text";
}
return null;
}
public static String getObjectName(Element element) {
return element.getSimpleName().toString();
}
public static boolean isIdField(Element element) {
return element.getAnnotation(Id.class) != null && TypeName.LONG.equals(TypeName.get(element.asType()));
}
public static String getObjectPackage(Element element) {
return element.getEnclosingElement().toString();
}
public static TypeName getCursorHelper(Element element) {
return ClassName.get(getObjectPackage(element), getCursorHelperName(getObjectName(element)));
}
public static String getCursorHelperName(String objectName) {
return objectName + Constants.CURSOR_HELPER_SUFFIX;
}
public static String getQueryBuilderName(String modelName) {
return modelName + Constants.QUERY_BUILDER_SUFFIX;
}
public static TypeName getQueryBuilder(Element element) {
return ClassName.get(getObjectPackage(element), getObjectName(element) + Constants.QUERY_BUILDER_SUFFIX);
}
public static String getModelDaoName(Element element) {
return getModelDaoName(getObjectName(element));
}
public static String getModelDaoName(String modelName) {
return modelName + Constants.DAO_SUFFIX;
}
public static ClassName getModelDao(Element element) {
return ClassName.get(getObjectPackage(element), getModelDaoName(element));
}
public static ParameterizedTypeName listOf(TypeName type) {
return ParameterizedTypeName.get(ClassName.get(List.class), type);
}
public static ParameterizedTypeName listOf(Element element) {
return ParameterizedTypeName.get(ClassName.get(List.class), getFieldClass(element));
}
public static ParameterizedTypeName listOf(Class classe) {
return ParameterizedTypeName.get(ClassName.get(List.class), ClassName.get(classe));
}
public static ParameterizedTypeName arraylistOf(TypeName type) {
return ParameterizedTypeName.get(ClassName.get(ArrayList.class), type);
}
public static ParameterizedTypeName arraylistOf(Class classe) {
return ParameterizedTypeName.get(ClassName.get(ArrayList.class), ClassName.get(classe));
}
public static boolean isPrimitive(Element element) {
return isPrimitive(TypeName.get(element.asType()));
}
public static boolean isModelId(VariableElement variableElement) {
return Constants.FIELD_ID.equals(variableElement.getSimpleName().toString());
}
public static TypeName unbox(TypeName typeName) {
try {
return typeName.unbox();
} catch (Exception e) {
return typeName;
}
}
public static boolean isPrimitive(TypeName typeName) {
return typeName.isPrimitive()
|| unbox(typeName).isPrimitive()
|| (ClassName.get(String.class).equals(typeName))
|| isDate(typeName);
}
public static boolean isCollectionOfPrimitive(Element element) {
return isCollection(element) && isPrimitive(getFieldClass(element));
}
public static String getQueryCast(VariableElement variableElement) {
TypeName typeName = getFieldClass(variableElement);
if (ClassName.get(String.class).equals(typeName)) {
return "$L";
} else if (typeName == TypeName.BOOLEAN || typeName.equals(TypeName.get(Boolean.class))) {
return "String.valueOf($L ? 1 : 0)";
} else {
return "String.valueOf($L)";
}
}
public static String getKeyName(VariableElement variableElement) {
return getKeyName(getFieldClassName(variableElement));
}
public static String getKeyName(String modelName) {
return modelName.toLowerCase() + "_id";
}
public static String getTableName(String elementName) {
return elementName.toUpperCase();
}
public static String getTableName(Element element) {
return getTableName(getFieldClassName(element));
}
public static List<TypeName> getParameters(Element element) {
try {
return ((ParameterizedTypeName) ParameterizedTypeName.get(element.asType())).typeArguments;
} catch (Exception e) {
return null;
}
}
public static TypeName getEnclosedTypeName(Element element) {
List<TypeName> parameters = getParameters(element);
if (parameters == null || parameters.isEmpty()) {
return null;
} else {
return parameters.get(0);
}
}
public static TypeName getFieldCursorHelperClass(VariableElement element) {
return ClassName.bestGuess(getFieldClass(element).toString() + Constants.CURSOR_HELPER_SUFFIX);
}
public static TypeName getFieldQueryBuilderClass(VariableElement element) {
return ClassName.bestGuess(getFieldClass(element).toString() + Constants.QUERY_BUILDER_SUFFIX);
}
public static TypeName getFieldClass(Element element) {
if (isArray(element)) {
TypeName typeName = getArrayEnclosedType(element);
return unbox(typeName);
} else {
TypeName enclosed = unbox(getEnclosedTypeName(element));
if (enclosed != null) {
return enclosed;
} else {
return unbox(TypeName.get(element.asType()));
}
}
}
public static String getFieldClassName(Element element) {
String name;
TypeName t = getFieldClass(element);
if (t instanceof ClassName) {
ClassName className = (ClassName) t;
name = className.simpleName();
} else {
name = t.toString();
}
return name;
}
public static boolean isArray(Element element) {
try {
return getArrayEnclosedType(element) != null;
} catch (Exception e) {
return false;
}
}
public static TypeName getArrayEnclosedType(Element element) {
return ((ArrayTypeName) ArrayTypeName.get(element.asType())).componentType;
}
public static boolean isCollection(Element element) {
return isArray(element) || getEnclosedTypeName(element) != null;
}
public static String getMethodId(MethodSpec methodSpec) {
return methodSpec.name + methodSpec.parameters.toString();
}
public static TypeName getElementEnumColumn(Element element) {
return ClassName.bestGuess(getFieldClass(element).toString() + Constants.ENUM_COLUMN_SUFFIX);
}
public static String getModelId(Element element, String elementVarialbe, String idVariableName) {
StringBuilder stringBuilder = new StringBuilder();
Element idField = getIdField(element);
if (idField != null) {
stringBuilder.append("java.lang.Long ")
.append(idVariableName)
.append(" = ")
.append(elementVarialbe)
.append(".")
.append(getObjectName(idField));
} else {
stringBuilder.append("java.lang.Long ").append(idVariableName).append(" = ");
stringBuilder.append(elementVarialbe)
.append(" instanceof ")
.append(Constants.entityProxyClassString)
.append(" ? ");
stringBuilder.append(
String.format("((%s.%s)%s).%s()", Constants.DAO_PACKAGE, Constants.MODEL_ENTITY_PROXY_INTERFACE,
elementVarialbe, Constants.MODEL_ENTITY_PROXY_GET_ID_METHOD));
stringBuilder.append(": null");
}
return stringBuilder.toString();
}
public static String setModelId(String variable) {
return String.format("((%s.%s)%s).%s", Constants.DAO_PACKAGE, Constants.MODEL_ENTITY_PROXY_INTERFACE, variable,
Constants.MODEL_ENTITY_PROXY_SET_ID_METHOD);
}
public static TypeName getModelProxy(Element element) {
return ClassName.get(getObjectPackage(element), getObjectName(element) + Constants.MODEL_ENTITY_PROXY);
}
public static String getPrimitiveCursorHelperFunction(Element element) {
TypeName typeName = getFieldClass(element);
if (isArray(element)) {
if (getArrayEnclosedType(element).isPrimitive()) {
if (ClassName.get(String.class).equals(typeName)) {
return "getStringsPrimitiveArray";
} else if (TypeName.INT.equals(typeName)) {
return "getIntegersPrimitiveArray";
} else if (TypeName.LONG.equals(typeName)) {
return "getLongsPrimitiveArray";
} else if (TypeName.FLOAT.equals(typeName)) {
return "getFloatsPrimitiveArray";
} else if (TypeName.DOUBLE.equals(typeName)) {
return "getDoublesPrimitiveArray";
} else if (TypeName.BOOLEAN.equals(typeName)) {
return "getBooleansPrimitiveArray";
}
} else {
if (ClassName.get(String.class).equals(typeName)) {
return "getStringsArray";
} else if (TypeName.INT.equals(typeName)) {
return "getIntegersArray";
} else if (TypeName.LONG.equals(typeName)) {
return "getLongsArray";
} else if (TypeName.FLOAT.equals(typeName)) {
return "getFloatsArray";
} else if (TypeName.DOUBLE.equals(typeName)) {
return "getDoublesArray";
} else if (TypeName.BOOLEAN.equals(typeName)) {
return "getBooleansArray";
}
}
} else {
if (ClassName.get(String.class).equals(typeName)) {
return "getStrings";
} else if (TypeName.INT.equals(typeName)) {
return "getIntegers";
} else if (TypeName.LONG.equals(typeName)) {
return "getLongs";
} else if (TypeName.FLOAT.equals(typeName)) {
return "getFloats";
} else if (TypeName.DOUBLE.equals(typeName)) {
return "getDoubles";
} else if (TypeName.BOOLEAN.equals(typeName)) {
return "getBooleans";
}
}
return null;
}
public static String addPrimitiveCursorHelperFunction(Element element) {
TypeName typeName = getFieldClass(element);
if (ClassName.get(String.class).equals(typeName)) {
return "addStrings";
} else if (TypeName.INT.equals(typeName)) {
return "addIntegers";
} else if (TypeName.LONG.equals(typeName)) {
return "addLongs";
} else if (TypeName.FLOAT.equals(typeName)) {
return "addFloats";
} else if (TypeName.DOUBLE.equals(typeName)) {
return "addDoubles";
} else if (TypeName.BOOLEAN.equals(typeName)) {
return "addBooleans";
}
return null;
}
public static ClassName getSelectorName(Element element) {
TypeName typeName = getFieldClass(element);
if (isCollection(element)) {
if (TypeName.INT.equals(typeName) || TypeName.LONG.equals(typeName) || TypeName.FLOAT.equals(typeName)) {
return Constants.queryBuilder_ListNumberSelectorClassName;
}
if (TypeName.BOOLEAN.equals(typeName)) {
return Constants.queryBuilder_ListBooleanSelectorClassName;
}
if (TypeName.get(String.class).equals(typeName)) {
return Constants.queryBuilder_ListStringSelectorClassName;
}
} else {
if (TypeName.INT.equals(typeName) || TypeName.LONG.equals(typeName) || TypeName.FLOAT.equals(typeName)) {
return Constants.queryBuilder_NumberSelectorClassName;
}
if (TypeName.BOOLEAN.equals(typeName)) {
return Constants.queryBuilder_BooleanSelectorClassName;
}
if (TypeName.get(String.class).equals(typeName)) {
return Constants.queryBuilder_StringSelectorClassName;
}
if (isDate(typeName)) {
return Constants.queryBuilder_DateSelectorClassName;
}
}
return null;
}
public static TypeName getUnboxedClass(Element element) {
TypeName typeName = getFieldClass(element);
if (TypeName.INT.equals(typeName)) {
return TypeName.get(Integer.class);
}
if (TypeName.LONG.equals(typeName)) {
return TypeName.get(Long.class);
}
if (TypeName.FLOAT.equals(typeName)) {
return TypeName.get(Float.class);
}
if (TypeName.DOUBLE.equals(typeName)) {
return TypeName.get(Double.class);
}
if (TypeName.BOOLEAN.equals(typeName)) {
return TypeName.get(Boolean.class);
}
if (TypeName.get(String.class).equals(typeName)) {
return typeName;
}
return null;
}
public static boolean isDate(Element element) {
return isDate(getFieldClass(element));
}
public static boolean isDate(TypeName typeName) {
return Constants.dateClassName.equals(typeName);
}
protected static List<String> getMethodsNames(TypeSpec typeSpec) {
List<String> names = new ArrayList<>();
for (MethodSpec methodSpec : typeSpec.methodSpecs) {
names.add(methodSpec.name + methodSpec.parameters.toString());
}
return names;
}
public static TypeName observableOf(TypeName typeName){
return ParameterizedTypeName.get(Constants.RX_OBSERVABLE, typeName);
}
public static TypeName observableSourceOf(TypeName typeName){
return ParameterizedTypeName.get(Constants.RX_OBSERVABLE_SOURCE, typeName);
}
public static TypeName functionOf(TypeName...typeName){
return ParameterizedTypeName.get(Constants.RX_FUNCTION, typeName);
}
}