/* 
@VaadinApache2LicenseForJavaFiles@
 */
package com.vaadin.data.fieldbinder;

import java.util.EnumSet;

import com.vaadin.data.Item;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.AbstractTextField;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Field;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.PasswordField;
import com.vaadin.ui.Table;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;

public class DefaultFieldBinderFieldFactory implements FieldBinderFieldFactory {

    public static final Object CAPTION_PROPERTY_ID = "Caption";

    public <T extends Field> T createField(Class<?> type, Class<T> fieldType) {
        if (Enum.class.isAssignableFrom(type)) {
            return createEnumField(type, fieldType);
        } else if (Boolean.class.isAssignableFrom(type)
                || boolean.class.isAssignableFrom(type)) {
            return createBooleanField(fieldType);
        }
        return createDefaultField(type, fieldType);
    }

    private <T extends Field> T createEnumField(Class<?> type,
            Class<T> fieldType) {
        if (AbstractSelect.class.isAssignableFrom(fieldType)) {
            AbstractSelect s = createCompatibleSelect((Class<? extends AbstractSelect>) fieldType);
            populateWithEnumData(s, (Class<? extends Enum>) type);
            return (T) s;
        }

        return null;
    }

    protected AbstractSelect createCompatibleSelect(
            Class<? extends AbstractSelect> fieldType) {
        AbstractSelect select;
        if (fieldType.isAssignableFrom(ListSelect.class)) {
            select = new ListSelect();
            select.setMultiSelect(false);
        } else if (fieldType.isAssignableFrom(NativeSelect.class)) {
            select = new NativeSelect();
        } else if (fieldType.isAssignableFrom(OptionGroup.class)) {
            select = new OptionGroup();
            select.setMultiSelect(false);
        } else if (fieldType.isAssignableFrom(Table.class)) {
            Table t = new Table();
            t.setSelectable(true);
            select = t;
        } else {
            select = new ComboBox(null);
        }
        select.setImmediate(true);
        select.setNullSelectionAllowed(false);

        return select;
    }

    protected <T extends Field> T createBooleanField(Class<T> fieldType) {
        if (fieldType.isAssignableFrom(CheckBox.class)) {
            CheckBox cb = new CheckBox(null);
            cb.setImmediate(true);
            return (T) cb;
        } else if (AbstractTextField.class.isAssignableFrom(fieldType)) {
            return (T) createAbstractTextField((Class<? extends AbstractTextField>) fieldType);
        }

        return null;
    }

    protected <T extends AbstractTextField> T createAbstractTextField(
            Class<T> fieldType) {
        if (fieldType.isAssignableFrom(PasswordField.class)) {
            PasswordField pf = new PasswordField();
            pf.setImmediate(true);
            return (T) pf;
        } else if (fieldType.isAssignableFrom(TextField.class)) {
            TextField tf = new TextField();
            tf.setImmediate(true);
            return (T) tf;
        } else if (fieldType.isAssignableFrom(TextArea.class)) {
            TextArea ta = new TextArea();
            ta.setImmediate(true);
            return (T) ta;
        }

        return null;
    }

    protected <T extends Field> T createDefaultField(Class<?> type,
            Class<T> fieldType) {
        if (AbstractTextField.class.isAssignableFrom(fieldType)) {
            return (T) createAbstractTextField((Class<? extends AbstractTextField>) fieldType);
        }
        return null;
    }

    /**
     * Populates the given select with all the enums in the given {@link Enum}
     * class. Uses {@link Enum}.toString() for caption.
     * 
     * @param select
     *            The select to populate
     * @param enumClass
     *            The Enum class to use
     */
    protected void populateWithEnumData(AbstractSelect select,
            Class<? extends Enum> enumClass) {
        select.removeAllItems();
        for (Object p : select.getContainerPropertyIds()) {
            select.removeContainerProperty(p);
        }
        select.addContainerProperty(CAPTION_PROPERTY_ID, String.class, "");
        select.setItemCaptionPropertyId(CAPTION_PROPERTY_ID);
        @SuppressWarnings("unchecked")
        EnumSet<?> enumSet = EnumSet.allOf(enumClass);
        for (Object r : enumSet) {
            Item newItem = select.addItem(r);
            newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(r.toString());
        }
    }
}

@@ -440,82 +440,13 @@
 .ui.
-PasswordField;%0D%0Aimport com.vaadin.ui.Table;%0D%0Aimport com.vaadin.ui.TextArea
+Table
 ;%0D%0Ai
@@ -986,32 +986,241 @@
 e);%0D%0A        %7D%0D%0A
+        if (AbstractTextField.class.isAssignableFrom(fieldType)) %7B%0D%0A            return fieldType.cast(createAbstractTextField(fieldType%0D%0A                    .asSubclass(AbstractTextField.class)));%0D%0A        %7D%0D%0A
         return c
@@ -3166,34 +3166,24 @@
 Type
-.isAssignableFrom(Password
+ == AbstractText
 Fiel
@@ -3182,33 +3182,32 @@
 TextField.class)
-)
  %7B%0D%0A            
@@ -3210,220 +3210,118 @@
     
-PasswordField pf = new PasswordField();%0D%0A            pf.setImmediate(true);%0D%0A            return (T) pf;%0D%0A        %7D else if (fieldType.isAssignableFrom(TextField.class)) %7B%0D%0A            TextField tf = new TextField
+fieldType = (Class%3CT%3E) TextField.class;%0D%0A        %7D%0D%0A        try %7B%0D%0A            T field = fieldType.newInstance
 ();%0D
@@ -3333,18 +3333,21 @@
         
-t
 f
+ield
 .setImme
@@ -3383,14 +3383,13 @@
 urn 
-(T) tf
+field
 ;%0D%0A 
@@ -3401,204 +3401,165 @@
   %7D 
-else if (fieldType.isAssignableFrom(TextArea.class)) %7B%0D%0A            TextArea ta = new TextArea();%0D%0A            ta.setImmediate(true);%0D%0A            return (T) ta;%0D%0A        %7D%0D%0A%0D%0A        return null;
+catch (Exception e) %7B%0D%0A            throw new FormBuilder.BuildException(%0D%0A                    %22Could not create a field of type %22 + fieldType, e);%0D%0A        %7D
 %0D%0A  
@@ -3681,39 +3681,25 @@
     if (
-AbstractTextField.class
+fieldType
 .isAssig
@@ -3704,33 +3704,39 @@
 ignableFrom(
-fieldType
+TextField.class
 )) %7B%0D%0A      
@@ -3740,36 +3740,47 @@
          return 
-(T) 
+fieldType.cast(
 createAbstractTe
@@ -3791,54 +3791,24 @@
 eld(
-(Class%3C? extends AbstractTextField%3E) fieldType
+TextField.class)
 );%0D%0A

Create the right type of AbstractTextField and use TextField as default