package fr.openwide.core.wicket.more.link.descriptor.builder.state.parameter.mapping;
import java.util.Collection;
import java.util.TreeSet;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.bindgen.binding.AbstractBinding;
import org.springframework.core.convert.TypeDescriptor;
import com.google.common.base.Supplier;
import fr.openwide.core.wicket.more.link.descriptor.builder.state.main.common.IMappableParameterDeclarationState;
import fr.openwide.core.wicket.more.link.descriptor.builder.state.parameter.chosen.common.IChosenParameterState;
import fr.openwide.core.wicket.more.link.descriptor.builder.state.parameter.chosen.common.IOneChosenParameterState;
import fr.openwide.core.wicket.more.link.descriptor.generator.ILinkGenerator;
import fr.openwide.core.wicket.more.link.descriptor.mapper.ILinkDescriptorMapper;
import fr.openwide.core.wicket.more.link.descriptor.parameter.extractor.ILinkParametersExtractor;
import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.ILinkParameterMappingEntry;
/**
* A state where one may map model parameters ({@link IModel}) to link parameters ({@link PageParameters}).
* <p><strong>Note:</strong> instead of using methods from this interface, please consider declaring your model
* parameters using {@link IMappableParameterDeclarationState#model(Class)} and then map those declared parameters using
* one of the methods defined in {@link IChosenParameterState} or {@link IOneChosenParameterState}. This will allow you
* to build a {@link ILinkDescriptorMapper link descriptor mapper}, suitable for use in declarative builders
* such as {@link fr.openwide.core.wicket.more.markup.repeater.table.builder.DataTableBuilder}.
*/
public interface IParameterMappingState
<
TSelf extends IParameterMappingState<TSelf>
> {
/**
* Map the HTTP query parameter with the given name to the given model, making sure that:
* <ul>
* <li>when {@link ILinkParametersExtractor extracting parameters} from a HTTP query, the parameter with the given
* name will get converted and stored in the given model
* <li>when {@link ILinkGenerator generating a link's URL}, the value stored in the given model will get converted
* and assigned to the HTTP query parameter with the given name.
* </ul>
* <p><strong>Note:</strong> collection mapping requires calling {@link #mapCollection(String, IModel, Class, Class)}
* instead.
* @param parameterName The HTTP query parameter name.
* @param valueModel The mapped model.
* @param valueType The expected type of values stored in the model (for use during conversion).
* @return A builder state where you will decide whether the newly created mapping is either mandatory or optional.
*/
<T> IAddedParameterMappingState<TSelf> map(String parameterName, IModel<T> valueModel, Class<T> valueType);
/**
* Map the HTTP query parameter with the given name to the given model.
* <p>This method should be used when the model is expected to contain a collection, since it enables implementors
* to convert collection elements as well as the collection itself.
* @param parameterName The HTTP query parameter name.
* @param valueModel The mapped model.
* @param rawCollectionType The expected type of values stored in the model (for use during conversion).
* @param elementType The expected type of elements stored in the collection (for use during conversion).
* @see #map(String, IModel, Class)
*/
@SuppressWarnings("rawtypes")
<RawC extends Collection, C extends RawC, T> IAddedParameterMappingState<TSelf> mapCollection(
String parameterName, IModel<C> valueModel,
Class<RawC> rawCollectionType, Class<T> elementType);
/**
* Map the HTTP query parameter with the given name to the given model.
* <p>This method should be used when the model is expected to contain a <strong>collection of collections</strong>,
* since it enables implementors to convert collection elements as well as the collection itself.
* @param parameterName The HTTP query parameter name.
* @param valueModel The mapped model.
* @param rawCollectionType The expected type of values stored in the model (for use during conversion).
* @param elementTypeDescriptor The expected type of elements stored in the collection (for use during conversion).
* @see #map(String, IModel, Class)
*/
@SuppressWarnings("rawtypes")
<RawC extends Collection, C extends RawC, T> IAddedParameterMappingState<TSelf> mapCollection(
String parameterName, IModel<C> valueModel,
Class<RawC> rawCollectionType, TypeDescriptor elementTypeDescriptor);
/**
* Similar to {@link #mapCollection(String, IModel, Class, TypeDescriptor)}, but additionally allows to define the
* exact collection implementation to use (for instance a {@link TreeSet} even if the raw type is simply
* {@link Collection}).
*/
@SuppressWarnings("rawtypes")
<RawC extends Collection, C extends RawC, T> IAddedParameterMappingState<TSelf> mapCollection(
String parameterName, IModel<C> valueModel,
Class<RawC> rawCollectionType, TypeDescriptor elementTypeDescriptor, Supplier<C> emptyCollectionSupplier);
/**
* Register a {@link ILinkParameterMappingEntry} that will handle the process of mapping HTTP query parameters
* to its internal models.
* @param parameterMappingEntry The object responsible for mapping parameters.
* @return A builder state where you will decide whether the newly created mapping is either mandatory or optional.
*/
IAddedParameterMappingState<TSelf> map(ILinkParameterMappingEntry parameterMappingEntry);
/**
* Map HTTP query parameter with the given name to the given model, making sure that:
* <ul>
* <li>when {@link ILinkParametersExtractor extracting parameters} from a HTTP query, the parameter
* <strong>is not written to the given model</strong>.
* <li>when {@link ILinkGenerator generating a link's URL}, the value stored in the given model will get converted
* and assigned to the HTTP query parameter with the given name.
* </ul>
* <p>This is useful when dealing with interrelated HTTP query parameters where one parameters will fully determine
* another, in which case the latter will only be here for cosmetics.
* @param parameterName The HTTP query parameter name.
* @param valueModel The mapped model.
* @return A builder state where you will decide whether the newly created mapping is either mandatory or optional.
*/
<T> IAddedParameterMappingState<TSelf> renderInUrl(String parameterName, IModel<T> valueModel);
/**
* Shorthand for <code>renderInUrl(parameterName, BindingModel.of(rootModel, binding))</code>
* @see #renderInUrl(String, IModel)
*/
<R, T> IAddedParameterMappingState<TSelf> renderInUrl(String parameterName, IModel<R> rootModel, AbstractBinding<R, T> binding);
}