package com.mySampleApplication.client;

import com.smartgwt.client.types.ListGridEditEvent;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.fields.*;
import com.smartgwt.client.widgets.form.fields.events.EditorEnterEvent;
import com.smartgwt.client.widgets.form.fields.events.EditorEnterHandler;
import com.smartgwt.client.widgets.form.fields.events.EditorExitEvent;
import com.smartgwt.client.widgets.form.fields.events.EditorExitHandler;
import com.smartgwt.client.widgets.form.validator.CustomValidator;
import com.smartgwt.client.widgets.grid.*;
import com.smartgwt.client.widgets.grid.events.RowEditorExitEvent;
import com.smartgwt.client.widgets.grid.events.RowEditorExitHandler;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;

import java.util.LinkedHashMap;


/**
 * Created with IntelliJ IDEA.
 * User: tellington
 * Date: 4/26/13
 * Time: 4:51 PM
 * To change this template use File | Settings | File Templates.
 */
public class EditorCustomizer extends Window {

    private enum TypeOption {

        STRING,
        BOOL,
        NUMBER,
        SET
    }

    private int rowIdx = 0;

    private final int valueCol = 1;

    private ListGrid grid = new ListGrid();

    private final String INDEX = "INDEX";
    private final String TYPE  = "TYPE";

    private final String VALUE = "VALUE";

    private final String TRUE  = "true";
    private final String FALSE = "false";


    public EditorCustomizer() {

        setTitle("Editor Customizer");
        setWidth(325);
        setHeight(175);

        grid.setEditEvent(ListGridEditEvent.CLICK);
        grid.setCanRemoveRecords(true);
        grid.setValidateByCell(true);
        grid.setShowRecordComponentsByCell(true);

        final ListGridField indexField = new ListGridField(INDEX);
        final ListGridField typeField  = new ListGridField(TYPE);
        final ListGridField valueField = new ListGridField(VALUE);

        indexField.setRequired(true);
        indexField.setCanEdit(false);

        typeField.setRequired(true);
        typeField.setCanEdit(true);
        typeField.setValidateOnChange(true);
        typeField.setValidators(new TypeValidator());

        final SelectItem valueTypes = new SelectItem();

        LinkedHashMap<String, String> types = new LinkedHashMap<String, String>();

        types.put(TypeOption.STRING.name(), TypeOption.STRING.name());
        types.put(TypeOption.BOOL.name(),   TypeOption.BOOL.name());
        types.put(TypeOption.NUMBER.name(), TypeOption.NUMBER.name());
        types.put(TypeOption.SET.name(),    TypeOption.SET.name());

        valueTypes.setValueMap(types);
        valueTypes.setDefaultToFirstOption(true);
        valueTypes.addEditorExitHandler(new EditorExitHandler() {
            @Override
            public void onEditorExit(EditorExitEvent editorExitEvent) {

                Object obj = editorExitEvent.getValue();

                if (obj == null)
                    return;

                grid.setEditValue(grid.getEditRow(), TYPE, obj.toString());
            }
        });

        typeField.setEditorType(valueTypes);

        valueField.setRequired(true);
        valueField.setCanEdit(true);
        valueField.setValidateOnChange(true);
        valueField.setValidators(new ValueValidator());

        grid.setFields(indexField, typeField, valueField);

        grid.hideField(INDEX);
        grid.showField(TYPE);
        grid.showField(VALUE);

        grid.addRowEditorExitHandler(new RowEditorExitHandler() {
            @Override
            public void onRowEditorExit(RowEditorExitEvent event) {

                if (grid.validateRow(grid.getEditRow())) {
                    grid.saveAllEdits();
                }
                else {
                    grid.startEditing(grid.getEditRow(), valueCol, false);
                }
            }
        });

        grid.setEditorCustomizer(new ListGridEditorCustomizer() {
            @Override
            public FormItem getEditor(final ListGridEditorContext context) {

                String field = context.getEditField().getName();

                if (!field.toLowerCase().equals(VALUE.toLowerCase()))
                    return context.getDefaultProperties();

                ListGridRecord row = context.getEditedRecord();

                if (row == null)
                    return context.getDefaultProperties();

                String typeValue = row.getAttributeAsString(TYPE);

                if (typeValue == null)
                    return context.getDefaultProperties();

                String content = row.getAttributeAsString(VALUE);

                if (content == null)
                    return context.getDefaultProperties();

                TypeOption type = TypeOption.valueOf(typeValue);

                switch (type) {

                    case STRING:
                        TextItem textEditor = new TextItem();

                        textEditor.setRequired(true);
                        textEditor.setValue(content);

                        textEditor.addEditorEnterHandler(new EditorEnterHandler() {
                            @Override
                            public void onEditorEnter(EditorEnterEvent editorEnterEvent) {

                                String value = editorEnterEvent.getValue().toString();

                                grid.setEditValue(grid.getEditRow(), VALUE, value);
                            }
                        });

                        return textEditor;
                    case BOOL:
                        SelectItem booleanEditor = new SelectItem();

                        booleanEditor.setRequired(true);

                        LinkedHashMap<String, String> values = new LinkedHashMap<String, String>();
                        values.put(TRUE, TRUE);
                        values.put(FALSE, FALSE);
                        booleanEditor.setValueMap(values);

                        if (content.toLowerCase().equals(TRUE) || content.toLowerCase().equals(FALSE)) {
                            booleanEditor.setValue(content);
                        }
                        else {
                            booleanEditor.setValue(TRUE);
                        }

                        booleanEditor.addEditorEnterHandler(new EditorEnterHandler() {
                            @Override
                            public void onEditorEnter(EditorEnterEvent editorEnterEvent) {

                                String value = editorEnterEvent.getValue().toString();

                                grid.setEditValue(grid.getEditRow(), VALUE, value);
                            }
                        });

                        return booleanEditor;
                    case NUMBER:
                        IntegerItem numberEditor = new IntegerItem();

                        numberEditor.setRequired(true);
                        numberEditor.setValue(content);
                        numberEditor.addEditorEnterHandler(new EditorEnterHandler() {
                            @Override
                            public void onEditorEnter(EditorEnterEvent editorEnterEvent) {

                                String value = editorEnterEvent.getValue().toString();

                                grid.setEditValue(grid.getEditRow(), VALUE, value);
                            }
                        });

                        return numberEditor;
                    case SET:
                        return new ValueSetItem(content);
                }

                return context.getDefaultProperties();
            }
        });

        ToolStrip strip = new ToolStrip();
        strip.setWidth100();

        ToolStripButton addValue = new ToolStripButton();
        addValue.setIcon("[SKIN]/actions/add.png");
        addValue.setTitle("New Row");
        addValue.addClickHandler(new ClickHandler() {
            @SuppressWarnings("rawtypes")
            public void onClick(ClickEvent clickEvent) {

                try {

                    ListGridRecord newValue = new ListGridRecord();

                    newValue.setAttribute(INDEX, rowIdx++);
                    newValue.setAttribute(TYPE,  TypeOption.STRING.name());
                    newValue.setAttribute(VALUE, "");

                    grid.startEditingNew(newValue);
                } catch (Exception e) {

                    SC.warn("Exception..." + e.getMessage());
                }
            }
        });

        strip.addButton(addValue);

        addItem(strip);
        addItem(grid);
    }

