/* D-RexGxt - D-RexGxt - GUI Design Tool for GWT
 * Copyright (c) 2008,  KPS Corporation
 * All rights reserved.
 *
 * Open Source License
 * ------------------------------------------------------------------------------------------
 * D-RexGxt is licensed under the terms of the Open Source GPL 3.0 license.
 *
 * http://www.gnu.org/licenses/gpl.html
 *
 * --
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */
package jp.co.kpscorp.gwt.client.design.gxt.delegate.comp;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jp.co.kpscorp.gwt.client.design.DesignPanel;
import jp.co.kpscorp.gwt.client.design.PropDialog;

import jp.co.kpscorp.gwt.client.design.WidgetService;
import jp.co.kpscorp.gwt.client.design.WidgetServiceFactory;
import jp.co.kpscorp.gwt.client.design.gxt.DesignStore;
import jp.co.kpscorp.gwt.client.design.gxt.GxtUtil;
import jp.co.kpscorp.gwt.client.design.gxt.common.LabelModel;
import jp.co.kpscorp.gwt.client.design.gxt.delegate.layout.TableDataDelegate;
import jp.co.kpscorp.gwt.client.design.gxt.widget.ColumnConfigWidget;
import jp.co.kpscorp.gwt.client.design.gxt.widget.ColumnModelWidget;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelStringProvider;
import com.extjs.gxt.ui.client.data.NestedModelUtil;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.WidgetHelper;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridHelper;
import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel;
import com.extjs.gxt.ui.client.widget.grid.GridView;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;

public class GridDelegate extends BoxComponentDelegate {

	private Grid<ModelData> comp;

	// selectionModel view 不要
	protected String[] props = { "minColumnWidth", "hideHeaders",
			"trackMouseOver", "autoExpandColumn", "autoExpandMin",
			"enableColumnResize", "stripeRows", "loadMask", "autoExpandMax" };

	protected String[] innerProps = { "view", "minColumnWidth", "hideHeaders",
			"trackMouseOver", "autoExpandColumn", "selectionModel",
			"autoExpandMin", "enableColumnResize", "stripeRows", "loadMask",
			"autoExpandMax" };

	public GridDelegate(WidgetService service, Component widget) {
		super(service, widget);
		this.comp = (Grid<ModelData>) widget;
	}

	@Override
	public String[] getProps() {
		return GxtUtil.add(super.getProps(), props);
	}

	@Override
	public String[] getInnerProps() {
		return GxtUtil.add(super.getInnerProps(), innerProps);
	}

	@Override
	public Object exec(String mthodName, Object[] parms) {
		if ("getHeigt".equals(mthodName)) {
			// getHeight例外
			return WidgetHelper.getHeight(comp);
		} else if ("getAutoExpandColumn".equals(mthodName)) {
			return comp.getAutoExpandColumn();
		} else if ("getAutoExpandMax".equals(mthodName)) {
			return comp.getAutoExpandMax();
		} else if ("getAutoExpandMin".equals(mthodName)) {
			return comp.getAutoExpandMin();
		} else if ("getColumnModel".equals(mthodName)) {
			return comp.getColumnModel();
		} else if ("getMinColumnWidth".equals(mthodName)) {
			return comp.getMinColumnWidth();
		} else if ("getSelectionModel".equals(mthodName)) {
			return comp.getSelectionModel();
		} else if ("getStore".equals(mthodName)) {
			return comp.getStore();
		} else if ("getView".equals(mthodName)) {
			return comp.getView();
		} else if ("isEnableColumnResize".equals(mthodName)) {
			return comp.isEnableColumnResize();
		} else if ("isHideHeaders".equals(mthodName)) {
			return comp.isHideHeaders();
		} else if ("isLoadMask".equals(mthodName)) {
			return comp.isLoadMask();
		} else if ("isStripeRows".equals(mthodName)) {
			return comp.isStripeRows();
		} else if ("isTrackMouseOver".equals(mthodName)) {
			return comp.isTrackMouseOver();
		} else if ("setAutoExpandColumn".equals(mthodName)
				&& parms[0] instanceof String) {
			comp.setAutoExpandColumn((String) parms[0]);
			return comp;
		} else if ("setAutoExpandMax".equals(mthodName)
				&& GxtUtil.safeParseInteger(parms[0]) != null) {
			comp.setAutoExpandMax(GxtUtil.safeParseInteger(parms[0]));
			return comp;
		} else if ("setAutoExpandMin".equals(mthodName)
				&& GxtUtil.safeParseInteger(parms[0]) != null) {
			comp.setAutoExpandMin(GxtUtil.safeParseInteger(parms[0]));
			return comp;
		} else if ("setContextMenu".equals(mthodName)
				&& parms[0] instanceof Menu) {
			comp.setContextMenu((Menu) parms[0]);
			return comp;
		} else if ("setEnableColumnResize".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setEnableColumnResize((Boolean) parms[0]);
			return comp;
		} else if ("setHideHeaders".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setHideHeaders((Boolean) parms[0]);
			return comp;
		} else if ("setLoadMask".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setLoadMask((Boolean) parms[0]);
			return comp;
		} else if ("setMinColumnWidth".equals(mthodName)
				&& GxtUtil.safeParseInteger(parms[0]) != null) {
			comp.setMinColumnWidth(GxtUtil.safeParseInteger(parms[0]));
			return comp;
		} else if ("setSelectionModel".equals(mthodName)
				&& parms[0] instanceof GridSelectionModel) {
			comp.setSelectionModel((GridSelectionModel<ModelData>) parms[0]);
			return comp;
		} else if ("setStringProvider".equals(mthodName)
				&& parms[0] instanceof ModelStringProvider) {
			comp.setStringProvider((ModelStringProvider) parms[0]);
			return comp;
		} else if ("setStripeRows".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setStripeRows((Boolean) parms[0]);
			return comp;
		} else if ("setTrackMouseOver".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setTrackMouseOver((Boolean) parms[0]);
			return comp;
		} else if ("setView".equals(mthodName) && parms[0] instanceof GridView) {
			comp.setView((GridView) parms[0]);
			return comp;
		}
		return super.exec(mthodName, parms);
	}

