package com.smartgwt.sample.showcase.client.forms;

import com.google.gwt.core.client.JavaScriptObject;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RecordList;
import com.smartgwt.client.types.FieldType;
import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.util.DateUtil;
import com.smartgwt.client.util.JSONEncoder;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.util.StringUtil;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.ButtonItem;
import com.smartgwt.client.widgets.form.fields.CanvasItem;
import com.smartgwt.client.widgets.form.fields.DateItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.form.fields.events.FormItemInitHandler;
import com.smartgwt.client.widgets.form.fields.events.ShowValueEvent;
import com.smartgwt.client.widgets.form.fields.events.ShowValueHandler;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.CellSavedEvent;
import com.smartgwt.client.widgets.grid.events.CellSavedHandler;
import com.smartgwt.sample.showcase.client.PanelFactory;
import com.smartgwt.sample.showcase.client.ShowcasePanel;

public class NestedEditorSample extends ShowcasePanel {
    private static final String DESCRIPTION =
        "<p>This example shows a reusable CanvasItem that edits nested data structures.</p>" +
        "<p>Here, a record representing an Order contains multiple OrderItem records &mdash; " +
        "in the Record for an Order the \"items\" field value is set to an Array of Records " +
        "representing OrderItems.</p>" +
        "<p>The CanvasItem embeds an editable ListGrid to provide an editing interaction " +
        "for the OrderItems right in the midst of the form. It can be used with any " +
        "DataSource that has nested records.</p>";
        
    public static class Factory implements PanelFactory {
        private String id;
        public ShowcasePanel create() {
            NestedEditorSample panel = new NestedEditorSample();
            id = panel.getID();
            return panel;
        }
        
        public String getID() {
            return id;
        }
        
        public String getDescription() {
            return DESCRIPTION;
        }
    }
    
    protected boolean isTopIntro() {
        return true;
    }
    
    public class GridEditorItem extends CanvasItem {
        GridEditorItem (String name) {
            super(name);
            
            setWidth("*");
            setHeight("*");
            setColSpan("*");
            setEndRow(true);
            setStartRow(true);
            
            // this is going to be an editable data item
            setShouldSaveValue(true);
            
            setInitHandler(new FormItemInitHandler() {
                @Override
                public void onInit(FormItem item) {
                    ListGrid grid = new ListGrid();

                    // dataSource and fields to use, provided to a listGridItem as
                    // listGridItem.gridDataSource and optional gridFields
                    grid.setDataSource(getGridDataSource());
                    if (gridFields != null) grid.setFields(getGridFields());
                    if (gridSortField != null) grid.setSortField(getGridSortField());
                    grid.setSortDirection(SortDirection.ASCENDING);
                    
                    // The form item's data is set to a list of records
                    RecordList value = item.getValueAsRecordList();
                    if (value != null) grid.setData(value);
                    
                    grid.setCanEdit(true);
                    grid.setSaveLocally(true);
                    
                    grid.addCellSavedHandler(new CellSavedHandler() {
                        @Override
                        public void onCellSaved(CellSavedEvent event) {
                            ListGrid grid = (ListGrid) event.getSource();
                            GridEditorItem item = (GridEditorItem) grid.getCanvasItem();
                            RecordList data = grid.getDataAsRecordList();
                            item.storeValue(data);
                            
                            if (item.getGridSortField() == null) return;
                            grid.sort(item.getGridSortField(), SortDirection.ASCENDING);
                        }
                    });
                    
                    setCanvas(grid);
                    
                    addShowValueHandler(new ShowValueHandler() {
                        @Override
                        public void onShowValue(ShowValueEvent event) {
                            ListGrid grid = (ListGrid)((CanvasItem)event.getSource()).getCanvas();
                            RecordList records = event.getDataValueAsRecordList();
                            if (records != null && grid != null) grid.setData(records);
                        }
                    });
                }
            });
        }
        
        private DataSource gridDataSource;
        public DataSource getGridDataSource() {
            return this.gridDataSource;
        }
        
        public void setGridDataSource(DataSource gridDataSource) {
            this.gridDataSource = gridDataSource;
        }
        
        private ListGridField[] gridFields;
        public ListGridField[] getGridFields() {
            return gridFields;
        }
        
        public void setGridFields(ListGridField... gridFields) {
            this.gridFields = gridFields;
        }
        
        private String gridSortField;
        public String getGridSortField() {
            return gridSortField;
        }
        
        public void setGridSortField(String gridSortField) {
            this.gridSortField = gridSortField;
        }
    };
    
