package org.arefgard.icerya.container;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.arefgard.icerya.container.parse.XmlBeanDefinitionReader;

/**
 * DIコンテナを作成するファクトリ。
 * 
 * @author Takashi Yamashina
 * @since 1.0.0
 */
public class ContainerFactory {
	
	/** ロガー */
	private static final Log log = LogFactory.getLog(ContainerFactory.class);
	
	/** コンテナキャッシュ */
	private static Map<String, IceryaContainer> cache = new java.util.HashMap<String, IceryaContainer>();
	
	/** コンテキストキャッシュ */
	private static Map<String, String> contexts = new java.util.HashMap<String, String>();
	
	/**
	 * 　DIコンテナを生成する。
	 * <br/>
	 * <br/>
	 * 　指定したDIコンテナが既に生成済みであれば、キャッシュからそのコンテナを取得
	 * する。まだ生成していなければ、新規に生成しキャッシュに保存しておく。
	 * 
	 * @param path DIコンテナパス
	 * @return DIコンテナ
	 * @throws ContainerException DIコンテナの生成に失敗した場合
	 */
	public synchronized static IceryaContainer create(String path) throws ContainerException {
		initialize(path);
		return cache.get(path);
	}
	
	private synchronized static void initialize(String path) throws ContainerException {
		if(cache.containsKey(path)) {
			// キャッシュされている
			if(log.isDebugEnabled()) {
				log.debug("contaier file [" + path +  "] is cached.");
			}
		}else {
			// コンテナを新規作成する
			if(log.isDebugEnabled()) {
				log.debug("container file [" + path + "] is not cached.");
			}
			try {
				IceryaContainer result = new IceryaContainer();
				XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(result);
				reader.parse(path);
				cache.put(path, result);
				contexts.put(result.getContext(), path);
			}catch(Exception e) {
				log.error("PATH[" + path + "] is illegal path.", e);
				throw new BeanDefinitionParseException("PATH[" + path + "] is illegal path.", e);
			}
		}
	}
	
	public synchronized static IceryaContainer getContainer(String context) throws ContainerException {
		return cache.get(contexts.get(context));
	}
	
	/**
	 * DIコンテナを生成する。
	 * <br/>
	 * <br/>
	 * 　キャッシュされない空のコンテナを生成する。キャッシュが必要であれば、利用側
	 * でキャッシュを行う。
	 * @return DIコンテナ
	 * @throws ContainerException DIコンテナの生成に失敗した場合
	 */
	public synchronized static IceryaContainer create() throws ContainerException {
		return new IceryaContainer();
	}
}
