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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.seasar.dbflute.DBDef;
import org.seasar.dbflute.QLog;
import org.seasar.dbflute.XLog;
import org.seasar.dbflute.bhv.core.supplement.SequenceCacheKeyGenerator;
import org.seasar.dbflute.jdbc.DataSourceHandler;
import org.seasar.dbflute.jdbc.StatementConfig;
import org.seasar.dbflute.jdbc.ValueType;
import org.seasar.dbflute.s2dao.valuetype.TnValueTypes;
import org.seasar.dbflute.twowaysql.DisplaySqlBuilder;

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

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    /** Log instance. */
    private static final Log _log = LogFactory.getLog(${glDBFluteConfig}.class);

#if ($database.isOutsideSqlPackageValid())
    /** The default package of outside SQL. The default value is '${database.outsideSqlPackage}'. */
    private static final String DEFAULT_OUTSIDE_SQL_PACKAGE = "${database.outsideSqlPackage}";
#else
    /** The default package of outside SQL. */
    private static final String DEFAULT_OUTSIDE_SQL_PACKAGE = null;
#end

#if ($database.isSqlLogRegistryValid())
    /** The default value of whether it uses SQL Log Registry. The default value is true. */
    private static final boolean DEFAULT_USE_SQL_LOG_REGISTRY = true;
#else
    /** The default value of whether it uses SQL Log Registry. The default value is false. */
    private static final boolean DEFAULT_USE_SQL_LOG_REGISTRY = false;
#end

    /** Singleton instance. */
    private static final ${glDBFluteConfig} _instance = new ${glDBFluteConfig}();

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    // -----------------------------------------------------
    //                                         Configuration
    //                                         -------------
	protected StatementConfig _defaultStatementConfig;
	protected boolean _queryLogLevelInfo;
	protected boolean _executeStatusLogLevelInfo;
	protected String _logDateFormat;
	protected String _logTimestampFormat;
    protected DataSourceHandler _dataSourceHandler;
    protected SequenceCacheKeyGenerator _sequenceCacheKeyGenerator;
    protected String _outsideSqlPackage = DEFAULT_OUTSIDE_SQL_PACKAGE;
	protected boolean _useSqlLogRegistry = DEFAULT_USE_SQL_LOG_REGISTRY;
	protected boolean _disableSelectIndex;
	protected boolean _internalDebug;

    // -----------------------------------------------------
    //                                   Database Dependency
    //                                   -------------------
#if ($database.isAvailableDatabaseDependency())
#if ($database.isDatabasePostgreSQL())
    protected org.seasar.dbflute.dbway.WayOfPostgreSQL.OperandOfLikeSearch _fullTextSearchOperand
            = org.seasar.dbflute.dbway.WayOfPostgreSQL.OperandOfLikeSearch.FULL_TEXT_SEARCH;