    public Canvas getViewPanel() {
        // Define a couple of simple nested dataSources. Make these client-only for simplicity
        DataSource orderItemDS = getOrderItemDS();
        DataSource orderDS = getOrderDS();
        
        DynamicForm exampleForm = new DynamicForm();
        exampleForm.setID("exampleForm");
        exampleForm.setWidth(350);
        exampleForm.setHeight(350);
        exampleForm.setDataSource(orderDS);
        
        StaticTextItem orderID = new StaticTextItem("orderID");
        DateItem orderDate = new DateItem("orderDate");
        
        GridEditorItem items = new GridEditorItem("items");
        items.setShowTitle(false);
        items.setGridDataSource(orderItemDS);
        
        ListGridField itemDescription = new ListGridField("itemDescription");
        ListGridField unitPrice = new ListGridField("unitPrice");
        
        items.setGridFields(itemDescription, unitPrice);
        
        items.setGridSortField("itemDescription");
        
        ButtonItem saveBtn = new ButtonItem("Save");
        saveBtn.addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() {
            @Override
            public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent event) {
                event.getForm().saveData(new DSCallback() {
                    @Override
                    public void execute(DSResponse response, Object rawData, DSRequest request) {
                        Record rec = response.getData()[0];
                        JavaScriptObject rawItems = rec.getAttributeAsJavaScriptObject("items");
                        String html = StringUtil.asHTML(new JSONEncoder().encode(rawItems));
                        SC.say("Record saved with items:" + html);
                    }
                });
            }
        });
        
        exampleForm.setItems(orderID, orderDate, items, saveBtn);
        
        Criteria orderCriteria = new Criteria();
        orderCriteria.addCriteria("orderID", 1);
        orderDS.fetchData(orderCriteria, new DSCallback() {
            @Override
            public void execute(DSResponse response, Object rawData, DSRequest request) {
                DynamicForm exampleForm = (DynamicForm) Canvas.getById("exampleForm");
                exampleForm.editRecord(response.getData()[0]);
            }
        });
        
        return exampleForm;
    }
    
    private DataSource orderItemDS;
    private DataSource getOrderItemDS () {
        if (orderItemDS != null) return orderItemDS;
        orderItemDS = new DataSource();
        orderItemDS.setClientOnly(true);
        DataSourceField pkField = new DataSourceField("pk", FieldType.SEQUENCE);
        pkField.setPrimaryKey(true);
        
        DataSourceField orderID = new DataSourceField("orderID", FieldType.INTEGER);
        orderID.setCanEdit(false);
        
        DataSourceField itemDescription = new DataSourceField("itemDescription", FieldType.TEXT);
        DataSourceField unitPrice = new DataSourceField("unitPrice", FieldType.FLOAT);
        
        orderItemDS.setFields(pkField, orderID, itemDescription, unitPrice);
        
        // No need to populate with test data - this is a schema only - the data is 
        // nested directly in each order record.
        
        return orderItemDS;
    }
    
    private RecordList orderItemData;
    private RecordList getOrderItemData(int orderID) {
        if (orderItemData == null) {
            orderItemData  = new RecordList();
            
            orderItemData.addList(new ListGridRecord[] {
                new ListGridRecord () {{
                    setAttribute("pk", 0);
                    setAttribute("orderID", 0);
                    setAttribute("itemDescription", "Yellow Widget");
                    setAttribute("unitPrice", 23.01);
                }},
                new ListGridRecord () {{
                    setAttribute("pk", 1);
                    setAttribute("orderID", 0);
                    setAttribute("itemDescription", "Green Widget");
                    setAttribute("unitPrice", 28.99);
                }},
                new ListGridRecord () {{
                    setAttribute("pk", 2);
                    setAttribute("orderID", 1);
                    setAttribute("itemDescription", "Red Widget");
                    setAttribute("unitPrice", 100);
                }},
                new ListGridRecord () {{
                    setAttribute("pk", 3);
                    setAttribute("orderID", 1);
                    setAttribute("itemDescription", "Orange Widget");
                    setAttribute("unitPrice", 48.22);
                }},
                new ListGridRecord () {{
                    setAttribute("pk", 4);
                    setAttribute("orderID", 2);
                    setAttribute("itemDescription", "Yellow Widget");
                    setAttribute("unitPrice", 23.01);
                }}
            });
        }
        return new RecordList(orderItemData.findAll("orderID", orderID));
    }
    
    private DataSource orderDS;
    private DataSource getOrderDS () {
        if (orderDS != null) return orderDS;
        orderDS = new DataSource();
        orderDS.setClientOnly(true);
        
        DataSourceField orderID = new DataSourceField("orderID", FieldType.SEQUENCE);
        orderID.setPrimaryKey(true);
        
        DataSourceField customerName = new DataSourceField("customerName", FieldType.TEXT);
        
        DataSourceField orderDate = new DataSourceField("orderDate", FieldType.DATE);
        
        DataSourceField items = new DataSourceField();
        items.setName("items");
        items.setTypeAsDataSource(getOrderItemDS());
        items.setMultiple(true);
        
        orderDS.setFields(orderID, customerName, orderDate, items);
        
        orderDS.setTestData(getOrderData());
        
        return orderDS;
        
    }
    
    private ListGridRecord[] getOrderData () {
        ListGridRecord[] orderData = new ListGridRecord[] {
            new ListGridRecord() {{
                setAttribute("orderID", 0);
                setAttribute("customerName", "Richard Jones");
                setAttribute("orderDate", DateUtil.parseInput("11/01/2011"));
                setAttribute("items", getOrderItemData(0));
            }},
            new ListGridRecord() {{
                setAttribute("orderID", 1);
                setAttribute("customerName", "Sarah Holden");
                setAttribute("orderDate", DateUtil.parseInput("02/04/2011"));
                setAttribute("items", getOrderItemData(1));
            }},
            new ListGridRecord() {{
                setAttribute("orderID", 2);
                setAttribute("customerName", "James Edwards");
                setAttribute("orderDate", DateUtil.parseInput("04/29/2011"));
                setAttribute("items", getOrderItemData(2));
            }}
        };
        return orderData;
    }
    
    public String getIntro() {
        return DESCRIPTION;
    }
}