package lu.tudor.santec.gecamed.letter.gui.placeholders;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.apache.log4j.Logger;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: JavaScriptClassLoader.java,v $
 */

public class JavaScriptClassLoader
{
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(JavaScriptClassLoader.class.getName());
	
	
	public Class<?> load (String className) throws Exception
	{
		try
		{
			return Class.forName(className);
		}
		catch (ClassNotFoundException e)
		{
			logger.error("No class found called \"" + className + "\"\n" + e.getMessage());
			throw e;
		}
	}
	
	
	public Object execute (String className, String methodName, Object ... parameter) throws Exception
	{
		try
		{
			Class<?> clazz = load(className);
			Method method = clazz.getMethod(methodName, getClasses(parameter));
			method.setAccessible(true);
			
			if (!Modifier.isStatic(method.getModifiers()))
			{
				logger.error("Couldn't invoke non-static method \"" + methodName + "\" of class \"" + className + "\".");
				return null;
			}
			
			return method.invoke(null, parameter);
		}
		catch (NoSuchMethodException e)
		{
			logger.error("Method \"" + methodName + "\" of class \"" + className + "\" not found.", e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("Couldn't execute method \"" + methodName + "\" of class \"" + className + "\".", e);
			throw e;
		}
	}
	
	
	public Object get (String className, String memberName) throws Exception
	{
		try
		{
			Class<?> clazz = load(className);
			Field member = clazz.getField(memberName);
			member.setAccessible(true);
			
			if (!Modifier.isStatic(member.getModifiers()))
			{
				logger.error("Couldn't get non-static member \"" + memberName + "\" of class \"" + className + "\".");
				throw new RuntimeException("Couldn't get non-static member \"" + memberName + "\" of class \"" + className + "\".");
			}
			
			return member.get(null);
		}
		catch (NoSuchFieldException e)
		{
			logger.error("Member \"" + memberName + "\" of class \"" + className + "\" not found.", e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("Couldn't get member \"" + memberName + "\" of class \"" + className + "\".", e);
			throw e;
		}
	}
	
	
	public Object create (String className, Object ... parameter) throws Exception
	{
		try
		{
			Class<?> clazz = load(className);
			Constructor<?> constructor = clazz.getConstructor(getClasses(parameter));
			constructor.setAccessible(true);
			
			return constructor.newInstance(parameter);
		}
		catch (NoSuchMethodException e)
		{
			logger.error("Constructor of class \"" + className + "\" not found.", e);
			throw e;
		}
		catch (Exception e)
		{
			logger.error("Couldn't instanciate constructor of class \"" + className + "\".", e);
			throw e;
		}
	}
	
	
	private Class<?>[] getClasses (Object[] objects)
	{
		if (objects == null || objects.length == 0)
			return null;
		
		Class<?>[] classes = new Class<?>[objects.length];
		
		for (int i = 0; i < objects.length; i++)
			classes[i] = objects[i].getClass();
		
		return classes;
	}
}