#end
#end

    // -----------------------------------------------------
    //                                                  Lock
    //                                                  ----
	protected boolean _locked = false; // at first unlocked

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    /**
     * Constructor.
     */
    private ${glDBFluteConfig}() {
	    if (isCurrentDBDef(DBDef.Oracle)) {
            // Date formatting has Two points:
            //   o The DATE type of Oracle has seconds.  
            //   o It uses a date literal of Oracle.
            String dateFormat = "yyyy-MM-dd HH:mm:ss";
            _logDateFormat = "timestamp $df:{" + dateFormat + "}";
            String timestampFormat = DisplaySqlBuilder.DEFAULT_TIMESTAMP_FORMAT;
            _logTimestampFormat = "timestamp $df:{" + timestampFormat + "}";

            // It should treat java.util.Date as time-stamp,
            // because the DATE type of Oracle has seconds.
            registerBasicValueType(java.util.Date.class, TnValueTypes.UTILDATE_AS_TIMESTAMP); // override
	    }
    }

    // ===================================================================================
    //                                                                           Singleton
    //                                                                           =========
    /**
     * Get singleton instance.
     * @return Singleton instance. (NotNull)
     */
    public static ${glDBFluteConfig} getInstance() {
        return _instance;
    }

    // ===================================================================================
    //                                                            Default Statement Config
    //                                                            ========================
    public StatementConfig getDefaultStatementConfig() {
        return _defaultStatementConfig;
    }
	
    public void setDefaultStatementConfig(StatementConfig defaultStatementConfig) {
	    assertNotLocked();
	    if (_log.isInfoEnabled()) {
		    _log.info("...Setting defaultStatementConfig: " + defaultStatementConfig);
		}
        _defaultStatementConfig = defaultStatementConfig;
    }
	
    // ===================================================================================
    //                                                                Query Log Level Info
    //                                                                ====================
	public void setQueryLogLevelInfo(boolean queryLogLevelInfo) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting queryLogLevelInfo: " + queryLogLevelInfo);
		}
		QLog.unlock();
		QLog.setQueryLogLevelInfo(queryLogLevelInfo);
		QLog.lock();
	}
	
    // ===================================================================================
    //                                                       Execute Status Log Level Info
    //                                                       =============================
	public void setExecuteStatusLogLevelInfo(boolean executeStatusLogLevelInfo) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting executeStatusLogLevelInfo: " + executeStatusLogLevelInfo);
		}
		XLog.unlock();
        XLog.setExecuteStatusLogLevelInfo(executeStatusLogLevelInfo);
		XLog.lock();
	}

    // ===================================================================================
    //                                                                          Log Format
    //                                                                          ==========
	public String getLogDateFormat() {
	    return _logDateFormat;
	}
	
	public void setLogDateFormat(String logDateFormat) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting logDateFormat: " + logDateFormat);
		}
	    _logDateFormat = logDateFormat;
	}

	public String getLogTimestampFormat() {
	    return _logTimestampFormat;
	}
	
	public void setLogTimestampFormat(String logTimestampFormat) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting logTimestampFormat: " + logTimestampFormat);
		}
	    _logTimestampFormat = logTimestampFormat;
	}

    // [DBFlute-0.9.0]
    // ===================================================================================
    //                                                                  DataSource Handler
    //                                                                  ==================
    /**
     * @return The handler of data source. (Nullable)
     */
	public DataSourceHandler getDataSourceHandler() {
	    return _dataSourceHandler;
	}

    /**
     * @param dataSourceHandler The handler of data source. (Nullable)
     */
	public void setDataSourceHandler(DataSourceHandler dataSourceHandler) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting dataSourceHandler: " + dataSourceHandler);
		}
	    _dataSourceHandler = dataSourceHandler;
	}

    // [DBFlute-0.9.6.4]
    // ===================================================================================
    //                                                                      Sequence Cache
    //                                                                      ==============
    /**
     * @return The key generator of sequence cache. (Nullable)
     */
	public SequenceCacheKeyGenerator getSequenceCacheKeyGenerator() {
	    return _sequenceCacheKeyGenerator;
	}

    /**
     * @param sequenceCacheKeyGenerator The key generator of sequence cache. (Nullable)
     */
	public void setSequenceCacheKeyGenerator(SequenceCacheKeyGenerator sequenceCacheKeyGenerator) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting sequenceCacheKeyGenerator: " + sequenceCacheKeyGenerator);
		}
	    _sequenceCacheKeyGenerator = sequenceCacheKeyGenerator;
	}

    // ===================================================================================
    //                                                                  OutsideSql Package
    //                                                                  ==================
    /**
     * @return The package of outside SQL. (Nullable)
     */
	public String getOutsideSqlPackage() {
	    return _outsideSqlPackage;
	}

    /**
     * @param outsideSqlPackage The package of outside SQL. (Nullable)
     */
	public void setOutsideSqlPackage(String outsideSqlPackage) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting outsideSqlPackage: " + outsideSqlPackage);
		}
	    _outsideSqlPackage = outsideSqlPackage;
	}

    // [DBFlute-0.8.2]
    // ===================================================================================
    //                                                                    SQL Log Registry
    //                                                                    ================
	public boolean isUseSqlLogRegistry() {
	    return _useSqlLogRegistry;
	}
	
	public void setUseSqlLogRegistry(boolean useSqlLogRegistry) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting useSqlLogRegistry: " + useSqlLogRegistry);
		}
	    _useSqlLogRegistry = useSqlLogRegistry;
	}

    // [DBFlute-0.9.0]
    // ===================================================================================
    //                                                                        Select Index
    //                                                                        ============
	public boolean isDisableSelectIndex() {
	    return _disableSelectIndex;
	}

	public void setDisableSelectIndex(boolean disableSelectIndex) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting disableSelectIndex: " + disableSelectIndex);
		}
	    _disableSelectIndex = disableSelectIndex;
	}
	
    // ===================================================================================
    //                                                                 Database Dependency
    //                                                                 ===================