	@Override
	public boolean isAddable() {
		return true;
	}

	@Override
	public List<Component> getChildren() {
		List<Component> l = super.getChildren();
		ColumnModelWidget cmw = comp.getData(ColumnModelWidget.class.getName());
		if (cmw == null) {
			cmw = new ColumnModelWidget(comp.getColumnModel(), comp);
			comp.setData(ColumnModelWidget.class.getName(), cmw);
		} else {
			cmw.setColumnModel(comp.getColumnModel());
		}
		l.add(cmw);
		return l;
	}

	@Override
	public Component getInstance() {
		Grid<ModelData> grid = new Grid<ModelData>(new ListStore<ModelData>(),
				new ColumnModel(new ArrayList<ColumnConfig>()));
		grid.setData(ColumnModelWidget.class.getName(), new ColumnModelWidget(
				grid.getColumnModel(), grid));
		return grid;
	}

	@Override
	public Component setInitStyle(Component widget) {

		List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
		ColumnConfig column = new ColumnConfig();
		column.setId("name");
		column.setHeader("Company");
		column.setWidth(200);
		configs.add(column);

		column = new ColumnConfig();
		column.setId("symbol");
		column.setHeader("Symbol");
		column.setWidth(100);
		configs.add(column);

		column = new ColumnConfig();
		column.setId("last");
		column.setHeader("Last");
		column.setAlignment(HorizontalAlignment.RIGHT);
		column.setWidth(75);
		column.setNumberFormat(NumberFormat.getFormat("#,##0"));
		configs.add(column);

		column = new ColumnConfig("change", "Change", 100);
		column.setAlignment(HorizontalAlignment.RIGHT);
		column.setNumberFormat(NumberFormat.getFormat("#,##0.0#;(#,##0.0#)"));
		configs.add(column);

		column = new ColumnConfig("date", "Last Updated", 100);
		column.setAlignment(HorizontalAlignment.RIGHT);
		column.setDateTimeFormat(DateTimeFormat.getShortDateFormat());
		configs.add(column);
		ColumnModel cm = new ColumnModel(configs);

		// return super.setInitStyle(cp);
		ListStore<ModelData> store = makeStore(cm, 300);
		Grid<ModelData> gd = new Grid<ModelData>(store, cm);
		gd.setHeight(300);
		gd.setWidth(600);
		gd.setData(ColumnModelWidget.class.getName(), new ColumnModelWidget(gd
				.getColumnModel(), gd));
		return gd;
	}

	// public void handleEvent(BaseEvent be) {
	// GridEvent ge = (GridEvent) be;
	// DOM.eventCancelBubble(ge.event, true);
	// DesignPanel dp = DesignPanel.getInstance();
	// dp.getPop().removeAll();
	// final Menu pop = dp.getPop();
	// ColumnConfig cfg = comp.getColumnModel().getColumn(ge.colIndex);
	// MenuItem bar1 = new MenuItem("columnConfig", new ColumnCfg(
	// new ColumnConfigWidget(cfg, new ColumnModelWidget(comp
	// .getColumnModel(), comp)), pop));
	// pop.add(bar1);
	// dp.setWidget(comp);
	// dp.addStandardBar(pop, comp);
	// pop
	// .showAt(DOM.eventGetClientX(ge.event), DOM
	// .eventGetClientY(ge.event));
	// }

