package com.xaadin.elementfactory;

import com.google.common.base.Strings;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Component;
import com.xaadin.VisualTreeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public abstract class AbstractDefaultElementFactory implements ElementFactory {

	private final static Logger LOG = LoggerFactory.getLogger(AbstractDefaultElementFactory.class);

	public Object createClass(Object parentObject, String classname) throws ElementFactoryException {
		try {
			Class clazz = null;
			try {
				clazz = Class.forName(classname);
			} catch (ClassNotFoundException ignored) {
			}

			if (clazz == null) {
				throw new ClassNotFoundException(classname);
			}

			return clazz.newInstance();
		} catch (Exception e) {
			throw new ElementFactoryException(e);
		}
	}

	public void setItemStyles(Object component, String[] styles) {
		if (component instanceof Component)
			for (String style : styles)
				((Component) component).addStyleName(style);
	}

	protected Method findMethodForName(Class clazz, String methodName, int parameterCount) throws ElementFactoryException {
		for (Method method : clazz.getMethods()) {
			if (method.getName().equals(methodName)
					&& (method.getParameterTypes().length == parameterCount)) {
				return method;
			}
		}

		// if no public method was found, try to find a private one
		for (Method method : clazz.getDeclaredMethods()) {
			if (method.getName().equals(methodName)
					&& (method.getParameterTypes().length == parameterCount)) {
				return method;
			}
		}

		throw new ElementFactoryException("could not find " + clazz.getName() + "." + methodName);
	}

	protected void invokeMethod(Method method, Object eventHandler, Object... parameters) throws InvocationTargetException, IllegalAccessException {
		LOG.trace("Invoking {}", method);
		boolean accessible = method.isAccessible();
		method.setAccessible(true);
		method.invoke(eventHandler, parameters);
		method.setAccessible(accessible);
	}

	public void setProperty(Object target, String property, String value) throws ElementFactoryException {
		try {
			handleNormalProperty(target, property, value);
		} catch (Exception e) {
			throw new ElementFactoryException(e);
		}
	}

	protected Alignment parseAlignment(String alignment) {
		if (Strings.isNullOrEmpty(alignment)) {
			return Alignment.MIDDLE_LEFT;
		}

		switch (alignment) {
			case "TOP_LEFT":
				return Alignment.TOP_LEFT;
			case "TOP_CENTER":
				return Alignment.TOP_CENTER;
			case "TOP_RIGHT":
				return Alignment.TOP_RIGHT;
			case "MIDDLE_LEFT":
				return Alignment.MIDDLE_LEFT;
			case "MIDDLE_CENTER":
				return Alignment.MIDDLE_CENTER;
			case "MIDDLE_RIGHT":
				return Alignment.MIDDLE_RIGHT;
			case "BOTTOM_LEFT":
				return Alignment.BOTTOM_LEFT;
			case "BOTTOM_CENTER":
				return Alignment.BOTTOM_CENTER;
			case "BOTTOM_RIGHT":
				return Alignment.BOTTOM_RIGHT;
			default:
				LOG.warn("unknown alignment for GridLayout: {}", alignment);
				return Alignment.MIDDLE_LEFT;
		}
	}

	private void handleNormalProperty(Object target, String property, String value) throws ElementFactoryException, InvocationTargetException, IllegalAccessException {
		Class clazz = target.getClass();
		String setterName = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);

		Method method = findMethodForName(clazz, setterName, 1);
		if (method == null) {
			throw new ElementFactoryException("could not find setter for attribute " + property + " on target " + target.getClass().getName());
		}
		if (method.getParameterTypes()[0].equals(int.class) || method.getParameterTypes()[0].equals(Integer.class)) {
			invokeMethod(method, target, Integer.parseInt(value));
		} else if (method.getParameterTypes()[0].equals(double.class) || method.getParameterTypes()[0].equals(Double.class)) {
			invokeMethod(method, target, Double.parseDouble(value));
		} else if (method.getParameterTypes()[0].equals(boolean.class) || method.getParameterTypes()[0].equals(Boolean.class)) {
			invokeMethod(method, target, Boolean.parseBoolean(value));
		} else {
			invokeMethod(method, target, value);
		}
	}

	protected float getFloatFromVisualTreeNode(String parameterName, VisualTreeNode node) {
		try {
			return Float.parseFloat(node.getAdditionalParameter(parameterName, "0.0"));
		} catch (NumberFormatException e) {
			return 0;
		}
	}
}

@@ -603,221 +603,39 @@
 %0A%09%09%09
-Class clazz = null;%0A%09%09%09try %7B%0A%09%09%09%09clazz = Class.forName(classname);%0A%09%09%09%7D catch (ClassNotFoundException ignored) %7B%0A%09%09%09%7D%0A%0A%09%09%09if (clazz == null) %7B%0A%09%09%09%09throw new ClassNotFoundException(classname);%0A%09%09%09%7D%0A%0A%09%09%09return clazz
+return Class.forName(classname)
 .new
@@ -822,16 +822,166 @@
 mponent)
+ %7B%0A%09%09%09for (String oldStyleName : ((Component) component).getStyleName().split(%22 %22)) %7B%0A%09%09%09%09((Component) component).removeStyleName(oldStyleName);%0A%09%09%09%7D%0A
 %0A%09%09%09for 
@@ -1003,16 +1003,18 @@
  styles)
+ %7B
 %0A%09%09%09%09((C
@@ -1051,24 +1051,33 @@
 ame(style);%0A
+%09%09%09%7D%0A%09%09%7D%0A
 %09%7D%0A%0A%09protect

Add a style cleanup in setStyleNames Cleanup some code