#if ($database.isAvailableDatabaseDependency())
#if ($database.isDatabasePostgreSQL())
    // -----------------------------------------------------
    //                              Full-Text Search Operand
    //                              ------------------------
    public org.seasar.dbflute.dbway.WayOfPostgreSQL.OperandOfLikeSearch getFullTextSearchOperand() {
        return _fullTextSearchOperand;
    }

    public void useDefaultFullTextSearchOperand() {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Using fullTextSearchOperand: Default");
		}
        _fullTextSearchOperand = org.seasar.dbflute.dbway.WayOfPostgreSQL.OperandOfLikeSearch.FULL_TEXT_SEARCH; 
    }

    public void useOldFullTextSearchOperand() {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Using fullTextSearchOperand: Old");
		}
        _fullTextSearchOperand = org.seasar.dbflute.dbway.WayOfPostgreSQL.OperandOfLikeSearch.OLD_FULL_TEXT_SEARCH; 
    }
#end
#end

    // ===================================================================================
    //                                                                      Internal Debug
    //                                                                      ==============
	public boolean isInternalDebug() {
	    return _internalDebug;
	}
	
	public void setInternalDebug(boolean internalDebug) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Setting internalDebug: " + internalDebug);
		}
	    _internalDebug = internalDebug;
	}

    // ===================================================================================
    //                                                                          Value Type
    //                                                                          ==========
    /**
     * Register the basic value type. <br />
     * This setting is shared by other DBFlute projects in the same class loader. 
     * @param keyType The type as key. (NotNull)
     * @param valueType The basic value type. (NotNull)
     */
	public void registerBasicValueType(Class<?> keyType, ValueType valueType) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Registering basic valueType: keyType=" + keyType + " valueType=" + valueType);
		}
	    TnValueTypes.registerBasicValueType(keyType, valueType);
	}

	public void removeBasicValueType(Class<?> keyType) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Removing basic valueType: keyType=" + keyType);
		}
	    TnValueTypes.removeBasicValueType(keyType);
	}

    /**
     * Register the plug-in value type. <br />
     * This setting is shared by other DBFlute projects in the same class loader.
     * @param keyName The name as key. (NotNull)
     * @param valueType The plug-in value type. (NotNull)
     */
	public void registerPluginValueType(String keyName, ValueType valueType) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Registering plug-in valueType: keyName=" + keyName + " valueType=" + valueType);
		}
	    TnValueTypes.registerPluginValueType(keyName, valueType);
	}

	public void removePluginValueType(String keyName) {
	    assertNotLocked();
		if (_log.isInfoEnabled()) {
		    _log.info("...Removing plug-in valueType: keyName=" + keyName);
		}
	    TnValueTypes.removePluginValueType(keyName);
	}

    // ===================================================================================
    //                                                                  Configuration Lock
    //                                                                  ==================
	public boolean isLocked() {
	    return _locked;
	}
	
	public void lock() {
		if (_log.isInfoEnabled()) {
		    _log.info("...Locking the configuration of DBFlute!");
		}
	    _locked = true;
	}
	
	public void unlock() {
		if (_log.isInfoEnabled()) {
		    _log.info("...Unlocking the configuration of DBFlute!");
		}
	    _locked = false;
	}
	
	protected void assertNotLocked() {
	    if (!isLocked()) {
		    return;
		}
		String msg = "The configuration of DBFlute is locked! Don't access at this timing!";
		throw new IllegalStateException(msg);
	}

    // ===================================================================================
    //                                                                       Assist Helper
    //                                                                       =============
    protected boolean isCurrentDBDef(DBDef currentDBDef) {
	    return ${glDBCurrent}.getInstance().isCurrentDBDef(currentDBDef);
    }
}