	@Override
	public Menu makeBar() {
		Menu menu = super.makeBar();
		if (ce instanceof GridEvent) {
			GridEvent ge = (GridEvent) ce;
			if (ge.colIndex >= 0) {
				ColumnConfig cfg = comp.getColumnModel().getColumn(ge.colIndex);
				MenuItem[] mi = new MenuItem[4];
				mi[0] = new MenuItem("columnConfig", new ColumnCfg(
						new ColumnConfigWidget(cfg, new ColumnModelWidget(
								(ColumnModel) comp.getColumnModel(), comp)),
						menu));
				// mi[1] = new MenuItem("addColumn", new AddColumn(GridHelper
				// .getConfig(comp.getColumnModel()), ge.colIndex, menu));
				// mi[2] = new MenuItem("removeColumn", new RemoveColumn(
				// GridHelper.getConfig(comp.getColumnModel()),
				// ge.colIndex, menu));
				menu.insert(mi[0], 0);
				// menu.insert(mi[1], 1);
				// menu.insert(mi[2], 2);
			}
		}
		return menu;
	}

	public class ColumnCfg extends SelectionListener<ComponentEvent> {
		private Menu pop;

		private ColumnConfigWidget config;

		public ColumnCfg(ColumnConfigWidget config, Menu pop) {
			super();
			this.pop = pop;
			this.config = config;
		}

		@Override
		public void componentSelected(ComponentEvent ce) {
			PropDialog pdialog = new PropDialog(config);
			pdialog.show();
			pop.hide();
		}
	}

	// public class AddColumn extends SelectionListener<ComponentEvent> {
	// private Menu pop;
	//
	// private List<ColumnConfig> configs;
	//
	// private int colIndex;
	//
	// public AddColumn(List<ColumnConfig> configs, int colIndex, Menu pop) {
	// super();
	// this.pop = pop;
	// this.configs = configs;
	// this.colIndex = colIndex;
	// }
	//
	// @Override
	// public void componentSelected(ComponentEvent ce) {
	// ColumnConfig column = new ColumnConfig();
	// WidgetService ws = WidgetServiceFactory
	// .getService(new ColumnConfigWidget(column,
	// new ColumnModelWidget((ColumnModel) comp
	// .getColumnModel(), comp)));
	// String tag = GxtUtil.getNewTag(ws.getTag());
	// column.setId(tag);
	// column.setHeader(tag);
	// column.setWidth(100);
	// configs.add(colIndex, column);
	// remakeColumn(configs);
	// pop.hide();
	// }
	//
	// }
	//
	// public class RemoveColumn extends SelectionListener<ComponentEvent> {
	// private Menu pop;
	//
	// private List<ColumnConfig> configs;
	//
	// private int colIndex;
	//
	// public RemoveColumn(List<ColumnConfig> configs, int colIndex, Menu pop) {
	// super();
	// this.pop = pop;
	// this.configs = configs;
	// this.colIndex = colIndex;
	// }
	//
	// @Override
	// public void componentSelected(ComponentEvent ce) {
	// configs.remove(configs.get(colIndex));
	// remakeColumn(configs);
	// pop.hide();
	// }
	//
	// }

	public static DesignStore makeStore(ColumnModel cm, int height) {
		return new DesignStore(cm, height);
	}

	@Override
	public void addWidget(Component widget) {
		if (widget instanceof ColumnModelWidget) {
			ColumnModelWidget cmw = (ColumnModelWidget) widget;
			ColumnModel cm = cmw.getWrapModel();
			comp = resetColumnModel(comp, cm);
		} else if (widget instanceof ColumnConfigWidget) {
			ColumnModelWidget cmw = comp.getData(ColumnModelWidget.class
					.getName());
			WidgetServiceFactory.getService(cmw).addWidget(widget);
			comp = (Grid<ModelData>) cmw.getParent();
		} else {
			super.addWidget(widget);
		}
	}

