package it.cavallium.strangedb.java.objects.lists; import it.cavallium.strangedb.java.annotations.DbField; import it.cavallium.strangedb.java.annotations.DbPrimitiveField; import it.cavallium.strangedb.java.annotations.DbProperty; import it.cavallium.strangedb.java.objects.EnhancedObject; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.commons.lang3.reflect.MethodUtils; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; public class ValuePointer { private static ValuePointer base = new ValuePointer(new int[0], new ValueType[0]); private final int[] pathNumbers; private final ValueType[] pathTypes; private ValuePointer(int[] pathNumbers, ValueType[] pathTypes) { this.pathNumbers = pathNumbers; this.pathTypes = pathTypes; } public static ValuePointer ofField(Class parentType, String field) { return base.field(parentType, field); } public static ValuePointer ofProp(Class parentType, String property) { return base.prop(parentType, property); } public static ValuePointer ofPrimitiveField(Class parentType, String primitiveFieldName) { return base.primitiveField(parentType, primitiveFieldName); } public ValuePointer prop(Class parentType, String propertyName) { ValueType[] newPathTypes = append(this.pathTypes, ValueType.FIELD); Method[] methods = MethodUtils.getMethodsWithAnnotation(parentType, DbProperty.class); DbProperty dbProperty = null; for (Method method : methods) { DbProperty annotation = method.getAnnotation(DbProperty.class); if (annotation.name().equals(propertyName)) { dbProperty = annotation; break; } } if (dbProperty == null) { throw new IllegalArgumentException("Property '" + propertyName + "' not found in class " + parentType.getSimpleName()); } int[] newPathNumbers = append(this.pathNumbers, dbProperty.id()); return new ValuePointer(newPathNumbers, newPathTypes); } public ValuePointer field(Class parentType, String fieldName) { ValueType[] newPathTypes = append(this.pathTypes, ValueType.FIELD); Field[] fields = FieldUtils.getFieldsWithAnnotation(parentType, DbField.class); DbField dbField = null; for (Field field : fields) { DbField annotation = field.getAnnotation(DbField.class); if (annotation.name().equals(fieldName)) { dbField = annotation; break; } } if (dbField == null) { throw new IllegalArgumentException("Field '" + fieldName + "' not found in class " + parentType.getSimpleName()); } int[] newPathNumbers = append(this.pathNumbers, dbField.id()); return new ValuePointer(newPathNumbers, newPathTypes); } public ValuePointer primitiveField(Class parentType, String primitiveFieldName) { ValueType[] newPathTypes = append(this.pathTypes, ValueType.PRIMITIVE_FIELD); Field[] fields = FieldUtils.getFieldsWithAnnotation(parentType, DbPrimitiveField.class); DbPrimitiveField dbField = null; for (Field field : fields) { DbPrimitiveField annotation = field.getAnnotation(DbPrimitiveField.class); if (annotation.name().equals(primitiveFieldName)) { dbField = annotation; break; } } if (dbField == null) { throw new IllegalArgumentException("Field '" + primitiveFieldName + "' not found in class " + parentType.getSimpleName()); } int[] newPathNumbers = append(this.pathNumbers, dbField.id()); return new ValuePointer(newPathNumbers, newPathTypes); } public ValuePointer at(int index) { if (index >= pathNumbers.length) { throw new ArrayIndexOutOfBoundsException(); } if (index == pathNumbers.length - 1) { return this; } return new ValuePointer(Arrays.copyOf(this.pathNumbers, index + 1), Arrays.copyOf(this.pathTypes, index + 1)); } public int size() { return this.pathNumbers.length; } public boolean hasPrevious() { return pathNumbers.length > 0; } public ValuePointer previous() { return at(pathNumbers.length - 2); } private static int[] append(int[] array, int value) { int[] newArray = Arrays.copyOf(array, array.length + 1); newArray[array.length] = value; return newArray; } private static T[] append(T[] array, T value) { T[] newArray = Arrays.copyOf(array, array.length + 1); newArray[array.length] = value; return newArray; } public int getPathNumber() { return pathNumbers[pathNumbers.length - 1]; } public ValueType getPathType() { return pathTypes[pathTypes.length - 1]; } }