package com.vaadin.tests.components.customfield;

import java.util.HashMap;
import java.util.Map;

import com.vaadin.ui.CustomLayout;
import com.vaadin.ui.Field;
import com.vaadin.ui.Form;
import com.vaadin.ui.Layout;

/**
 * Form that displays its fields in the layout of another form.
 * 
 * The fields are still logically part of this form even though they are in the
 * layout of the parent form. The embedded form itself is automatically hidden.
 * 
 * TODO Known issue: any field factory creating an {@link EmbeddedForm}
 * (directly or indirectly) should re-use the field once it has been created to
 * avoid the creation of duplicate fields when e.g. setting the visible item
 * properties.
 */
public class EmbeddedForm extends Form {
    private Form parentForm;
    private Map<Object, Field> fields = new HashMap<Object, Field>();

    /**
     * Create a form that places its fields in another {@link Form}.
     * 
     * @param parentForm
     *            form to which to embed the fields, not null
     */
    public EmbeddedForm(Form parentForm) {
        this.parentForm = parentForm;
        setVisible(false);
    }

    @Override
    protected void attachField(Object propertyId, Field field) {
        if (propertyId == null || field == null) {
            return;
        }

        Layout layout = parentForm.getLayout();

        Field oldField = fields.get(propertyId);
        if (oldField != null) {
            layout.removeComponent(oldField);
        }

        fields.put(propertyId, field);

        if (layout instanceof CustomLayout) {
            ((CustomLayout) layout).addComponent(field, propertyId.toString());
        } else {
            layout.addComponent(field);
        }
    }

    @Override
    public boolean removeItemProperty(Object id) {
        // remove the field from the parent layout if already added there
        parentForm.getLayout().removeComponent(fields.get(id));
        fields.remove(id);

        return super.removeItemProperty(id);
    }
}