package jp.sourceforge.glad.org.seasar.framework.model.impl;

import java.util.ArrayList;
import java.util.List;

import jp.sourceforge.glad.org.seasar.framework.model.ModelFactory;

import org.aopalliance.intercept.MethodInterceptor;
import org.seasar.framework.aop.Pointcut;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.AspectDefFactory;
import org.seasar.framework.container.impl.ArgDefImpl;
import org.seasar.framework.container.impl.ComponentDefImpl;
import org.seasar.framework.container.impl.S2ContainerImpl;

/**
 * @author GLAD!!
 */
public class ModelFactoryImpl implements ModelFactory {

    S2Container container;
    List<Aspect> aspects = new ArrayList<Aspect>();

    public void setContainer(final S2Container container) {
        this.container = container;
    }

    public void addAspect(final MethodInterceptor interceptor) {
        addAspect(null, interceptor);
    }

    public void addAspect(
            final String pointcut, final MethodInterceptor interceptor) {
        aspects.add(new Aspect(pointcut, interceptor));
    }

    @SuppressWarnings("unchecked")
    public <T> T create(final Class<T> clazz, final Object... args) {
        // 実装は暫定。
        final S2Container c = new S2ContainerImpl();
        c.include(container);
        final ComponentDefImpl cd = new ComponentDefImpl(clazz);
        for (final Object arg : args) {
            cd.addArgDef(new ArgDefImpl(arg));
        }
        for (final Aspect aspect : aspects) {
            final Pointcut pointcut;
            if (aspect.pointcut == null) {
                pointcut = AspectDefFactory.createPointcut(clazz);
            } else {
                pointcut = AspectDefFactory.createPointcut(aspect.pointcut);
            }
            cd.addAspectDef(AspectDefFactory
                    .createAspectDef(aspect.interceptor, pointcut));
        }
        c.register(cd);
        return (T) c.getComponent(clazz);
    }

    public static class Aspect {
        public final String pointcut;
        public final MethodInterceptor interceptor;
        public Aspect(final String pointcut,
                final MethodInterceptor interceptor) {
            this.pointcut = pointcut;
            this.interceptor = interceptor;
        }
    }

}
