package javango.contrib.hibernate;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import javango.contrib.hibernate.annotations.Filter;
import javango.contrib.hibernate.annotations.ModelChoiceFieldProperties;
import javango.db.ManagerException;
import javango.db.Managers;
import javango.db.QuerySet;
import javango.forms.fields.AbstractChoiceField;
import javango.forms.widgets.WidgetFactory;
import com.google.inject.Inject;
public class ModelChoiceField<T> extends AbstractChoiceField<T, String> {
protected Class<? extends T> model;
protected QuerySet<?> querySet;
protected HibernateUtil hibernateUtil;
protected Managers managers;
@Inject
public ModelChoiceField(WidgetFactory widgetFactory, HibernateUtil hibernateUtil, Managers managers) {
super(widgetFactory);
this.hibernateUtil = hibernateUtil;
this.managers = managers;
}
@Override
public T clean(String[] values, Map<String, String> errors) {
if (values == null || values.length == 0) {
return clean("", errors);
}
return clean(values[0], errors);
}
protected Object correctKeyType(String value) throws ManagerException {
return new HibernateQuerySetHelper(hibernateUtil, getModel(), null).convertToPk(value);
}
@Override
public T clean(String value, Map<String, String> errors) {
try {
if (StringUtils.isEmpty(value)) {
if (isRequired()) {
errors.put(getName(), "This field is required.");
return null;
}
if (isAllowNull()) {
return null;
}
return null; // yea allow null does not really mean much for model choice fields.
}
Object key = correctKeyType(value);
if (key != null && !errors.containsKey(this.getName())) {
managers.forClass(model);
T v1 = managers.forClass(model).get((Serializable)key);
if (v1 == null) {
errors.put(getName(), UNKNOWN_CHOICE_ERROR);
}
return v1;
}
} catch (ManagerException e) {
errors.put(getName(), "Unable to get data: " + e);
return null;
}
return null;
}
@Override
public Map<T, String> getChoices() {
if (super.getChoices() != null) {
return super.getChoices();
}
ModelChoiceMap map = new ModelChoiceMap(managers, model);
if (querySet != null) {
map.setQuerySet(querySet);
}
setChoices(map);
return map;
}
@Override
public void handleAnnotation(Annotation annotation) {
super.handleAnnotation(annotation);
if (annotation instanceof ModelChoiceFieldProperties) {
ModelChoiceFieldProperties mcfp = (ModelChoiceFieldProperties)annotation;
this.setModel(mcfp.modelClass());
try {
QuerySet<?> qs = null;
if (mcfp.filters().length > 0) {
qs = managers.forClass(getModel()).all();
for(Filter f : mcfp.filters()) {
String[] value = f.value();
if (value != null && value.length > 0) {
if (value != null && value.length == 1) {
qs = qs.filter(f.property(), value[0]);
} else {
qs = qs.filter(f.property(), value);
}
}
if (!"".equals(f.otherProperty())) {
qs = qs.filterByProperty(f.property(), f.otherProperty());
}
if (f.nullCheck()) {
qs = qs.filter(f.property(), null);
}
}
}
if (mcfp.orderby().length > 0) {
qs = qs != null ? qs : managers.forClass(getModel()).all();
qs = qs.orderBy(mcfp.orderby());
}
if (qs != null) setQuerySet(qs);
} catch (ManagerException e) {
// ARGG WHAT TO DO... think of the children
}
}
}
public ModelChoiceField<T> setChoices(Collection<T> collection) {
Map<T, String> choices = new LinkedHashMap<T,String>();
try {
// String keyField = managers.forClass(model).getPkProperty();
for (T choice : collection) {
choices.put(choice, choice.toString());
}
} catch (Exception e) {
// TODO
}
setChoices(choices);
return this;
}
public Class getModel() {
return model;
}
public ModelChoiceField setModel(Class model) {
this.model = model;
return this;
}
public QuerySet<?> getQuerySet() {
return querySet;
}
public ModelChoiceField setQuerySet(QuerySet<?> querySet) {
this.querySet = querySet;
return this;
}
@Override
public Object cleanInitialValue(Object value) {
value = super.cleanInitialValue(value);
try {
String keyField = managers.forClass(model).getPkProperty();
return BeanUtils.getProperty(value, keyField);
} catch (Exception e) {
// TODO
}
return null;
}
}