package org.simpleflatmapper.map.mapper;
import org.simpleflatmapper.map.CaseInsensitiveFieldKeyNamePredicate;
import org.simpleflatmapper.map.FieldKey;
import org.simpleflatmapper.map.property.GetterProperty;
import org.simpleflatmapper.map.property.SetterProperty;
import org.simpleflatmapper.reflect.Getter;
import org.simpleflatmapper.reflect.Setter;
import org.simpleflatmapper.util.BiConsumer;
import org.simpleflatmapper.util.ConstantUnaryFactory;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.UnaryFactory;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractColumnDefinitionProvider<C extends ColumnDefinition<K, C>, K extends FieldKey<K>> implements ColumnDefinitionProvider<C, K> {
protected final List<PredicatedColunnPropertyFactory<C, K>> properties;
public AbstractColumnDefinitionProvider() {
this(new ArrayList<PredicatedColunnPropertyFactory<C, K>>());
}
public AbstractColumnDefinitionProvider(List<PredicatedColunnPropertyFactory<C, K>> properties) {
this.properties = properties;
}
public void addColumnDefinition(Predicate<? super K> predicate, C definition) {
for(Object prop : definition.properties()) {
addColumnProperty(predicate, newFactory(prop));
}
}
public void addColumnDefinition(String name, C definition) {
Predicate<? super K> predicate = newPredicate(name);
for(Object prop : definition.properties()) {
addColumnProperty(predicate, newFactory(prop));
}
}
public void addColumnProperty(String name, Object property) {
addColumnProperty(newPredicate(name), newFactory(property));
}
public void addColumnProperty(Predicate<? super K> predicate, Object property) {
addColumnProperty(predicate, newFactory(property));
}
public void addColumnProperty(Predicate<? super K> predicate, UnaryFactory<? super K, Object> propertyFactory) {
properties.add(new PredicatedColunnPropertyFactory<C, K>(predicate, propertyFactory));
}
private CaseInsensitiveFieldKeyNamePredicate newPredicate(String name) {
return CaseInsensitiveFieldKeyNamePredicate.of(name);
}
private UnaryFactory<? super K, Object> newFactory(Object prop) {
return ConstantUnaryFactory.of(upgrade(prop));
}
private Object upgrade(Object property) {
if (property instanceof Setter) {
return new SetterProperty((Setter<?, ?>) property);
}
if (property instanceof Getter) {
return new GetterProperty((Getter<?, ?>) property);
}
return property;
}
@Override
public C getColumnDefinition(K key) {
C definition = identity();
for(int i = properties.size() - 1; i >= 0; i--) {
PredicatedColunnPropertyFactory<C, K> tuple2 = properties.get(i);
if (tuple2.predicate.test(key)) {
Object columnProperty = tuple2.columnPropertyFactory.newInstance(key);
if (columnProperty != null) {
definition = definition.add(columnProperty);
}
}
}
return definition;
}
protected abstract C identity();
public List<PredicatedColunnPropertyFactory<C, K>> getProperties() {
return properties;
}
@Override
public <CP, BC extends BiConsumer<Predicate<? super K>, CP>> BC forEach(Class<CP> propertyType, BC consumer) {
for (PredicatedColunnPropertyFactory<C, K> tuple2 : properties) {
final UnaryFactory<? super K, Object> unaryFactory = tuple2.columnPropertyFactory;
if (unaryFactory instanceof ConstantUnaryFactory) {
final Object columnProperty = unaryFactory.newInstance(null);
if (propertyType.isInstance(columnProperty)) {
consumer.accept(tuple2.predicate, propertyType.cast(columnProperty));
}
}
}
return consumer;
}
public static class PredicatedColunnPropertyFactory<C extends ColumnDefinition<K, C>, K extends FieldKey<K>> {
private final Predicate<? super K> predicate;
private final UnaryFactory<? super K, Object> columnPropertyFactory;
public PredicatedColunnPropertyFactory(Predicate<? super K> predicate, UnaryFactory<? super K, Object> columnPropertyFactory) {
this.predicate = predicate;
this.columnPropertyFactory = columnPropertyFactory;
}
public Predicate<? super K> getPredicate() {
return predicate;
}
public UnaryFactory<? super K, Object> getColumnPropertyFactory() {
return columnPropertyFactory;
}
}
}