package org.seasar.framework.container.factory;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.seasar.framework.container.ExtensionNotFoundRuntimeException;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.PropertiesUtil;
import org.seasar.framework.util.ResourceUtil;

/**
 * @author higa
 *
 */
public final class S2ContainerFactory {

	public static final String PUBLIC_ID = "-//SEASAR//DTD S2Container//EN";
	public static final String DTD_PATH =
		"org/seasar/framework/container/factory/components.dtd";
	public static final String BUILDER_CONFIG_PATH =
		"s2containerbuilder.properties";
	private static Properties builderProps_ = new Properties();
	private static Map builders_ = new HashMap();
	private static S2ContainerBuilder defaultBuilder_ =
		new XmlS2ContainerBuilder();

	static {
		if (ResourceUtil.isExist(BUILDER_CONFIG_PATH)) {
			PropertiesUtil.load(
				builderProps_,
				ResourceUtil.getResourceAsStream(BUILDER_CONFIG_PATH));
		}
		builders_.put("xml", defaultBuilder_);
		builders_.put("dicon", defaultBuilder_);
	}

	private S2ContainerFactory() {
	}

	public static S2Container create(String path) {
		return create(path, null);
	}
	
	public static S2Container create(String path, ClassLoader classLoader) {
		String ext = getExtension(path);
		S2Container container = getBuilder(ext).build(path, classLoader);
		return container;
	}
	
	public static S2Container include(S2Container parent, String path) {
		S2Container root = parent.getRoot();
		S2Container child = null;
		synchronized (root) {
			if (root.hasDescendant(path)) {
				child = root.getDescendant(path);
				parent.include(child);
			} else {
				String ext = getExtension(path);
				S2ContainerBuilder builder = getBuilder(ext);
				child = builder.include(parent, path);
				root.registerDescendant(child);
			}
		}
		return child;
	}
	
	private static String getExtension(String path) {
		String ext = ResourceUtil.getExtension(path);
		if (ext == null) {
			throw new ExtensionNotFoundRuntimeException(path);
		}
		return ext;
	}
	
	private static S2ContainerBuilder getBuilder(String ext) {
		S2ContainerBuilder builder = null;
		synchronized (builders_) {
			builder = (S2ContainerBuilder) builders_.get(ext);
			if (builder != null) {
				return builder;
			}
			String className = builderProps_.getProperty(ext);
			if (className != null) {
				builder = (S2ContainerBuilder) ClassUtil.newInstance(className);
				builders_.put(ext, builder);
			} else {
				builder = defaultBuilder_;
			}
		}
		return builder;
	}
}
