/*
 * Copyright (c) 2006-2008 Maskat Project.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Maskat Project - initial API and implementation
 */
package org.maskat.ui.views.properties;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.PropertyDescriptor;

import org.maskat.core.layout.AbstractComponent;
import org.maskat.core.layout.LayoutElement;
import org.maskat.ui.editors.layout.commands.UndoableSetPropertyCommand;
import org.maskat.ui.editors.layout.tools.ComponentUtils;
import org.maskat.ui.views.properties.descriptor.MaskatTextPropertyDescriptor;

public class AbstractComponentPropertySource implements IPropertySource {

	public static final String PROP_NAME = "_prop_name_"; 
	
	public static final String PROP_LEFT = "_prop_left_";
	
	public static final String PROP_TOP = "_prop_top_";

	public static final String PROP_WIDTH = "_prop_width_";

	public static final String PROP_HEIGHT = "_prop_height_";

	protected static IPropertyDescriptor[] descriptor; 
	
	/** key=PropertyDescriptor id such as _prop_name_; value=property name of Bean */
	protected static Map propMap = new HashMap();
	
	protected Object bean;
	
	private CommandStack commandStack;
	
	public AbstractComponentPropertySource(Object bean) {
		this.bean = bean;
		initialize();
	}
	
	protected void initialize() {
		descriptor = new PropertyDescriptor[] {
				new MaskatTextPropertyDescriptor(PROP_NAME, "name"),
				new MaskatTextPropertyDescriptor(PROP_LEFT, "left"),
				new MaskatTextPropertyDescriptor(PROP_TOP, "top"),
				new MaskatTextPropertyDescriptor(PROP_WIDTH, "width"),
				new MaskatTextPropertyDescriptor(PROP_HEIGHT, "height")};

//		make sure the values are the same as bean's property.
		if (bean instanceof AbstractComponent) {
			propMap.put(PROP_NAME, "name");
		  	propMap.put(PROP_LEFT, "left");
		  	propMap.put(PROP_TOP, "top");
		  	propMap.put(PROP_WIDTH, "width");
		  	propMap.put(PROP_HEIGHT, "height");
		}
	}
	
	public Object getEditableValue() {
		return this;
	}

	public IPropertyDescriptor[] getPropertyDescriptors() {
		return descriptor;
	}

	public Object getPropertyValue(Object id) {
		Object result = doGetPropertyValue(id);
		return (result == null) ? "" : result;
	}
	
	protected Object doGetPropertyValue(Object id) {
		if (id != null && propMap.containsKey(id)) {
			try {
				return BeanUtils.getProperty(bean, (String) propMap.get(id));
			} catch (Exception e) {
				e.printStackTrace();
			}			
		}
		return null;
	}

	public boolean isPropertySet(Object id) {
		return false;
	}

	public void resetPropertyValue(Object id) {
	}

	public void setPropertyValue(Object id, Object value) {
		if ("".equals(value)) {
			value = null;
			// PropertySourceに空白文字列を渡さないように
			// xmlに name="" のようなattributeを出力しないように
		}
		doSetPropertyValue(id, value);
	}

	protected void doSetPropertyValue(Object id, Object value) {
		if (id != null && propMap.containsKey(id)) {
			if(value != null && PROP_NAME.equals(id) && ComponentUtils.isExistenceId(((LayoutElement)bean).getLayout(), (String)value)) {
//				try {
//					value = BeanUtils.getProperty(bean, (String) propMap.get(PROP_NAME));
//				}catch(Exception e){
//				}
				return;
			} else if (value == null && PROP_NAME.equals(id)) {
				return;
			}
			
			if (commandStack != null) {
				Object oldValue = null;
				try {
					oldValue = BeanUtils.getProperty(bean, (String) propMap.get(id));
				} catch (Exception e) {
					e.printStackTrace();
				}
				if ((oldValue == null && value != null) || (oldValue != null && !oldValue.equals(value))) {
					commandStack.execute(new UndoableSetPropertyCommand(bean, (String) propMap.get(id), value));
				}
				return;
			}
			
			try {
				BeanUtils.setProperty(bean, (String) propMap.get(id), value);
			} catch (Exception e) {
				e.printStackTrace();
			}			
		}
	}
	
	public void setCommandStack(CommandStack commandStack) {
		this.commandStack = commandStack;
	}
}