	public static Grid<ModelData> resetColumnModel(Grid<ModelData> grid,
			ColumnModel cm) {
		if (grid == null) {
			return null;
		}
		if (grid.isRendered()) {
			Grid<ModelData> grid2 = remakeGrid(grid, cm);
			Component parent = (Component) grid2.getParent();
			if (parent instanceof LayoutContainer) {
				LayoutContainer lc = (LayoutContainer) parent;
				lc.layout();
			}
			return grid2;
		} else {
			GridHelper.setColumnModel(grid, cm);
			GridHelper.setStore(grid, makeStore(cm, WidgetHelper
					.getHeight(grid)));
		}
		return grid;
	}

	@Override
	public Component removeWidget(Component widget) {
		if (widget instanceof ColumnConfigWidget) {
			ColumnModelWidget cmw = comp.getData(ColumnModelWidget.class
					.getName());
			comp = (Grid<ModelData>) WidgetServiceFactory.getService(cmw)
					.removeWidget(widget);
			return comp;
		} else {
			return super.removeWidget(widget);
		}
	}

	@Override
	public String getAddCode(Component widget, List<String>[] lists,
			String parentFiledName, String fieldName, Map<Object, Object> map) {
		List<String> l = (List<String>) map.get(parentFiledName + "_Grid");
		if (widget instanceof ColumnModelWidget) {
			String s = l.remove(0);
			l.add(0, s.replaceAll("%1", fieldName));
			lists[1].addAll(l);
		} else {
			l.add(super.getAddCode(widget, lists, parentFiledName, fieldName,
					map));
		}
		return null;
	}

	private ComponentEvent ce;

	@Override
	public void setClickEvent(ComponentEvent clickEvent) {
		super.setClickEvent(clickEvent);
		this.ce = clickEvent;
	}

	public static Grid<ModelData> remakeGrid(Grid<ModelData> grid,
			ColumnModel cm) {
		Grid<ModelData> grid2 = GxtUtil.addRender(new Grid<ModelData>(
				GridDelegate.makeStore(cm, grid.getHeight()), cm));
		WidgetService gws = WidgetServiceFactory.getService(grid2);
		gws.shallowCopy(grid);
		GxtUtil.resetToParent2(grid, (Component) grid.getParent(), grid2);
		ColumnModelWidget cmw = grid.getData(ColumnModelWidget.class.getName());
		cmw.setColumnModel(grid2.getColumnModel());
		cmw.setGrid(grid2);
		grid2.setData(ColumnModelWidget.class.getName(), cmw);
		return grid2;
	}

	// private void remakeColumn(List<ColumnConfig> configs) {
	// ColumnModel cm = new ColumnModel(configs);
	// GridHelper.setColumnModel(comp, cm);
	// remakeGrid(comp, new ColumnModelWidget(cm, comp));
	// // DesignPanel.getInstance().importRec(
	// // remakeG);
	// }

	public static void addModelGrid(WidgetService gridWs, Object classIns,
			WidgetService service, Component comp) {
		DesignPanel.getInstance().checkPoint();
		Component grid = propGrid(classIns);
		grid = service.addWidget(grid);
		gridWs.onAdd(comp);
		DesignPanel.getInstance().getBasePanel().layout();
		// layout以降でないとTableDataがとれない
		// TableDataDelegate.setTableDataSize(grid);
		DesignPanel.getInstance().getPop().hide();
	}

	private static Component propGrid(Object classIns) {
		ModelData data = (ModelData) NestedModelUtil
				.convertIfNecessary(classIns);
		Iterator<String> it = data.getPropertyNames().iterator();
		List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
		while (it.hasNext()) {
			String prop = it.next();
			String head = null;
			if (classIns instanceof LabelModel) {
				LabelModel lm = (LabelModel) classIns;
				head = lm.label(prop);
			}
			if (head != null) {
				configs.add(new ColumnConfig(prop, head, 100));
			}
		}
		ColumnModel cm = new ColumnModel(configs);
		ListStore<ModelData> store = makeStore(cm, 300);
		Grid<ModelData> grid = new Grid<ModelData>(store, cm);
		grid.setSize(600, 300);
		return GxtUtil.addRender(grid);
	}

	// private int insertIdx;
	//
	// @Override
	// public void setTargetInfo(Component parent, Component child) {
	// insertIdx = 0;
	// if (parent instanceof Grid && child instanceof ColumnConfigWidget) {
	// Grid grid = (Grid) parent;
	// ColumnModel cm = grid.getColumnModel();
	// ColumnConfig cc = ((ColumnConfigWidget) child).getWrapConfig();
	// insertIdx = cm.getIndexById(cc.getId());
	// }
	// }

	@Override
	public String getCategory() {
		return "Panel/Sample";
	}

	@Override
	public String getIconStyle() {
		return "icon-menu-Gr";
	}

}
