package com.googlecode.tawus.addons.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.tapestry5.OptionGroupModel;
import org.apache.tapestry5.OptionModel;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.internal.OptionModelImpl;
import org.apache.tapestry5.ioc.services.PropertyAccess;
import org.apache.tapestry5.ioc.services.PropertyAdapter;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.util.AbstractSelectModel;
public class SelectSupport<T> extends AbstractSelectModel implements ValueEncoder<T> {
private final List<T> items;
private Map<String, PropertyAdapter> adapterMap = new HashMap<String, PropertyAdapter>();
private String label;
private PropertyAdapter indexPropertyAdapter;
private TypeCoercer typeCoercer;
private final static Pattern PROPERTY_PATTERN = Pattern.compile("\\$\\{([\\w.$]+)\\}");
public SelectSupport(final List<T> items, final String label, String indexProperty,
final Class<?> valueType, final PropertyAccess access, TypeCoercer typeCoercer) {
this.items = items;
this.label = label;
indexPropertyAdapter = access.getAdapter(valueType).getPropertyAdapter(indexProperty);
if (indexPropertyAdapter == null) {
throw new RuntimeException(String.format("No property '%s' exists for class '%s'",
indexProperty, valueType.getCanonicalName()));
}
Matcher matcher = PROPERTY_PATTERN.matcher(label);
this.typeCoercer = typeCoercer;
while (matcher.find()) {
adapterMap.put(matcher.group(0),
access.getAdapter(valueType).getPropertyAdapter(matcher.group(1)));
}
}
public List<OptionGroupModel> getOptionGroups() {
return null;
}
public List<OptionModel> getOptions() {
final List<OptionModel> options = new ArrayList<OptionModel>();
if (items != null) {
for (T item : items) {
options.add(new OptionModelImpl(toLabel(item), item));
}
}
return options;
}
private String toLabel(Object object) {
String label = this.label;
for (String key : adapterMap.keySet()) {
label = label.replace(key, adapterMap.get(key).get(object).toString());
}
return label;
}
/**
* {@inheritDoc}
*/
public String toClient(T value) {
return typeCoercer.coerce(getIndex(value), String.class);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public T toValue(String clientValue) {
for (T value : items) {
if (getIndex(value).equals(
typeCoercer.coerce(clientValue, indexPropertyAdapter.getType()))) {
return value;
}
}
return null;
}
/**
* Gets the index value for a particular item
*
* @param value
*/
private Object getIndex(Object value) {
Object fieldValue = indexPropertyAdapter.get(value);
if (fieldValue == null) {
throw new RuntimeException("Index property cannot be null");
}
return fieldValue;
}
}