/*
 * Copyright 2008-2010 the T2 Project ant the Others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.t2framework.t2.adapter;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.t2framework.commons.bootstrap.CommonsInitializer;
import org.t2framework.commons.exception.NoSuchComponentException;
import org.t2framework.commons.meta.BeanDesc;
import org.t2framework.commons.meta.BeanDescFactory;
import org.t2framework.commons.util.Assertion;
import org.t2framework.commons.util.CollectionsUtil;
import org.t2framework.commons.util.Logger;
import org.t2framework.t2.handler.ExceptionHandler;
import org.t2framework.t2.handler.GlobalExceptionHandler;
import org.t2framework.t2.handler.impl.GlobalExceptionHandlerImpl;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

/**
 * 
 * {@.en An adapter class for Google Guice.}
 * 
 * <br />
 * 
 * {@.ja Guice???????????????.{@link Module}?{@link CommonsInitializer}
 * ?????????{@link Injector}??????.
 * 
 * @author shot
 * @author yone098
 * @see com.google.inject.Module
 * @see com.google.inject.Injector
 */
public class GuiceAdapter extends AbstractContainerAdapter<Injector> {

	protected static Logger logger = Logger.getLogger(GuiceAdapter.class);

	protected static Injector injector;

	protected Module[] modules;

	@Override
	public void init() {
		List<Module> moduleList = CollectionsUtil.newArrayList();
		for (Iterator<Module> iterator = CommonsInitializer
				.iterator(CommonsInitializer.load(Module.class)); iterator
				.hasNext();) {
			moduleList.add(iterator.next());
		}
		this.modules = moduleList.toArray(new Module[0]);
	}

	@Override
	public void init(String configPath) {
		init();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> BeanDesc<T> getBeanDesc(Class<? super T> key) {
		Assertion.notNull(key);
		setupInjector();
		if (hasComponent(key)) {
			return (BeanDesc<T>) BeanDescFactory.getBeanDesc(key);
		} else {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getComponent(Class<? super T> componentClass) {
		Assertion.notNull(componentClass);
		setupInjector();
		try {
			return (T) injector.getInstance(componentClass);
		} catch (Throwable e) {
			throw new NoSuchComponentException(componentClass);
		}
	}

	protected void setupInjector() {
		if (injector == null) {
			injector = Guice.createInjector(modules);
		}
	}

	@Override
	public <T> List<T> getComponents(Class<? super T> componentClass) {
		logger
				.debug("GuiceAdapter does not support getComponents(), so just return single component.");
		setupInjector();
		if (hasComponent(componentClass)) {
			List<T> ret = CollectionsUtil.newArrayList();
			ret.add((T) getComponent(componentClass));
			return ret;
		} else {
			return Collections.emptyList();
		}
	}

	@Override
	public <T> boolean hasComponent(Class<T> componentClass) {
		setupInjector();
		try {
			return injector.getInstance(componentClass) != null;
		} catch (Throwable t) {
			return false;
		}
	}

	@Override
	public <T> T injectDependency(T t) {
		setupInjector();
		injector.injectMembers(t);
		return t;
	}

	@Override
	public <T> void register(Class<? extends T> key) {
		Assertion.notNull(key);
		setupInjector();
		logger.debug("GuiceAdapter can not register a component:"
				+ key.getName());
	}

	@Override
	public <T> void register(T key) {
		Assertion.notNull(key);
		setupInjector();
		logger.debug("GuiceAdapter can not register a component:"
				+ key.getClass().getName());
	}

	@Override
	public Injector getContainer() {
		return injector;
	}

	@Override
	public List<ExceptionHandler<Throwable, Exception>> createExceptionHandlers() {
		setupInjector();
		logger
				.debug("GuiceAdapter does not support createrExceptionHandlers().");
		return CollectionsUtil.emptyList();
	}

	@Override
	public GlobalExceptionHandler createGlobalExceptionHandler() {
		setupInjector();
		if (hasComponent(GlobalExceptionHandler.class)) {
			return injector.getInstance(GlobalExceptionHandler.class);
		} else {
			return new GlobalExceptionHandlerImpl();
		}
	}

	@Override
	public void destroy() {
		injector = null;
	}

	/**
	 * {@.en {@link Injector} generated with this adaptor is returned.}
	 * 
	 * <br />
	 * 
	 * {@.ja ?Adapter?????.{@link Injector}??????
	 * 
	 * @return {@link Injector}
	 */
	public static Injector getSingletonGuiceInjector() {
		return injector;
	}

}