package fr.openwide.core.wicket.more.link.descriptor.builder.impl.main;
import static fr.openwide.core.wicket.more.condition.Condition.anyPermission;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.lang.Args;
import org.bindgen.BindingRoot;
import org.bindgen.binding.AbstractBinding;
import org.javatuples.Pair;
import org.javatuples.Tuple;
import org.springframework.core.convert.TypeDescriptor;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import fr.openwide.core.wicket.more.condition.Condition;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.factory.BuilderTargetFactories;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.factory.IBuilderLinkDescriptorFactory;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.factory.IBuilderMapperLinkDescriptorFactory;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.parameter.AbstractCoreAddedParameterMapperStateImpl;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.parameter.LinkParameterMappingEntryBuilder;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.parameter.LinkParameterTypeInformation;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.parameter.mapping.CollectionLinkParameterMappingEntry;
import fr.openwide.core.wicket.more.link.descriptor.builder.impl.parameter.mapping.SimpleLinkParameterMappingEntry;
import fr.openwide.core.wicket.more.link.descriptor.builder.state.main.common.IMainState;
import fr.openwide.core.wicket.more.link.descriptor.builder.state.parameter.mapping.IAddedParameterMappingState;
import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.ILinkParameterMappingEntry;
import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.InjectOnlyLinkParameterMappingEntry;
import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.factory.ILinkParameterMappingEntryFactory;
import fr.openwide.core.wicket.more.link.descriptor.parameter.validator.ConditionLinkParameterValidator;
import fr.openwide.core.wicket.more.link.descriptor.parameter.validator.ILinkParameterValidator;
import fr.openwide.core.wicket.more.link.descriptor.parameter.validator.factory.ILinkParameterValidatorFactory;
import fr.openwide.core.wicket.more.markup.html.factory.IDetachableFactory;
import fr.openwide.core.wicket.more.markup.html.factory.ModelFactories;
import fr.openwide.core.wicket.more.model.BindingModel;
abstract class AbstractMainStateImpl
<
TSelf extends IMainState<TSelf>,
TEarlyTargetDefinitionLinkDescriptor,
TLateTargetDefinitionPageLinkDescriptor,
TLateTargetDefinitionResourceLinkDescriptor,
TLateTargetDefinitionImageResourceLinkDescriptor
>
implements IMainState<TSelf> {
protected static <T> IDetachableFactory<Tuple, IModel<T>> constantModelFactory(IModel<T> earlyTargetDefinitionTargetModel) {
return ModelFactories.constant(earlyTargetDefinitionTargetModel);
}
private final BuilderTargetFactories<
TEarlyTargetDefinitionLinkDescriptor, ?,
TLateTargetDefinitionPageLinkDescriptor,
TLateTargetDefinitionResourceLinkDescriptor,
TLateTargetDefinitionImageResourceLinkDescriptor
> targetFactories;
private final Map<LinkParameterMappingEntryBuilder<?>, List<Integer>> mappingEntryBuilders;
private final Map<ILinkParameterValidatorFactory<?>, List<Integer>> validatorFactories;
public AbstractMainStateImpl(
BuilderTargetFactories<
TEarlyTargetDefinitionLinkDescriptor, ?,
TLateTargetDefinitionPageLinkDescriptor,
TLateTargetDefinitionResourceLinkDescriptor,
TLateTargetDefinitionImageResourceLinkDescriptor
> targetFactories) {
this.targetFactories = targetFactories;
this.mappingEntryBuilders = Maps.newLinkedHashMap();
this.validatorFactories = Maps.newLinkedHashMap();
}
public AbstractMainStateImpl(AbstractMainStateImpl<
?,
TEarlyTargetDefinitionLinkDescriptor,
TLateTargetDefinitionPageLinkDescriptor,
TLateTargetDefinitionResourceLinkDescriptor,
TLateTargetDefinitionImageResourceLinkDescriptor
> previousMainState) {
this.targetFactories = previousMainState.targetFactories;
this.mappingEntryBuilders = Maps.newLinkedHashMap(previousMainState.mappingEntryBuilders);
this.validatorFactories = Maps.newLinkedHashMap(previousMainState.validatorFactories);
}
@SuppressWarnings("unchecked")
protected TSelf thisAsTSelf() {
return (TSelf) this;
}
@Override
public <T> IAddedParameterMappingState<TSelf> map(String name, IModel<T> valueModel, Class<T> valueType) {
Args.notNull(name, "name");
Args.notNull(valueModel, "valueModel");
Args.notNull(valueType, "valueType");
return map(new SimpleLinkParameterMappingEntry<T>(
name, valueModel, LinkParameterTypeInformation.valueOf(valueType).getTypeDescriptorSupplier()
));
}
@Override
@SuppressWarnings("rawtypes")
public <RawC extends Collection, C extends RawC, T> IAddedParameterMappingState<TSelf>
mapCollection(String parameterName, IModel<C> valueModel, Class<RawC> rawCollectionType,
Class<T> elementType) {
return mapCollection(parameterName, valueModel, rawCollectionType, TypeDescriptor.valueOf(elementType));
}
@Override
@SuppressWarnings("rawtypes")
public <RawC extends Collection, C extends RawC, T> IAddedParameterMappingState<TSelf>
mapCollection(String parameterName, IModel<C> valueModel, Class<RawC> rawCollectionType,
TypeDescriptor elementTypeDescriptor) {
return map(new CollectionLinkParameterMappingEntry<>(
parameterName, valueModel,
LinkParameterTypeInformation.collection(rawCollectionType, elementTypeDescriptor)
.getTypeDescriptorSupplier()
));
}
@Override
@SuppressWarnings("rawtypes")
public <RawC extends Collection, C extends RawC, T> IAddedParameterMappingState<TSelf>
mapCollection(String parameterName, IModel<C> valueModel, Class<RawC> rawCollectionType,
TypeDescriptor elementTypeDescriptor, Supplier<C> emptyCollectionSupplier) {
return map(new CollectionLinkParameterMappingEntry<>(
parameterName, valueModel,
LinkParameterTypeInformation.collection(rawCollectionType, elementTypeDescriptor)
.getTypeDescriptorSupplier(),
emptyCollectionSupplier
));
}
protected final <TTuple extends Tuple> IAddedParameterMappingState<TSelf>
doMap(final ILinkParameterMappingEntryFactory<TTuple> factory, List<Integer> parameterIndices) {
LinkParameterMappingEntryBuilder<TTuple> builder = new LinkParameterMappingEntryBuilder<TTuple>(factory);
mappingEntryBuilders.put(builder, parameterIndices);
return new AbstractCoreAddedParameterMapperStateImpl<TSelf, TTuple>(builder) {
@Override
protected TSelf toNextState(LinkParameterMappingEntryBuilder<TTuple> builder) {
return AbstractMainStateImpl.this.thisAsTSelf();
}
};
}
@Override
public IAddedParameterMappingState<TSelf> map(ILinkParameterMappingEntry parameterMappingEntry) {
Args.notNull(parameterMappingEntry, "parameterMappingEntry");
return doMap(new ConstantLinkParameterMappingEntryFactory(parameterMappingEntry), ImmutableList.<Integer>of());
}
private static class ConstantLinkParameterMappingEntryFactory implements ILinkParameterMappingEntryFactory<Tuple> {
private static final long serialVersionUID = 1L;
private final ILinkParameterMappingEntry parameterMappingEntry;
protected ConstantLinkParameterMappingEntryFactory(ILinkParameterMappingEntry parameterMappingEntry) {
super();
this.parameterMappingEntry = parameterMappingEntry;
}
@Override
public void detach() {
parameterMappingEntry.detach();
}
@Override
public ILinkParameterMappingEntry create(Tuple parameters) {
return parameterMappingEntry;
}
}
@Override
public <T> IAddedParameterMappingState<TSelf> renderInUrl(String parameterName,
IModel<T> valueModel) {
return map(new InjectOnlyLinkParameterMappingEntry<>(parameterName, valueModel));
}
@Override
public <R, T> IAddedParameterMappingState<TSelf> renderInUrl(String parameterName,
IModel<R> rootModel, AbstractBinding<R, T> binding) {
return map(new InjectOnlyLinkParameterMappingEntry<>(parameterName, BindingModel.of(rootModel, binding)));
}
protected final <TTuple extends Tuple> TSelf
doValidator(final ILinkParameterValidatorFactory<TTuple> factory, List<Integer> parameterIndices) {
validatorFactories.put(factory, parameterIndices);
return thisAsTSelf();
}
@Override
public TSelf validator(ILinkParameterValidator validator) {
Args.notNull(validator, "validator");
return doValidator(new ConstantLinkParameterValidatorFactory(validator), ImmutableList.<Integer>of());
}
private static class ConstantLinkParameterValidatorFactory implements ILinkParameterValidatorFactory<Tuple> {
private static final long serialVersionUID = 1L;
private final ILinkParameterValidator validator;
protected ConstantLinkParameterValidatorFactory(ILinkParameterValidator validator) {
super();
this.validator = validator;
}
@Override
public void detach() {
validator.detach();
}
@Override
public ILinkParameterValidator create(Tuple parameters) {
return validator;
}
}
@Override
public TSelf validator(Condition condition) {
Args.notNull(condition, "condition");
return validator(new ConditionLinkParameterValidator(condition));
}
@Override
public TSelf permission(IModel<?> model, String permissionName) {
return validator(new ConditionLinkParameterValidator(Condition.permission(model, permissionName)));
}
@Override
public TSelf permission(IModel<?> model,
String firstPermissionName, String... otherPermissionNames) {
return validator(new ConditionLinkParameterValidator(anyPermission(model, firstPermissionName, otherPermissionNames)));
}
@Override
public <R, T> TSelf permission(
IModel<R> model, BindingRoot<R, T> binding, String firstPermissionName, String... otherPermissionNames) {
return permission(BindingModel.of(model, binding), firstPermissionName, otherPermissionNames);
}
public BuilderTargetFactories<
TEarlyTargetDefinitionLinkDescriptor, ?,
TLateTargetDefinitionPageLinkDescriptor,
TLateTargetDefinitionResourceLinkDescriptor,
TLateTargetDefinitionImageResourceLinkDescriptor
> getTargetFactories() {
return targetFactories;
}
protected final <TTarget, TLinkDescriptor> IBuilderMapperLinkDescriptorFactory<TLinkDescriptor>
mapperLinkDescriptorFactory(
IBuilderLinkDescriptorFactory<TTarget, TLinkDescriptor> linkDescriptorFactory,
IDetachableFactory<? extends Tuple, ? extends IModel<? extends TTarget>> targetFactory,
List<Integer> targetFactoryParameterIndices
) {
return linkDescriptorFactory.forMapper(
Pair.with(targetFactory, targetFactoryParameterIndices),
mappingEntryBuilders, validatorFactories
);
}
}