/*
 * Created on 2003/11/20
 *
 * To change the template for this generated file go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
package hiro.yoshioka.classmanager;

import hiro.yoshioka.util.FileList;

import java.io.File;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ClassManager {
	private static Log log = LogFactory.getLog(ClassManager.class);

	URLClassLoader loader;

	HashMap<String, URL> _libList = new HashMap<String, URL>();

	public ClassManager(File lib_file) throws MalformedURLException {
		if (log.isTraceEnabled()) {
			log.trace(lib_file.getAbsolutePath());
		}
		File[] fs = new FileList(".*[.]jar").getMatches(lib_file, 1);
		for (int i = 0; i < fs.length; i++) {
			add_lib(fs[i]);
		}
	}

	public ClassManager() {
	}

	private void createLoader() throws MalformedURLException {
		Iterator ite = _libList.entrySet().iterator();
		ArrayList<URL> list = new ArrayList<URL>();
		while (ite.hasNext()) {
			list.add((URL) ((Map.Entry) ite.next()).getValue());
		}
		// if (log.isTraceEnabled()) {
		// log.trace("Loading Class Path" + list);
		// }
		URL[] urls = new URL[list.size()];
		loader = new URLClassLoader((URL[]) list.toArray(urls));
	}

	public Class getClassForName(String className)
			throws ClassNotFoundException, MalformedURLException {
		// logger.info(className);
		createLoader();
		try {
			// if (log.isTraceEnabled()) {
			// log.trace("className:[" + className + "]");
			// }
			Class clazz = loader.loadClass(className);

			// if (log.isTraceEnabled()) {
			// log.trace("loadClass return:[" + clazz + "]");
			// }
			return clazz;
		} catch (Throwable e) {
			log.error("input:" + className, e);
			return null;
		}
	}

	public Object getObject(String className, Class[] parameterTypes,
			Object[] initargs) throws Exception {
		createLoader();
		Constructor construntor = loader.loadClass(className).getConstructor(
				parameterTypes);
		return construntor.newInstance(initargs);
	}

	public boolean add_lib(File file) throws MalformedURLException {
		if (file == null || !file.exists()) {
			if (log.isWarnEnabled()) {
				log.warn("file not exists! " + file);
			}
			return false;
		}
		_libList.put(file.getAbsolutePath(), file.toURL());

		return true;
	}

	public static void main(String[] args) {
		ClassManager obj = new ClassManager();
		try {
			obj.add_lib(new File("D:/Tools/hsqldb/lib/hsqldb.jar"));
			obj.add_lib(new File(
					"D:/Tools/Microsoft SQL Server 2005 JDBC Driver/sqljdbc_1.1/jpn/sqljdbc.jar"));
			// obj.getClassInstanceOf(Driver.class, checkTargetClassNames)
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private boolean recurse(Class driver, Class target) {
		Class[] interfaces = target.getInterfaces();
		for (int i = 0; i < interfaces.length; i++) {
			if (interfaces[i].equals(driver)) {
				return true;
			}
			Class sp = interfaces[i].getSuperclass();
			if (sp != null) {
				if (recurse(driver, interfaces[i])) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @param class1
	 * @return
	 */
	public List<String> getClassInstanceOf(Class class1,
			String[] checkTargetClassNames) {
		List<String> list = new ArrayList<String>();
		try {
			createLoader();
			for (int i = 0; i < checkTargetClassNames.length; i++) {
				try {
					Class clazz = loader.loadClass(checkTargetClassNames[i]);
					if (recurse(class1, clazz)) {
						if (log.isDebugEnabled()) {
							log.debug("Grab Classes : " + clazz);
						}
						list.add(checkTargetClassNames[i]);
					}
				} catch (Throwable e1) {
				}
			}
		} catch (Throwable e) {
		}
		return list;

	}
}