/* 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.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.delegate.BaseDelegate;
import jp.co.kpscorp.gwt.client.design.gxt.GxtUtil;
import jp.co.kpscorp.gwt.client.design.gxt.widget.LayoutDataWidget;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.Style.Orientation;
import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.Style.VerticalAlignment;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.util.Point;
import com.extjs.gxt.ui.client.util.Rectangle;
import com.extjs.gxt.ui.client.util.Size;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.Container;
import com.extjs.gxt.ui.client.widget.Header;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.form.AdapterField;
import com.extjs.gxt.ui.client.widget.form.Field;
import com.extjs.gxt.ui.client.widget.form.FormPanel.LabelAlign;
import com.extjs.gxt.ui.client.widget.layout.AccordionLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.layout.LayoutData;
import com.extjs.gxt.ui.client.widget.menu.AdapterMenuItem;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.extjs.gxt.ui.client.widget.tips.ToolTipConfig;
import com.extjs.gxt.ui.client.widget.toolbar.AdapterToolItem;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.HasWidgets;

public class ComponentDelegate extends BaseDelegate {

	private Component comp;

	protected String[] props = { "borders" };

	// element ng
	protected String[] innerProps = { "toolTip", "borders", "enabled", "data",
			"visible" };

	public ComponentDelegate(WidgetService service, Component widget) {
		super(service, widget);
		this.comp = (Component) widget;
	}

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

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

	@SuppressWarnings("deprecation")
	@Override
	public Object exec(String mthodName, Object[] parms) {
		if ("getId".equals(mthodName)) {
			return comp.getId();
		} else if ("getState".equals(mthodName)) {
			return comp.getState();
		} else if ("getData".equals(mthodName)) {
			return comp.getData();
		} else if ("getBaseStyle".equals(mthodName)) {
			return comp.getBaseStyle();
		} else if ("getBorders".equals(mthodName)) {
			return comp.getBorders();
		} else if ("getElement".equals(mthodName)) {
			return comp.getElement();
		} else if ("getItemId".equals(mthodName)) {
			return comp.getItemId();
		} else if ("getLayoutData".equals(mthodName)) {
			return ComponentHelper.getLayoutData(comp);
		} else if ("getModel".equals(mthodName)) {
			return comp.getModel();
		} else if ("getToolTip".equals(mthodName)) {
			return comp.getToolTip();
		} else if ("setBorders".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setBorders((Boolean) parms[0]);
			return comp;
		} else if ("setData".equals(mthodName) && parms[0] instanceof Object) {
			comp.setData((Object) parms[0]);
			return comp;
		} else if ("setElement".equals(mthodName)
				&& parms[0] instanceof Element) {
			comp.setElement((Element) parms[0]);
			return comp;
		} else if ("setEnabled".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setEnabled((Boolean) parms[0]);
			return comp;
		} else if ("setEnableState".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setEnableState((Boolean) parms[0]);
			return comp;
		} else if ("setHeight".equals(mthodName) && parms[0] instanceof String) {
			comp.setHeight((String) parms[0]);
			return comp;
		} else if ("setId".equals(mthodName) && parms[0] instanceof String) {
			comp.setId((String) parms[0]);
			return comp;
		} else if ("setItemId".equals(mthodName) && parms[0] instanceof String) {
			comp.setItemId((String) parms[0]);
			return comp;
		} else if ("setLayoutData".equals(mthodName)
				&& parms[0] instanceof LayoutData) {
			ComponentHelper.setLayoutData(comp, (LayoutData) parms[0]);
			return comp;
		} else if ("setLayoutData".equals(mthodName)
				&& parms[0] instanceof LayoutDataWidget) {
			LayoutDataWidget lw = (LayoutDataWidget) parms[0];
			ComponentHelper.setLayoutData(comp, lw.getWrapLayoutData());
			return comp;
		} else if ("setStyleName".equals(mthodName)
				&& parms[0] instanceof String) {
			comp.setStyleName((String) parms[0]);
			return comp;
		} else if ("setTitle".equals(mthodName) && parms[0] instanceof String) {
			comp.setTitle((String) parms[0]);
			return comp;
		} else if ("setToolTip".equals(mthodName)
				&& parms[0] instanceof ToolTipConfig) {
			comp.setToolTip((ToolTipConfig) parms[0]);
			return comp;
		} else if ("setToolTip".equals(mthodName) && parms[0] instanceof String) {
			comp.setToolTip((String) parms[0]);
			return comp;
		} else if ("setVisible".equals(mthodName)
				&& parms[0] instanceof Boolean) {
			comp.setVisible((Boolean) parms[0]);
			return comp;
		} else if ("setWidth".equals(mthodName) && parms[0] instanceof String) {
			comp.setWidth((String) parms[0]);
			return comp;
		}
		return super.exec(mthodName, parms);
	}

	@Override
	public Field getLtext(String prop) {
		if (GxtUtil.contains(super.getProps(), prop)) {
			return super.getLtext(prop);
		}
		return GxtUtil.getLtext(this, prop);
	}

	@Override
	public void setLtext(String prop, Field ltext) {
		if (!ltext.isDirty()) {
			return;
		}
		if (GxtUtil.contains(super.getProps(), prop)) {
			super.setLtext(prop, ltext);
		}
		GxtUtil.setLtext(this, prop, ltext);
	}

	@Override
	public String makeParmString(Object o) {
		if (o instanceof Rectangle) {
			Rectangle r = (Rectangle) o;
			return "new Rectangle(" + r.x + "," + r.y + "," + r.width + ","
					+ r.height + ")";
		} else if (o instanceof Margins) {
			Margins r = (Margins) o;
			return "new Margins(" + r.top + "," + r.left + "," + r.bottom + ","
					+ r.right + ")";
		} else if (o instanceof Point) {
			Point r = (Point) o;
			return "new Point(" + r.x + "," + r.y + ")";
		} else if (o instanceof Size) {
			Size r = (Size) o;
			return "new Size(" + r.width + "," + r.height + ")";
		} else if (o instanceof Scroll) {
			return "Scroll." + o.toString();
		} else if (o instanceof LayoutRegion) {
			return "LayoutRegion." + o.toString();
		} else if (o instanceof Orientation) {
			return "Orientation." + o.toString();
		} else if (o instanceof HorizontalAlignment) {
			return "HorizontalAlignment." + o.toString();
		} else if (o instanceof VerticalAlignment) {
			return "VerticalAlignment." + o.toString();
		} else if (o instanceof LabelAlign) {
			return "LabelAlign." + o.toString();
		} else if (o instanceof NumberFormat) {
			NumberFormat format = (NumberFormat) o;
			return "NumberFormat.getFormat(" + format.getPattern() + ")";
		} else if (o instanceof DateTimeFormat) {
			DateTimeFormat format = (DateTimeFormat) o;
			return "DateTimeFormat.getFormat(" + format.getPattern() + ")";
		}
		return super.makeParmString(o);
	}

	@Override
	public Object getParmObj(String parmStr) {
		int st = parmStr.indexOf('(') + 1;
		if (st > 0) {
			int en = parmStr.lastIndexOf(')');
			if (en == -1) {
				en = parmStr.length();
			}
			String p = parmStr.substring(st, en);
			if (parmStr.indexOf(" Rectangle(") != -1) {
				return GxtUtil.makeRectangle(p);
			} else if (parmStr.indexOf(" Margins(") != -1) {
				return GxtUtil.makeMargins(p);
			} else if (parmStr.indexOf(" Point(") != -1) {
				return GxtUtil.makePoint(p);
			} else if (parmStr.indexOf(" Size(") != -1) {
				return GxtUtil.makeSize(p);
			} else if (parmStr.indexOf("NumberFormat.getFormat(") != -1) {
				return GxtUtil.makeNumberFormat(p);
			} else if (parmStr.indexOf("DateTimeFormat.getFormat(") != -1) {
				return GxtUtil.makeDateTimeFormat(p);
			}
		}
		if (parmStr.indexOf('.') != -1) {
			Object o = GxtUtil.getEnumObj(parmStr);
			if (o != parmStr) {
				return o;
			}
		}
		return super.getParmObj(parmStr);
	}

	@Override
	public Menu makeBar() {
		Menu bar1 = super.makeBar();
		DesignPanel dp = DesignPanel.getInstance();
		if (!dp.isBase() && !dp.isResizeMode()
				&& comp.getParent() instanceof LayoutContainer) {
			int i = 99;
			if (bar1.getItemCount() < i) {
				i = bar1.getItemCount();
			}
			LayoutData data = getLayoutData(comp);
			if (data != null) {
				bar1.insert(new MenuItem(
						GxtUtil.getSimpleName(data.getClass()),"icon-menu-LD",
						new SetLayoutData(comp, data)), i);
			}
		}
		return bar1;
	}

	private LayoutData getLayoutData(Component comp) {
		LayoutData ld = ComponentHelper.getLayoutData(comp);
		if (ld == null) {
			LayoutContainer lc = (LayoutContainer) comp.getParent();
			ld = GxtUtil.getValidLayoutData(lc.getLayout());
		}
		return ld;
	}

	private class SetLayoutData extends SelectionListener<ComponentEvent> {
		private Component con;

		private LayoutData data;

		public SetLayoutData(Component con, LayoutData data) {
			super();
			this.con = con;
			this.data = data;
		}

		@Override
		public void componentSelected(ComponentEvent ce) {
			LayoutDataWidget ldWidget = GxtUtil.getLayoutDataWidget(data, con);
			PropDialog pd = new PropDialog(ldWidget);
			pd.show();
			DesignPanel.getInstance().getPop().hide();
		}

	}

	@Override
	public List<Component> getChildren() {
		List<Component> l = new ArrayList<Component>();
		LayoutData ld = ComponentHelper.getLayoutData(comp);
		if (ld != null) {
			l.add(GxtUtil.getLayoutDataWidget(ld, comp));
		}
		return l;
	}

	@Override
	public boolean isAddable() {
		if (this.widget instanceof Container) {
			return true;
		}
		return false;
	}

	@Override
	public void addWidget(Component widget) {
		if (widget instanceof LayoutDataWidget) {
			LayoutDataWidget lw = (LayoutDataWidget) widget;
			ComponentHelper.setLayoutData(comp, lw.getWrapLayoutData());
			lw.setParent(comp);
			return;
		}
		super.addWidget(widget);
	}

	@Override
	public boolean isAddableToParent(Component parent) {
		if (parent instanceof LayoutContainer) {
			LayoutContainer lc = (LayoutContainer) parent;
			if (lc.getLayout() instanceof AccordionLayout) {
				if (this instanceof ContentPanelDelegate) {
					return true;
				} else {
					return false;
				}
			}
			if (lc.getLayout() instanceof BorderLayout) {
				if (this instanceof BoxComponentDelegate) {
					return true;
				} else {
					return false;
				}
			}
		}
		if (parent instanceof LayoutContainer || parent instanceof HasWidgets
				|| parent instanceof Header
				|| parent instanceof AdapterToolItem
				|| parent instanceof AdapterField
				|| parent instanceof AdapterMenuItem) {
			return true;
		}
		return false;
	}

	@Override
	public String getAddCode(Component widget, List<String>[] lists,
			String parentFiledName, String fieldName, Map<Object, Object> map) {
		if (widget instanceof LayoutDataWidget) {
			String gpname = (String) map.get(parentFiledName + "_addedTo");
			return gpname + ".add(" + parentFiledName + "," + fieldName + ");";
		}
		return super.getAddCode(widget, lists, parentFiledName, fieldName, map);
	}

	@Override
	public boolean isRemovableToParent(Component parent) {
		if (ComponentHelper.getLayoutData(comp) instanceof BorderLayoutData
				&& ((BorderLayoutData) ComponentHelper.getLayoutData(comp))
						.getRegion() == LayoutRegion.CENTER) {
			return false;
		} else if (parent instanceof AdapterToolItem
				|| parent instanceof AdapterField
				|| parent instanceof AdapterMenuItem) {
			return false;
		}
		return super.isRemovableToParent(parent);
	}

	@Override
	public void makeSetterCode(Component widget, List<String>[] lists,
			String fstr, String instr, String obstr, String fn, Map map) {
		for (int i = 0; i < getProps().length; i++) {
			String prop = getProps()[i];
			Object o = exec(GxtUtil.makeGetterName(prop), null);
			if (o == null) {
				o = exec(GxtUtil.makeGetterName(prop, true), null);
			}
			//bordersは必須
			if ("borders".equals(prop) || o != null && !"".equals(o.toString())
					&& !isAutoId(prop, o) && !o.equals(getDefaultValue(prop))) {
				lists[1]
						.add(fn + "." + makeSetterPart(prop, makeParmString(o)));
			}
		}
	}

	protected String makeSetterPart(String prop, String parm) {
		return GxtUtil.makeSetterName(prop) + "(" + parm + ");";
	}

	// x-auto-xxxのid titleは作らない
	private boolean isAutoId(String prop, Object o) {
		return ("id".equals(prop) || "title".equals(prop)) && o != null
				&& o.toString().startsWith("x-auto-");
	}

	private Component definstance;

	private Object getDefaultValue(String prop) {
		WidgetService ws;
		if (definstance == null) {
			ws = WidgetServiceFactory.getService(comp);
			definstance = (Component) ws.getInstance();
		}
		ws = WidgetServiceFactory.getService(definstance);
		Object o = ws.exec(GxtUtil.makeGetterName(prop), null);
		if (o == null) {
			o = ws.exec(GxtUtil.makeGetterName(prop, true), null);
		}
		return o;
	}

	@Override
	public boolean isClickResize() {
		return false;
	}

	@Override
	public Component getParent() {
		// 親の親がnullのケースはGxtUtilで探す
		if (comp.getParent() == null || comp.getParent().getParent() == null) {
			Component parent = comp.getData("parent");
			if (parent == null) {
				parent = GxtUtil.findParent(comp);
				comp.setData("parent", parent);
			}
			return parent;
		}
		return super.getParent();
	}

}
