/************************************************
 * Copyright (c) Shen Li. All rights reserved.  *
 * http://joyaop.sourceforge.net                *
 * -------------------------------------------- *
 * Distributable under LGPL license.            *
 * See terms of license at gnu.org.             *
 ************************************************/
package net.sf.joyaop.util;

import net.sf.cglib.proxy.Factory;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Shen Li
 */
public abstract class ClassUtils {
    public static Object newInstance(Class clazz) {
        try {
            return getFastClass(clazz).newInstance();
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static Object newInstance(Class clazz, Class[] argumentTypes, Object[] arguments) {
        try {
            return getFastClass(clazz).newInstance(argumentTypes, arguments);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static Class loadClass(String name) {
        try {
            return getClassLoader().loadClass(name);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public static FastClass getFastClass(Class clazz) {
        return FastClass.create(getClassLoader(), clazz);
    }

    private static final Map fastMethods = new HashMap();

    public static FastMethod getFastMethod(Class clazz, Method method) {
        synchronized (fastMethods) {
            FastMethod fastMethod = (FastMethod) fastMethods.get(method);
            if (fastMethod == null) {
                fastMethod = getFastClass(clazz).getMethod(method.getName(), method.getParameterTypes());
                fastMethods.put(method, fastMethod);
            }
            return fastMethod;
        }
    }

    public static Object invokeFastMethod(FastMethod fastMethod, Object target, Object[] args) throws Throwable {
        try {
            return fastMethod.invoke(target, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    public static ClassLoader getClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }

    private static final Map proxyFactories = new HashMap();

    public static void putProxyFactory(Class originalClass, Factory factory) {
        synchronized (proxyFactories) {
            if (proxyFactories.containsKey(originalClass)) {
                return;
            }
            proxyFactories.put(originalClass, factory);
        }
    }

    public static Factory getProxyFactory(Class originalClass) {
        synchronized (proxyFactories) {
            return (Factory) proxyFactories.get(originalClass);
        }
    }
}
