package org.simpleflatmapper.reflect.meta;
import org.simpleflatmapper.util.BooleanSupplier;
import org.simpleflatmapper.util.Predicate;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class ArrayPropertyFinder<T, E> extends AbstractIndexPropertyFinder<T> {
public ArrayPropertyFinder(ArrayClassMeta<T, E> arrayClassMeta, Predicate<PropertyMeta<?, ?>> propertyFilter) {
super(arrayClassMeta, propertyFilter);
}
@Override
protected IndexedElement<T, E> getIndexedElement(IndexedColumn indexedColumn) {
while (elements.size() <= indexedColumn.getIndexValue()) {
elements.add(new IndexedElement<T, E>(
newElementPropertyMeta(elements.size(), "element" + elements.size()), ((ArrayClassMeta<T, E>)classMeta).getElementClassMeta(),
propertyFilter));
}
return (IndexedElement<T, E>) elements.get(indexedColumn.getIndexValue());
}
private PropertyMeta<T, E> newElementPropertyMeta(int index, String name) {
ArrayClassMeta<T, E> arrayClassMeta = (ArrayClassMeta<T, E>) classMeta;
BooleanSupplier appendSetter = new BooleanSupplier() {
@Override
public boolean getAsBoolean() {
return elements.size() == 1;
}
};
return new ArrayElementPropertyMeta<T, E>(name,
classMeta.getType(), arrayClassMeta.getReflectionService(), index, arrayClassMeta,
arrayClassMeta.<T, E>newSetterFactory(appendSetter), arrayClassMeta.<T, E>newGetterFactory());
}
@Override
protected void extrapolateIndex(PropertyNameMatcher propertyNameMatcher, FoundProperty foundProperty, PropertyMatchingScore score, PropertyFinderTransformer propertyFinderTransformer) {
final ClassMeta<E> elementClassMeta = ((ArrayClassMeta)classMeta).getElementClassMeta();
// all element has same type so check if can find any property matching
PropertyMeta<E, ?> property =
elementClassMeta.newPropertyFinder(propertyFilter).findProperty(propertyNameMatcher);
if (property != null) {
for (int i = 0; i < elements.size(); i++) {
IndexedElement element = elements.get(i);
ExtrapolateFoundProperty<T> matchingProperties = new ExtrapolateFoundProperty<T>(element, foundProperty);
lookForAgainstColumn(new IndexedColumn(i, propertyNameMatcher), matchingProperties, score.decrease(i), propertyFinderTransformer);
if (matchingProperties.hasFound()) {
return;
}
}
int index = elements.size();
lookForAgainstColumn(new IndexedColumn(index, propertyNameMatcher), foundProperty, score.decrease(index == 0 ? 0 : (16 + index) ), propertyFinderTransformer);
}
}
@Override
protected boolean isValidIndex(IndexedColumn indexedColumn) {
return indexedColumn.getIndexValue() >= 0;
}
private static class ExtrapolateFoundProperty<T> implements FoundProperty<T> {
private final IndexedElement element;
private final FoundProperty foundProperty;
private boolean found;
public ExtrapolateFoundProperty(IndexedElement element, FoundProperty foundProperty) {
this.element = element;
this.foundProperty = foundProperty;
}
@Override
public <P extends PropertyMeta<T, ?>> void found(P propertyMeta, Runnable selectionCallback, PropertyMatchingScore score) {
String pathCheck;
if (propertyMeta instanceof ArrayElementPropertyMeta) {
pathCheck = SelfPropertyMeta.PROPERTY_PATH;
} else if (propertyMeta.isSubProperty()) {
pathCheck = ((SubPropertyMeta)propertyMeta).getSubProperty().getPath();
} else {
throw new IllegalArgumentException("Excepted match " + propertyMeta);
}
if (!element.hasProperty(pathCheck)) {
foundProperty.found(propertyMeta, selectionCallback, score);
this.found = true;
}
}
public boolean hasFound() {
return found;
}
}
}