package enkan.component.doma2;

import enkan.component.ComponentLifecycle;
import enkan.component.DataSourceComponent;
import enkan.component.SystemComponent;
import enkan.exception.MisconfigurationException;
import org.seasar.doma.jdbc.Config;
import org.seasar.doma.jdbc.ConfigProvider;
import org.seasar.doma.jdbc.SqlFileRepository;

import javax.sql.DataSource;
import java.lang.reflect.Constructor;
import java.util.concurrent.ConcurrentHashMap;

import static enkan.util.ReflectionUtils.tryReflection;

/**
 * @author kawasima
 */
public class DomaProvider extends SystemComponent {
    private DataSource dataSource;
    private ConcurrentHashMap<String, Object> daoCache = new ConcurrentHashMap<>();

    /**
     * Gets the DAO.
     *
     * @param daoInterface a type of DAO
     * @param <T> a type of DAO
     * @return a DAO of the given class.
     */
    public <T> T getDao(Class<? extends T> daoInterface) {
        return (T) daoCache.computeIfAbsent(daoInterface.getName(), key ->
                tryReflection(() -> {
                    Class<? extends T> daoClass;
                    try {
                         daoClass = (Class<? extends T>) Class.forName(daoInterface.getName() + "Impl", true, daoInterface.getClassLoader());
                    } catch (ClassNotFoundException ex) {
                        throw new MisconfigurationException("doma2.DAO_IMPL_NOT_FOUND", daoInterface.getName(), ex);
                    }
                    Constructor<? extends T> daoConstructor = daoClass.getConstructor(DataSource.class);
                    return daoConstructor.newInstance(dataSource);
            }));
    }

    @Override
    protected ComponentLifecycle lifecycle() {
        return new ComponentLifecycle<DomaProvider>() {
            @Override
            public void start(DomaProvider component) {
                DataSourceComponent dataSourceComponent = getDependency(DataSourceComponent.class);
                component.dataSource = dataSourceComponent.getDataSource();
            }

            @Override
            public void stop(DomaProvider component) {
                component.dataSource = null;
                daoCache.values().stream()
                        .filter(ConfigProvider.class::isInstance)
                        .map(ConfigProvider.class::cast)
                        .map(ConfigProvider::getConfig)
                        .map(Config::getSqlFileRepository)
                        .forEach(SqlFileRepository::clearCache);
                daoCache.clear();
            }
        };
    }
}

@@ -328,16 +328,114 @@
 ository;
+%0Aimport org.seasar.doma.jdbc.dialect.Dialect;%0Aimport org.seasar.doma.jdbc.dialect.StandardDialect;
 %0A%0Aimport
@@ -584,29 +584,17 @@
 onUtils.
-tryReflection
+*
 ;%0A%0A/**%0A 
@@ -786,16 +786,79 @@
 Map%3C%3E();
+%0A    private Config defaultConfig;%0A    private Dialect dialect;
 %0A%0A    /*
@@ -1587,32 +1587,62 @@
               %7D%0A
+                    try %7B%0A    
                 
@@ -1746,24 +1746,28 @@
             
+    
 return daoCo
@@ -1797,24 +1797,282 @@
 ataSource);%0A
+                    %7D catch (NoSuchMethodException e) %7B%0A                        Constructor%3C? extends T%3E daoConstructor = daoClass.getConstructor(Config.class);%0A                        return daoConstructor.newInstance(defaultConfig);%0A                    %7D%0A%0A
             
@@ -2450,24 +2450,504 @@
 taSource();%0A
+                if (component.dialect == null) component.dialect = new StandardDialect();%0A                component.defaultConfig = new Config() %7B%0A                    @Override%0A                    public DataSource getDataSource() %7B%0A                        return component.dataSource;%0A                    %7D%0A%0A                    @Override%0A                    public Dialect getDialect() %7B%0A                        return component.dialect;%0A                    %7D%0A                %7D;%0A
             
@@ -3481,11 +3481,96 @@
 %7D;%0A    %7D
+%0A%0A    public void setDialect(Dialect dialect) %7B%0A        this.dialect = dialect;%0A    %7D
 %0A%7D%0A

Remove a constraint that DAO annotation must have a config property