/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.zowyapp.store.ui;

import com.vaadin.data.Item;
import java.util.Arrays;

import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.MethodProperty;
import com.vaadin.ui.Button;
import com.vaadin.ui.Form;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.FormFieldFactory;
import com.vaadin.ui.ProgressIndicator;
import java.lang.reflect.Field;
import java.text.FieldPosition;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author dhaval
 */
public class GenericForm extends VerticalLayout {

    private Item genericItem;
    private GenericFormEventHandler eventHandler;
    List<String> fieldNameList = new ArrayList<String>();

    public GenericForm(Map<String, Object> beanMap, Item bean, String header, FormFieldFactory fieldFactory, final GenericFormEventHandler eventHandler){
        genericItem = bean;
        this.eventHandler = eventHandler;
        Collection ids = bean.getItemPropertyIds();
        fieldNameList.addAll(ids);

        setSpacing(true);
        setMargin(true);
        init(header, fieldFactory);
    }

    public GenericForm(Object bean, String header, FormFieldFactory fieldFactory, final GenericFormEventHandler eventHandler) {
        this.eventHandler = eventHandler;
        genericItem = new BeanItem(bean);

        // Determines which properties are shown, and in which order:
        Field[] fields = bean.getClass().getDeclaredFields();
        for(Field field: fields){
            fieldNameList.add(field.getName());
        }

        init(header, fieldFactory);
    }

    private void init(String header, FormFieldFactory fieldFactory){
        // Create the Form
        final Form genericForm = new Form();
//        genericForm.setCaption(header);
        genericForm.setWriteThrough(false); // we want explicit 'apply'
        genericForm.setInvalidCommitted(false); // no invalid values in datamodel

        // FieldFactory for customizing the fields and adding validators
        genericForm.setFormFieldFactory(fieldFactory);
        genericForm.setItemDataSource(genericItem); // bind to POJO via BeanItem

        genericForm.setVisibleItemProperties(fieldNameList.toArray());

        // Add form to layout
        addComponent(genericForm);

        // The cancel / apply buttons
        HorizontalLayout buttons = new HorizontalLayout();
        buttons.setSpacing(true);
        Button discardChanges = new Button("Reset",
                new Button.ClickListener() {

                    public void buttonClick(ClickEvent event) {
                        genericForm.discard();
                    }
                });
        buttons.addComponent(discardChanges);
        buttons.setComponentAlignment(discardChanges, "middle");

        Button apply = new Button("Submit", new Button.ClickListener() {

            public void buttonClick(ClickEvent event) {
                try {
                    genericForm.commit();
                    if(eventHandler != null){
                        eventHandler.formCommitted(getFormBean());
                    }else{
                        showPojoState();
                    }
                } catch (Exception e) {
                    // Ingnored, we'll let the Form handle the errors
                }
            }
        });
        buttons.addComponent(apply);
        genericForm.getLayout().addComponent(buttons);
    }

    private void showPojoState() {
        Window.Notification n = new Window.Notification("POJO state", Window.Notification.TYPE_TRAY_NOTIFICATION);
        n.setPosition(Window.Notification.POSITION_CENTERED);
        Collection<?> ids = genericItem.getItemPropertyIds();
        String description = "";
        for(Object id : ids){
            Object val = genericItem.getItemProperty(id).getValue();
            if (val != null) {
                description += "<br>" + id + " :: " + val;
            } else {
                description += "<br>" + id;
            }
        }
        n.setDescription(description);
        getWindow().showNotification(n);
    }

    private Object getFormBean(){
        if(genericItem instanceof BeanItem){
            return ((BeanItem)genericItem).getBean();
        }else{
            Map<String, Object> bean = new HashMap<String, Object>();
            Collection<?> ids = genericItem.getItemPropertyIds();
            for(Object id : ids){
                bean.put(id.toString(), genericItem.getItemProperty(id).getValue());
            }
            return bean;
        }
    }
}