    public class ValueSetItem extends CanvasItem {

        private int rowIdx = 0;


        public ValueSetItem(String valueSet) {

            setHeight(50);
            setWidth(150);

            final ListGrid grid = new ListGrid();

            ListGridField index = new ListGridField(INDEX);
            ListGridField value = new ListGridField(VALUE);

            grid.setFields(index, value);

            grid.setEditEvent(ListGridEditEvent.CLICK);
            grid.setCanRemoveRecords(true);

            grid.hideField(INDEX);
            grid.showField(VALUE);

            ToolStrip strip = new ToolStrip();
            strip.setWidth100();

            ToolStripButton addValue = new ToolStripButton();
            addValue.setIcon("[SKIN]/actions/add.png");
            addValue.setTitle("New Row");
            addValue.addClickHandler(new ClickHandler() {
                @SuppressWarnings("rawtypes")
                public void onClick(ClickEvent clickEvent) {

                    try {

                        ListGridRecord newValue = new ListGridRecord();

                        newValue.setAttribute(INDEX, rowIdx++);
                        newValue.setAttribute(VALUE, "");

                        grid.startEditingNew(newValue);
                    } catch (Exception e) {

                        SC.warn("Exception..." + e.getMessage());
                    }
                }
            });

            VLayout layout = new VLayout();

            layout.addMember(strip);
            layout.addMember(grid);

            setCanvasItem(layout.getCanvasItem());
        }
    }

    public class TypeValidator extends CustomValidator {

        @Override
        protected boolean condition(Object value) {

            if (value == null)
                return false;

            try {

                switch (TypeOption.valueOf(value.toString())) {

                    case STRING:    // fall thru
                    case BOOL:      // fall thru
                    case NUMBER:    // fall thru
                    case SET:
                        return true;
                }
            }
            catch (IllegalArgumentException e) {
                SC.logDebug("EXCEPTION: " + e.getMessage());
            }
            catch (NullPointerException e) {
                SC.logDebug("EXCEPTION: " + e.getMessage());
            }

            return false;
        }
    }

    public class ValueValidator extends CustomValidator {

        @Override
        protected boolean condition(Object obj) {

            if (obj == null)
                return false;

            try {

                String value = obj.toString();

                String typeValue = grid.getEditValueAsString(grid.getEditRow(), TYPE);

                if (typeValue == null)
                    typeValue = grid.getSelectedRecord().getAttributeAsString(TYPE);

                switch (TypeOption.valueOf(typeValue)) {

                    case STRING:    // fall thru
                    case SET:
                        return true; // todo check for min length?
                    case BOOL:
                        if (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE)) {
                            return true;
                        }
                        break;
                    case NUMBER:
                        if (Integer.parseInt(value) > -1) {
                            return true;
                        }
                        break;
                }
            }
            catch (IllegalArgumentException e) {
                SC.logDebug("EXCEPTION: " + e.getMessage());
            }
            catch (NullPointerException e) {
                SC.logDebug("EXCEPTION: " + e.getMessage());
            }
            catch (Exception e) {
                SC.logDebug("EXCEPTION: " + e.getMessage());
            }

            return false;
        }
    }
}
