// @formatter:off
package %s;

import hope.common.spring.data.persistence.spring.HopeJdbcRepository;
import hope.common.spring.data.persistence.converter.HopeListConverters;
import hope.common.spring.data.persistence.config.HopeAbstractJdbcConfiguration;
import hope.common.spring.data.persistence.config.ColumnTypeMapper;

import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.data.jdbc.autoconfigure.DataJdbcRepositoriesAutoConfiguration;
import org.springframework.boot.jdbc.autoconfigure.JdbcProperties;
import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;
import org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizers;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.env.Environment;
import org.springframework.data.jdbc.core.dialect.DialectResolver;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.support.JdbcTransactionManager;
import org.springframework.transaction.TransactionManager;
import javax.annotation.Generated;

@Generated("H.O.P.E. Infra Team")
@AutoConfigureBefore(
    value = {DataJdbcRepositoriesAutoConfiguration.class, JdbcTemplateAutoConfiguration.class})
@Configuration
@EnableJdbcRepositories(
    jdbcOperationsRef = "_HPP_%s_namedParameterJdbcTemplate",
    transactionManagerRef = "_HPP_%s_transactionManager",
    basePackages = { "%s" },
    repositoryBaseClass = HopeJdbcRepository.class)
public class %sJdbcConfiguration extends HopeAbstractJdbcConfiguration {

  public static final String NAMED_PARAMETER_JDBC_TEMPLATE = "_HPP_%s_namedParameterJdbcTemplate";
  public static final String JDBC_TEMPLATE = "_HPP_%s_jdbcTemplate";
  public static final String TRANSACTION_MANAGER = "_HPP_%s_transactionManager";
  public static final String MYBATIS_JDBC_TEMPLATE = "_HPP_%s_myBatisJdbcTemplate";

  %s
  @Autowired
  protected DataSource dataSource;

  @Autowired protected Environment environment;

  @Autowired protected JdbcProperties properties;

  %s
  // is Primary
  @Bean
  public %sPersistenceContext persistenceContext() {
    return new %sPersistenceContext();
  }

  %s
  // is Primary
  @Bean(name = { %s })
  public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
    return new NamedParameterJdbcTemplate(jdbcTemplate());
  }

  %s
  // is Primary
  @Bean(name = { %s })
  public JdbcTemplate jdbcTemplate() {

    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    JdbcProperties.Template template = properties.getTemplate();
    jdbcTemplate.setFetchSize(template.getFetchSize());
    jdbcTemplate.setMaxRows(template.getMaxRows());
    if (template.getQueryTimeout() != null) {
      jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
    }

    return jdbcTemplate;
  }

  %s
  // is Primary
  @Bean(name = { %s })
  public Dialect dialect() {
    return DialectResolver.getDialect(jdbcTemplate());
  }

  %s
  // is Primary
  @Bean(name = { %s })
  public DataSourceTransactionManager transactionManager(
      ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {

    final DataSourceTransactionManager transactionManager =
        createTransactionManager(environment, dataSource);
    transactionManagerCustomizers.ifAvailable(
        (customizers) -> customizers.customize((TransactionManager)transactionManager));
    return transactionManager;
  }

  private DataSourceTransactionManager createTransactionManager(
      final Environment environment, final DataSource dataSource) {
    return environment.getProperty(
            "spring.dao.exceptiontranslation.enabled", Boolean.class, Boolean.TRUE)
        ? new JdbcTransactionManager(dataSource)
        : new DataSourceTransactionManager(dataSource);
  }

  %s
  // is Primary
  // Mybatis dynamic SQL is used for complex analyst SQL
  @ConditionalOnClass(
      name = "org.mybatis.dynamic.sql.util.spring.NamedParameterJdbcTemplateExtensions")
  @Bean(name = { %s })
  public org.mybatis.dynamic.sql.util.spring.NamedParameterJdbcTemplateExtensions
      myBatisJdbcTemplate() {
    return new org.mybatis.dynamic.sql.util.spring.NamedParameterJdbcTemplateExtensions(
        namedParameterJdbcTemplate());
  }

  @Override
  protected List<?> userConverters() {
    final List<Converter> res  = new ArrayList<>();
    final List<Converter> _exists = HopeListConverters.getConvertersToRegister();
    res.addAll(_exists);
    final List<Converter> _custom = %s.getConvertersToRegister();
    res.addAll(_custom);
    return res;
  }

  //Those for the customized DB table column type mapper
  public interface %sColumnTypeMapper extends ColumnTypeMapper {
      %sColumnTypeMapper DEFAULT =
          new %sColumnTypeMapper() {
            @Override
            public Class<?> getColumnType(
                RelationalPersistentProperty property) {
              return %sColumnTypeMapper.super.getColumnType(property);
            }
          };
  }
  @Autowired(required = false)
  protected %sColumnTypeMapper _mapper  = %sColumnTypeMapper.DEFAULT;

  @Override
  protected ColumnTypeMapper columnTypeMapper() {
      return _mapper;
  }
}
