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

import java.util.LinkedHashMap;

import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.DragAppearance;
import com.smartgwt.client.types.HeaderControls;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.SelectionStyle;
import com.smartgwt.client.widgets.AnimationCallback;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.events.CloseClickEvent;
import com.smartgwt.client.widgets.events.CloseClickHandler;
import com.smartgwt.client.widgets.grid.CellFormatter;
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.RecordClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.PortalLayout;
import com.smartgwt.client.widgets.layout.Portlet;
import com.smartgwt.sample.showcase.client.PanelFactory;
import com.smartgwt.sample.showcase.client.ShowcasePanel;

public class PortletAnimationSample extends ShowcasePanel {
    private static final String DESCRIPTION = "Click on the portlet list to the left to create portlets and see them animate into place. Drag " +
        "portlets around to new locations and they animate into place.";

    private ListGrid listGrid;

    public static class Factory implements PanelFactory {
        private String id;

        public ShowcasePanel create() {
            PortletAnimationSample panel = new PortletAnimationSample();
            id = panel.getID();
            return panel;
        }

        public String getID() {
            return id;
        }

        public String getDescription() {
            return DESCRIPTION;
        }
    }

    @Override
    protected boolean isTopIntro() {
        return true;
    }

    public Canvas getViewPanel() {
        final PortalLayout portalLayout = new PortalLayout();
        portalLayout.setOverflow(Overflow.VISIBLE);
        portalLayout.setColumnOverflow(Overflow.VISIBLE);
        portalLayout.setPreventColumnUnderflow(false);
        portalLayout.setNumColumns(3);
        portalLayout.setShowColumnMenus(true);
        portalLayout.setColumnBorder("0");
        	
        listGrid = new ListGrid();
        listGrid.setWidth(120);
        listGrid.setHeight(20);
        // autosize to fit the list, instead of scrolling
        listGrid.setOverflow(Overflow.VISIBLE);
        listGrid.setBodyOverflow(Overflow.VISIBLE);
        listGrid.setLeaveScrollbarGap(false);
	    
        // hide the column headers
        listGrid.setShowHeader(false);
	    
        // disable normal row selection behaviors
        listGrid.setSelectionType(SelectionStyle.NONE);
		
        ListGridRecord records[] = new ListGridRecord[10];
        records[0] = new ListGridRecord();
        records[0].setAttribute("portletName", "Portlet 1");
        records[1] = new ListGridRecord();
        records[1].setAttribute("portletName", "Portlet 2");
        records[2] = new ListGridRecord();
        records[2].setAttribute("portletName", "Portlet 3");
        records[3] = new ListGridRecord();
        records[3].setAttribute("portletName", "Portlet 4");
        records[4] = new ListGridRecord();
        records[4].setAttribute("portletName", "Portlet 5");
        records[5] = new ListGridRecord();
        records[5].setAttribute("portletName", "Portlet 6");
        records[6] = new ListGridRecord();
        records[6].setAttribute("portletName", "Portlet 7");
        records[7] = new ListGridRecord();
        records[7].setAttribute("portletName", "Portlet 8");
        records[8] = new ListGridRecord();
        records[8].setAttribute("portletName", "Portlet 9");
        records[9] = new ListGridRecord();
        records[9].setAttribute("portletName", "Portlet 10");
        // fake portlet list for self-contained example
        // The real list could be included inline, or loaded on the fly from the server.
        // This data can include whatever attributes you want to use for these portlet,
        // e.g. feed URLs, icons, update frequency...
        listGrid.setData(records);
		
        ListGridField portletNameField = new ListGridField("portletName");
        portletNameField.setCellFormatter(new CellFormatter() {
            @Override
            public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
                return Canvas.imgHTML("[SKIN]actions/view.png") + " " + value;
            }
        });
        listGrid.setFields(portletNameField);
		
        // global for convenient single setting of multiple animation times in this example
        // default 750
        listGrid.setAnimateTime(750);
	    
