package ch.asynk.helloworld;

import com.vaadin.terminal.UserError;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.Validator;
import com.vaadin.data.validator.DoubleValidator;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Label;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.TextField;

public class DataMappingLayout extends VerticalLayout {
    //
    private static final long serialVersionUID = 1L;
    //
    private Context ctx = null;

    public DataMappingLayout(Context context) {
        ctx = context;
        //
        final AbstractComponent pa = buildPanel();
        pa.setWidth(600,UNITS_PIXELS);
        pa.setHeight(400,UNITS_PIXELS);
        addComponent(pa);
        setComponentAlignment(pa, Alignment.MIDDLE_CENTER);
        //
    }
    //
    private AbstractComponent buildPanel() {
        Panel panel = new Panel("Data Mapping Layout");
        FormLayout layout = new FormLayout();
        panel.setContent(layout);
        //
        final TextField tf1 = new TextField("Property.ValueChangeListener");
        tf1.setImmediate(true);
        layout.addComponent(tf1);
        final Label lb1 = new Label();
        lb1.setCaption("The Value");
        layout.addComponent(lb1);
        tf1.addListener( new Property.ValueChangeListener() {
            private static final long serialVersionUID = 1L;
            @Override
            public void valueChange(ValueChangeEvent event) {
                String value = (String) tf1.getValue();
                lb1.setValue(value);
            }
        });
        //
        Double trouble = 66.6;
        final ObjectProperty<Double> property = new ObjectProperty<Double>(trouble);
        final TextField tf2 = new TextField("ObjectProperty + Validator", property);
        tf2.setImmediate(true);
        tf2.addValidator( new DoubleValidator("It should be a double") );
        //tf2.setValidationVisible(false);    // nothing will happen
        layout.addComponent(tf2);
        final Label lb2 = new Label(property);
        lb2.setCaption("The Value");
        layout.addComponent(lb2);
        //
        final TextField tf3 = new TextField("No spaces");
        layout.addComponent(tf3);
        tf3.setComponentError(null); // (actually the default)
        final Button b1 = new Button("Ok!");
        layout.addComponent(b1);
        b1.addListener(new Button.ClickListener() {
            private static final long serialVersionUID = 1L;
            @Override
            public void buttonClick(ClickEvent event) {
                if (! ((String) tf3.getValue()).matches("^\\w*$")) {
                    tf3.setComponentError(new UserError("Must be letters and numbers"));
                } else {
                    tf3.setComponentError(null);
                }
            }
        });
        //
        // final Validator intValidator = new Validator() { ... }
        class MyIntValidator implements Validator {
            private static final long serialVersionUID = 1L;
            public boolean isValid(Object value) {
                if (value == null || !(value instanceof String)) {
                    return false;
                }
                return ((String) value).matches("[1-9][0-9]{4}");
            }
            public void validate(Object value) throws InvalidValueException {
                if (!isValid(value)) {
                    if (value != null && value.toString().startsWith("0")) {
                        throw new InvalidValueException("Must not start with a zero.");
                    } else {
                        throw new InvalidValueException("Must be a number 10000-99999.");
                    }
                }
            }
        };
        final TextField tf5 = new TextField("MyIntValidator");
        tf5.addValidator(new MyIntValidator());
        tf5.setImmediate(true);
        layout.addComponent(tf5);
        //
        class IntegerObjectProperty implements Property {
            private static final long serialVersionUID = 1L;
            Integer data = 0;
            boolean readOnly = false;
            public Class<?> getType() {
                return Integer.class;
            }
            public Object getValue() {
                return data;
            }
            public boolean isReadOnly() {
                return readOnly;
            }
            public void setReadOnly(boolean newStatus) {
                readOnly = newStatus;
            }
            public void setValue(Object newValue) throws ReadOnlyException, ConversionException {
                if (readOnly)
                    throw new ReadOnlyException();
                if (newValue instanceof Integer)
                    data = (Integer) newValue;
                else if (newValue instanceof String)
                    try {
                        data = Integer.parseInt((String) newValue, 16);
                    } catch (NumberFormatException e) {
                        throw new ConversionException("Must be an integer (from property)");
                    }
                else
                    throw new ConversionException("Unknown entry type (from property)");
            }
            @Override
            public String toString() {
                return Integer.toHexString(data)+" (hex)";
            }
        };
        final IntegerObjectProperty intProperty = new IntegerObjectProperty();
        intProperty.setValue(666);
        final TextField tf4 = new TextField("MyObjectProperty",intProperty);
        tf4.setImmediate(true);
        tf4.setErrorHandler(new ComponentErrorHandler() {
            private static final long serialVersionUID = 1L;
            @Override
            public boolean handleComponentError(ComponentErrorEvent event) {
                tf4.setComponentError(new UserError("Must be an integer (from handler)"));
                return true;
            }
        });
        layout.addComponent(tf4);
        //
        Button nextButton = new Button("next layout");
        nextButton.setDescription("Go to next layout");
        layout.addComponent(nextButton );
        nextButton.addListener( new Button.ClickListener() {
            private static final long serialVersionUID = 1L;
            @Override
            public void buttonClick(ClickEvent event) {
                getApplication().getMainWindow().setContent( new LayoutLayout(ctx) );
            }
        });
        //
        return panel;
    }
}