${database.allClassCopyright}package ${glPackageBaseCommon};

import javax.sql.DataSource;

import org.slim3.container.S3Container;
import org.slim3.container.S3ContainerFactory;
import org.seasar.dbflute.BehaviorSelector;
import org.seasar.dbflute.bhv.BehaviorReadable;
import org.seasar.dbflute.bhv.core.BehaviorCommandInvoker;
import org.seasar.dbflute.bhv.core.CommonColumnAutoSetupper;
import org.seasar.dbflute.bhv.core.InvokerAssistant;
import ${glPackageExtendedBhv}.*;

/**
 * @author ${database.classAuthor}
 */
public class ${glDBFluteModule} {

    protected DataSource dataSource;

    public DBFluteModule(DataSource dataSource) {
        if (dataSource == null) {
            String msg = "The argument 'dataSource' should not be null!";
            throw new IllegalArgumentException(msg);
        }
        this.dataSource = dataSource;
    }

    public void configure() {
        new ${glDBFluteInitializer}(); // Initialize!
        
        // The components of DBFlute Runtime.
        ${glImplementedBehaviorSelector} behaviorSelector = new ${glImplementedBehaviorSelector}();
        behaviorSelector.setContainer(S3ContainerFactory.getInstance().getContainer());
        BehaviorCommandInvoker behaviorCommandInvoker = new BehaviorCommandInvoker();
        ${glImplementedInvokerAssistant} invokerAssistant = createImplementedInvokerAssistant(behaviorCommandInvoker);
        behaviorCommandInvoker.setInvokerAssistant(invokerAssistant);
        ${glImplementedCommonColumnAutoSetupper} commonColumnAutoSetupper = createImplementedCommonColumnAutoSetupper();
        
        bind(BehaviorSelector.class).toInstance(behaviorSelector);
        bind(BehaviorCommandInvoker.class).toInstance(behaviorCommandInvoker);
        bind(InvokerAssistant.class).toInstance(invokerAssistant);
        bind(CommonColumnAutoSetupper.class).toInstance(commonColumnAutoSetupper);
        
        // The components of Behavior.
        BehaviorCommandInvoker ker = behaviorCommandInvoker;
        BehaviorSelector tor = behaviorSelector;
        CommonColumnAutoSetupper per = commonColumnAutoSetupper;
#foreach ($table in $database.tables)
        {
            ${table.extendedBehaviorClassName} bhv = new ${table.extendedBehaviorClassName}();
#if ($table.isWritable())
            bhv.setBehaviorCommandInvoker(ker); bhv.setBehaviorSelector(tor); bhv.setCommonColumnAutoSetupper(per);
#else
            bhv.setBehaviorCommandInvoker(ker); bhv.setBehaviorSelector(tor);
#end
            bind(${table.extendedBehaviorClassName}.class).toInstance(bhv);
        }
#end
    }

    protected ${glImplementedInvokerAssistant} createImplementedInvokerAssistant(BehaviorCommandInvoker behaviorCommandInvoker) {
#if ($database.hasExtendedImplementedInvokerAssistantClass())
        ${glImplementedInvokerAssistant} invokerAssistant = new ${database.extendedImplementedInvokerAssistantClass}();
#else
        ${glImplementedInvokerAssistant} invokerAssistant = new ${glImplementedInvokerAssistant}();
#end
        invokerAssistant.setBehaviorCommandInvoker(behaviorCommandInvoker);
        invokerAssistant.setDataSource(dataSource);
        return invokerAssistant;
    }

    protected ${glImplementedCommonColumnAutoSetupper} createImplementedCommonColumnAutoSetupper() {
#if ($database.hasExtendedImplementedCommonColumnAutoSetupperClass())
        return new ${database.extendedImplementedCommonColumnAutoSetupperClass}();
#else
        return new ${glImplementedCommonColumnAutoSetupper}();
#end
    }

    protected Setupper bind(Class<?> type) {
        final S3Container container = S3ContainerFactory.getInstance().getContainer();
        final String name;
        if (BehaviorReadable.class.isAssignableFrom(type)) {
            name = type.getSimpleName();
        } else {
            name = type.getName();
        }
        return new Setupper() {
            public void toInstance(Object instance) {
                container.bind(name, instance);
            }
        };
    }

    protected static interface Setupper {
        void toInstance(Object instance);
    }
}
