
package de.ivu.elect.util;

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

public class ReflectionAccess {

  private static final char SEPARATOR = '.';
  private static final String SET = "set";
  private static final String GET = "get";

  public static <C> void setReflection(Object object, String path, Class<C> valueClass, C value) {

    Object objectToCall = object;
    String methodeName = path;

    if (path.indexOf(SEPARATOR) > 0) {
      objectToCall = findObject(object, path);
      methodeName = path.substring(path.lastIndexOf(SEPARATOR) + 1);
    }

    callSetter(objectToCall, methodeName, valueClass, value);

  }

  public static Object getReflection(Object object, String path) {

    Object objectToCall = object;
    String methodeName = path;

    if (path.indexOf(SEPARATOR) > 0) {
      objectToCall = findObject(object, path);
      methodeName = path.substring(path.lastIndexOf(SEPARATOR) + 1);
    }

    return callGetter(objectToCall, methodeName);

  }

  static Object findObject(Object object, String path) {

    Object currentObject = object;
    String[] pathEntries = path.split("\\.");
    for (int i = 0; i < pathEntries.length - 1; i++) {
      currentObject = callGetter(currentObject, pathEntries[i]);
    }

    return currentObject;
  }

  static Object callGetter(Object objectToCall, String methodeName) {

    try {
      Method m = objectToCall.getClass().getMethod(getGetterMethodeName(methodeName));

      return m.invoke(objectToCall);

    } catch (NoSuchMethodException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (SecurityException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }

  static <C> void callSetter(Object objectToCall, String methodeName, Class<C> valueClass, C value) {

    try {
      Method m = objectToCall.getClass().getMethod(getSetterMethodeName(methodeName), valueClass);

      m.invoke(objectToCall, value);

    } catch (NoSuchMethodException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (SecurityException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException(e.getMessage(), e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }

  private static String getGetterMethodeName(String methodeName) {
    return GET + getMethodeName(methodeName);
  }

  static String getSetterMethodeName(String methodeName) {
    return SET + getMethodeName(methodeName);
  }

  private static String getMethodeName(String methodeName) {
    return methodeName.substring(0, 1).toUpperCase() + methodeName.substring(1);
  }
}
