package javango.forms.fields;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;
import java.util.Map;
import javango.forms.ValidationException;
import javango.forms.fields.annotations.FieldProperties;
import javango.forms.widgets.TextInputWidget;
import javango.forms.widgets.Widget;
import javango.forms.widgets.WidgetFactory;
import org.apache.commons.lang.StringUtils;
import com.google.inject.Inject;
public abstract class AbstractField<T> implements Field<T> {
public final static String REQUIRED_ERROR = "This field is required.";
protected Object initial;
protected String name;
protected String label;
protected String helpText;
protected WidgetFactory widgetFactory;
protected Class<? extends Widget> widgetClass;
protected Widget widget;
protected Class<? extends Widget> hiddenWidgetClass;
protected Widget hiddenWidget;
Map<String, String> widgetAttrs;
private boolean required = true;
private boolean hidden = false;
private boolean editable = true;
private boolean allowNull = false; // TODO This is not incorporated in all fiel types
@Inject
public AbstractField(WidgetFactory widgetFactory) {
super();
this.widgetFactory = widgetFactory;
}
public abstract T clean(String value, Map<String, String> errors) throws ValidationException;
public T clean(String[] value, Map<String, String> errors) throws ValidationException {
// TODO Should value == null, value.length==0 be handled differently
if (value == null || value.length == 0) {
return clean("", errors);
}
return clean(value[0], errors);
}
public T[] cleanAll(String[] values, Map<String, String> errors) throws ValidationException {
T[] clean = (T[]) new Object[values.length]; // ugly but it works...
int i=0;
for(String val : values) {
clean[i++] = clean(val, errors);
}
return clean;
}
public Object cleanInitialValue(Object value) {
if (value == null) {
return getInitial();
}
return value;
}
public void handleAnnotation(Annotation annotation) {
if (!(annotation instanceof FieldProperties)) return;
FieldProperties props = (FieldProperties)annotation;
this.setRequired(props.required());
this.setEditable(props.editable());
this.setAllowNull(props.allowNull());
this.label = "".equals(props.label()) ? props.verboseName() : props.label();
this.helpText = props.helpText();
this.hidden = props.hidden();
this.setWidgetAttrs(props.widgetAttrs());
if (props.widgetClass() != FieldProperties.NoWidget.class) this.widgetClass = props.widgetClass();
}
public AbstractField<T> setName(String name) {
this.name = name;
return this;
}
public String getName() {
return this.name;
}
public Widget getWidget() {
if (this.widget == null) {
if (this.widgetClass == null) {
setWidget(widgetFactory.newWidget(TextInputWidget.class));
} else {
setWidget(widgetFactory.newWidget(widgetClass));
}
}
Map<String, String> widgetAttrs = getWidgetAttrs();
if (widgetAttrs != null) this.widget.getAttrs().putAll(getWidgetAttrs());
return this.widget;
}
public Field<T> setWidget(Widget widget) {
this.widget = widget;
return this;
}
public boolean isRequired() {
return required;
}
public AbstractField<T> setRequired(boolean required) {
this.required = required;
return this;
}
public Object getInitial() {
return initial;
}
public AbstractField<T> setInitial(Object initial) {
this.initial = initial;
return this;
}
/**
* @deprecated Use getLabel instead
*/
public String getVerboseName() {
return this.getLabel();
}
/**
* @deprecated Use setLabel instead
*/
public AbstractField<T> setVerboseName(String verboseName) {
return this.setLabel(verboseName);
}
public String getLabel() {
return label;
}
public AbstractField<T> setLabel(String label) {
this.label = label;
return this;
}
public Widget getHiddenWidget() {
if (this.hiddenWidget == null) {
this.hiddenWidget = new TextInputWidget().setHidden(true);
}
return this.hiddenWidget;
}
public AbstractField<T> setHiddenWidget(Widget hiddenWidget) {
this.hiddenWidget = hiddenWidget;
return this;
}
public boolean isHidden() {
return hidden;
}
public AbstractField<T> setHidden(boolean hidden) {
this.hidden = hidden;
return this;
}
public boolean isEditable() {
return editable;
}
public Field<T> setEditable(boolean editable) {
this.editable = editable;
return this;
}
public boolean isAllowNull() {
return allowNull;
}
public Field<T> setAllowNull(boolean allowNull) {
this.allowNull = allowNull;
return this;
}
public String getHelpText() {
return helpText;
}
public Field<T> setHelpText(String helpText) {
this.helpText = helpText;
return this;
}
public Class<? extends Widget> getHiddenWidgetClass() {
return hiddenWidgetClass;
}
public Class<? extends Widget> getWidgetClass() {
return widgetClass;
}
public Field<T> setHiddenWidget(Class<? extends Widget> widgetClass) {
this.hiddenWidgetClass = widgetClass;
return this;
}
public Field<T> setWidget(Class<? extends Widget> widgetClass) {
this.widgetClass = widgetClass;
return this;
}
public Map<String, String> getWidgetAttrs() {
return widgetAttrs;
}
public Field<T> setWidgetAttrs(String[] widgetAttrsStrings) {
Map<String, String> widgetAttrs = getWidgetAttrs();
if (widgetAttrs == null && widgetAttrsStrings.length > 0) {
widgetAttrs = new LinkedHashMap<String, String>();
}
for(String s : widgetAttrsStrings) {
String[] v = s.split(":");
if (v != null && v.length == 2) {
widgetAttrs.put(v[0], v[1]);
} else if (v != null && v.length == 1) {
widgetAttrs.put(v[0], null);
}
}
setWidgetAttrs(widgetAttrs);
return this;
}
public Field<T> setWidgetAttrs(Map<String, String> attrs) {
this.widgetAttrs = attrs;
return this;
}
public Field<T> setWidget(Class<? extends Widget> widgetClass, String... widgetAttrsStrings) {
setWidget(widgetClass);
if (widgetAttrs == null && widgetAttrsStrings.length > 0) {
setWidgetAttrs(widgetAttrsStrings);
}
return this;
}
}