package com.mindoo.ec09.example5.ca.pb;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;

import com.ibm.rcp.propertybroker.event.PropertyChangeEvent;
import com.ibm.rcp.propertybroker.property.PropertyValue;
import com.ibm.rcp.propertybroker.wire.Wire;
import com.mindoo.ec09.example5.ca.DebugUtils;
import com.mindoo.ec09.example5.ca.ViewBeanRegistry;

/**
 * This class received the PropertyChangeEvents through incoming wires from the
 * Property Broker. If possible, those property changes are mapped to the viewparts
 * PCSBean, a Java bean implementation that simplifies the data exchange between the
 * viewpart and other CA components.
 */
public class PBHandler extends Action implements IHandler {

	public void runWithEvent(Event event) {
		if (event instanceof PropertyChangeEvent) {
			final PropertyChangeEvent pEvent = (PropertyChangeEvent) event;
			Thread t = new Thread() {
				public void run() {
					Wire wire = pEvent.getWireDefinition();
					com.ibm.rcp.propertybroker.property.Action action = pEvent.getActionDefinition();
					String id = wire.getTargetEntityId();
					Object data = ViewBeanRegistry.getInstance().getViewBean(id);
					if (data == null) {
						DebugUtils.println("PBHandler: can't locate data for "
								+ wire.getTargetEntityId());
						return;
					}
					PropertyValue value = pEvent.getPropertyValue();
					DebugUtils.println("PBHandler, "
							+ DebugUtils.getEntityProperty("", wire
									.getSourceEntityId(), wire.getSourceName())
									+ "->"
									+ DebugUtils.getEntityProperty("", wire
											.getTargetEntityId(), wire.getTargetName())
											+ " = \"" + value.getValue().toString() + "\"");
					setValue(data, action.getName(), value.getValue());
				}
			};
			Display display = Display.getDefault();
			display.asyncExec(t);
		}
	}

	public static void setValue(Object data, String actionName, Object value) {
		if (!actionName.startsWith("set"))
			return;
		//try to find matching method of the PCSBean
		String methodName = actionName.substring(3);
		methodName = "set" + Character.toUpperCase(methodName.charAt(0)) + methodName.substring(1);
		Class[] methodProfile = new Class[1];
		methodProfile[0] = value.getClass();
		Method setter = null;
		try {
			setter = data.getClass().getMethod(methodName, methodProfile);
		} catch (SecurityException e) {
			//
		} catch (NoSuchMethodException e) {
			//
		}
		if (setter == null) {
			DebugUtils.println("PBHandler.setValue, Cannot find setter "+methodName+"("+methodProfile[0].getName()+")");
			return; // TODO: look for appropriate and convert arg
		}
		Object[] args = new Object[1];
		args[0] = value;
		try {
			//Call the method to transfer the data change
			
			//DebugUtils.println("PBHandler.setValue, invoking "
			//		+methodName+"("
			//		+methodProfile[0].getName()+":"
			//		+value+")");
			setter.invoke(data, args);
		} catch (Exception e) {
			DebugUtils.println("Exception trying to set "+data.getClass().getName()+"$"+actionName+" = "+value);
			e.printStackTrace();
			if (e instanceof InvocationTargetException) {
				InvocationTargetException ite = (InvocationTargetException)e;
				ite.getCause().printStackTrace();
			}
		}
	}

	public static Map getValues(Object data) {
		HashMap map = new HashMap();
		try {
			BeanInfo info = Introspector.getBeanInfo(data.getClass());
			PropertyDescriptor[] props = info.getPropertyDescriptors();
			Object[] args = new Object[0];
			for (int i = 0; i < props.length; i++)
				map.put(props[i].getName(), props[i].getReadMethod().invoke(data, args));
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return map;
	}

	public static Object getValue(Object data, String actionName) {
		try {
			BeanInfo info = Introspector.getBeanInfo(data.getClass());
			PropertyDescriptor[] props = info.getPropertyDescriptors();
			Object[] args = new Object[0];
			for (int i = 0; i < props.length; i++)
				if (props[i].getName().equalsIgnoreCase(actionName))
					return props[i].getReadMethod().invoke(data, args);
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}

	public void addHandlerListener(IHandlerListener listener) {
	}

	public void dispose() {
	}

	public Object execute(ExecutionEvent ev) throws ExecutionException {
		Object event = ev.getTrigger();
		if ((event != null) && (event instanceof Event))
			runWithEvent((Event)event);
		return null;
	}

	public void removeHandlerListener(IHandlerListener listener) {
	}
}
