
package no.priv.garshol.duke.utils;

import java.util.Map;
import java.util.ArrayList;
import java.util.Collection;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

import no.priv.garshol.duke.DukeException;
import no.priv.garshol.duke.DukeConfigException;

public class ObjectUtils {

  /**
   * Returns the enum constant from the given enum class representing
   * the constant with the given identifier/name.
   */
  public static Object getEnumConstantByName(Class klass, String name) {
    name = name.toUpperCase();
    Object c[] = klass.getEnumConstants();
    for (int ix = 0; ix < c.length; ix++)
      if (c[ix].toString().equals(name))
        return c[ix];
    throw new DukeConfigException("No such " + klass + ": '" + name + "'");
  }
  
  /**
   * Calls the named bean setter property on the object, converting
   * the given value to the correct type. Note that parameter 'prop'
   * is converted to a method name according to Lisp convention:
   * (foo-bar), and not the usual Java dromedaryCase (fooBar). So
   * "foo-bar" will become "setFooBar".
   *
   * <p>The value conversion is mostly straightforward, except that if
   * the type of the method's first parameter is not a
   * java.lang.Something, then the method will assume that the value
   * is the name of an object in the 'objects' map, and pass that.
   *
   * <p>Further, if the type is a Collection, the method will assume
   * the value is a list of object names separated by whitespace.
   */
  public static void setBeanProperty(Object object, String prop, String value,
                                     Map<String, Object> objects) {
    prop = makePropertyName(prop);
    try {
      boolean found = false;
      Method[] methods = object.getClass().getMethods();
      for (int ix = 0; ix < methods.length && !found; ix++) {
        if (!methods[ix].getName().equals(prop))
          continue;
        if (methods[ix].getParameterTypes().length != 1)
          continue;

        Class type = methods[ix].getParameterTypes()[0];
        methods[ix].invoke(object, convertToType(value, type, objects));
        found = true;
      }

      if (!found)
        throw new DukeConfigException("Couldn't find method '" + prop + "' in " +
                                      "class " + object.getClass());
    } catch (IllegalArgumentException e) {
      throw new DukeConfigException("Couldn't set bean property " + prop +
                                    " on object of class " + object.getClass() +
                                    ": " + e);
    } catch (IllegalAccessException e) {
      throw new DukeException(e);
    } catch (InvocationTargetException e) {
      throw new DukeConfigException("Couldn't set bean property " + prop +
                                    " on object of class " + object.getClass() +
                                    ": " + e);
    }
  }

  // public because it's used by other packages that use Duke
  public static String makePropertyName(String name) {
    char[] buf = new char[name.length() + 3];
    int pos = 0;
    buf[pos++] = 's';
    buf[pos++] = 'e';
    buf[pos++] = 't';
    
    for (int ix = 0; ix < name.length(); ix++) {
      char ch = name.charAt(ix);
      if (ix == 0)
        ch = Character.toUpperCase(ch);
      else if (ch == '-') {
        ix++;
        if (ix == name.length())
          break;
        ch = Character.toUpperCase(name.charAt(ix));
      }

      buf[pos++] = ch;
    }

    return new String(buf, 0, pos);
  }

  private static Object convertToType(String value, Class type,
                                      Map<String, Object> objects) {
    if (type == String.class)
      return value;
    else if (type == Integer.TYPE)
      return Integer.parseInt(value);
    else if (type == Boolean.TYPE)
      return Boolean.parseBoolean(value);
    else if (type == Double.TYPE)
      return Double.parseDouble(value);
    else if (type == Float.TYPE)
      return Float.parseFloat(value);
    else if (type == Character.TYPE) {
      if (value.length() != 1)
        throw new DukeConfigException("String '" + value + "' is not a character");
      return new Character(value.charAt(0));
    } else if (type.isEnum())
      return getEnumConstantByName(type, value);
    else if (type.equals(Collection.class)) {
      Collection coll = new ArrayList();
      String[] values = StringUtils.split(value);
      for (int ix = 0; ix < values.length; ix++) {
        Object object = objects.get(values[ix]);
        if (object == null)
          object = values[ix];
        coll.add(object);
      }
      return coll;
    } else {
      // now we check if there's an object by this name. if there is
      // we return that, otherwise we return the value itself.
      Object object = objects.get(value);
      if (object != null)
        return object;
      else
        return value;
    }
  }

  public static Object instantiate(String klassname) {
    try {
      Class klass = Class.forName(klassname);
      return klass.newInstance();
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    } catch (InstantiationException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }
  
}
@@ -781,18 +781,16 @@
 %22);%0A  %7D%0A
-  
 %0A  /**%0A 
@@ -3151,20 +3151,16 @@
  = 't';%0A
-    
 %0A    for
@@ -5011,16 +5011,23 @@
 lassname
+.trim()
 );%0A     
@@ -5303,8 +5303,7 @@
   %7D%0A
-  
 %0A%7D
+%0A

Trim class names to avoid hard-to-detect errors