        listGrid.addRecordClickHandler(new RecordClickHandler() {
            @Override
            public void onRecordClick(RecordClickEvent event) {
                final ListGridRecord record = (ListGridRecord)event.getRecord();
                record.setEnabled(false);
                listGrid.refreshRow(event.getRecordNum());
                final Portlet newPortlet = new Portlet();
                newPortlet.setTitle(record.getAttributeAsString("portletName"));
                newPortlet.setShowShadow(false);
                // enable predefined component animation
                newPortlet.setAnimateMinimize(true);
                // Window is draggable with "outline" appearance by default.
                // "target" is the solid appearance.
                newPortlet.setDragAppearance(DragAppearance.OUTLINE);
                // customize the appearance and order of the controls in the window header
                // (could do this in load_skin.js instead)
                newPortlet.setHeaderControls(HeaderControls.HEADER_ICON, HeaderControls.HEADER_LABEL,
                    HeaderControls.MINIMIZE_BUTTON,  HeaderControls.CLOSE_BUTTON);
                // show either a shadow, or translucency, when dragging a portlet
                // (could do both at the same time, but these are not visually compatible effects)
                newPortlet.setDragOpacity(30);
                // these settings enable the portlet to autosize its height only to fit its contents
                // (since width is determined from the containing layout, not the portlet contents)
                newPortlet.setHeight(145);
                newPortlet.setOverflow(Overflow.VISIBLE);
                LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
                map.put("overflow", "VISIBLE");
                newPortlet.setBodyDefaults(map);
                Label label = new Label();
                label.setAlign(Alignment.CENTER);
                label.setLayoutAlign(Alignment.CENTER);
                label.setContents(record.getAttributeAsString("portletName")+" contents");
                // simple fake portlet contents - could put anything here
                newPortlet.addItem(label);
                newPortlet.addCloseClickHandler(new CloseClickHandler() {
                    @Override
                    public void onCloseClick(CloseClickEvent event) {
                        closePortlet(newPortlet, record);
                    }
                });
                newPortlet.hide();
				
                int fewestPortlets = 999999;
                int fewestPortletsColumn = 0;
                // find the column with the fewest portlets
                Portlet portletArray[][][] = portalLayout.getPortletArray();
                for (int i=0; i < portletArray.length; i++) {
                    int numPortlets = portletArray[i].length;
                    if (numPortlets < fewestPortlets) {
                        fewestPortlets = numPortlets;
                        fewestPortletsColumn = i;
                    }
                }
                portalLayout.addPortlet(newPortlet, fewestPortletsColumn, 0);
			    
                // create an outline around the clicked row
                final Canvas outline = new Canvas();
                outline.setLeft(listGrid.getPageLeft());
                outline.setTop(listGrid.getRowPageTop(event.getRecordNum()));
                outline.setWidth(listGrid.getVisibleWidth());
                outline.setHeight(listGrid.getDrawnRowHeight(event.getRecordNum()));
                outline.setBorder("2px solid #8289A6");  
                outline.draw();  
                outline.bringToFront();  
                outline.animateRect(newPortlet.getPageLeft(), newPortlet.getPageTop(),
                        portalLayout.getColumnWidth(fewestPortletsColumn), newPortlet.getVisibleHeight(),
                        new AnimationCallback() {  
                            public void execute(boolean earlyFinish) {
                                // callback at end of animation - destroy placeholder and outline; show the new portlet 
                                outline.destroy();
                                newPortlet.show();
                            }
                        }, 750);
            }
        });
        HLayout hLayout = new HLayout();
        hLayout.setWidth("100%");
        hLayout.setHeight("100%");
        hLayout.setLayoutMargin(10);
        hLayout.setMembersMargin(10);
        hLayout.addMembers(listGrid, portalLayout);
		
        return hLayout;
    }

    private void closePortlet(final Portlet portlet, final ListGridRecord portletRecord) {
        final int rowNum = listGrid.getDataAsRecordList().indexOf(portletRecord);
		
        // create an outline around the portlet
        final Canvas outline = new Canvas();
        outline.setBorder("2px solid #8289A6");
        outline.setRect(portlet.getPageRect());
        outline.bringToFront();
        
        // swap the portlet with a blank spacer element
        // (disabling relayout temporarily to prevent animation during the swap)
        Canvas portalColumn = portlet.getParentElement();
        portlet.hide();
        final LayoutSpacer spacer = new LayoutSpacer();
        spacer.setRect(portlet.getRect());
        portalColumn.addChild(spacer);

        // animateHide (shrink) the spacer to collapse this space in the content area
        spacer.setAnimateHideTime(listGrid.getAnimateTime());
        spacer.setAnimateHideTime(10);

        // simultaneously animate the portlet outline down to the row in this portletList
        outline.draw();
        outline.animateRect(listGrid.getPageLeft(), listGrid.getRowPageTop(rowNum),
	       listGrid.getVisibleWidth(), listGrid.getDrawnRowHeight(rowNum),
               new AnimationCallback() {  
                   public void execute(boolean earlyFinish) {
                       // callback at end of animation - destroy outline, portlet, and spacer;
                       // also enable and refresh the row in the portletList so it does not show the special
                       // style (and so it can be clicked again)
                       outline.destroy();
                       spacer.destroy();
                       portlet.destroy();
                       portletRecord.setEnabled(true);
                       listGrid.refreshRow(rowNum);
                   }
               }, 750);
    }

    public String getIntro() {
        return DESCRIPTION;
    }
}