${database.allClassCopyright}package ${myDBMetaPackageName};
#set ($myClassName = "${myDBMetaClassName}")

import java.util.List;
import java.util.Map;

import org.seasar.dbflute.DBDef;
import org.seasar.dbflute.Entity;
import org.seasar.dbflute.dbmeta.AbstractDBMeta;
import org.seasar.dbflute.dbmeta.info.*;
import org.seasar.dbflute.dbmeta.name.*;
import org.seasar.dbflute.helper.StringKeyMap;
import ${glPackageBaseCommon}.*;
import ${myExtendedEntityPackageName}.*;

/**
 * The DB meta of ${table.name}. (Singleton)
 * @author ${database.classAuthor}
 */
public class ${myClassName} extends AbstractDBMeta {

    // ===================================================================================
    //                                                                           Singleton
    //                                                                           =========
    private static final ${myClassName} _instance = new ${myClassName}();
    private ${myClassName}() {}
    public static ${myClassName} getInstance() { return _instance; }

    // ===================================================================================
    //                                                                       Current DBDef
    //                                                                       =============
    public DBDef getCurrentDBDef() { return ${glDBCurrent}.getInstance().currentDBDef(); }

    // ===================================================================================
    //                                                                          Table Info
    //                                                                          ==========
    protected final String _tableDbName = "${table.name}";
    protected final String _tablePropertyName = "${table.javaBeansRulePropertyName}";
    protected final TableSqlName _tableSqlName = new TableSqlName("${table.tableSqlName}", _tableDbName);
    { _tableSqlName.xacceptFilter(${glDBFluteConfig}.getInstance().getTableSqlNameFilter()); }
    public String getTableDbName() { return _tableDbName; }
    public String getTablePropertyName() { return _tablePropertyName; }
    public TableSqlName getTableSqlName() { return _tableSqlName; }
#if ($table.hasAlias())
    protected final String _tableAlias = "$table.alias";
    public String getTableAlias() { return _tableAlias; }
#end
#if ($table.isCommentForDBMetaValid())
    protected final String _tableComment = "$table.commentForDBMeta";
    public String getTableComment() { return _tableComment; }
#end

    // ===================================================================================
    //                                                                         Column Info
    //                                                                         ===========
#foreach ($col in $table.columns)
    protected final ColumnInfo _column${col.javaBeansRulePropertyNameInitCap} = cci("${col.name}", "${col.columnSqlName}", ${col.synonymSettingExpression}, ${col.aliasSettingExpression}, ${col.isNotNull()}, "${col.javaBeansRulePropertyName}", ${col.javaNativeTypeLiteral}, ${col.isPrimaryKey()}, ${col.isAutoIncrement()}, "${col.dbTypeExpression}", ${col.columnSizeSettingExpression}, ${col.columnDecimalDigitsSettingExpression}, ${col.isCommonColumn()}, ${col.optimistickLockExpression}, ${col.commentForDBMetaSettingExpression}, ${col.foreignPropertyNameCommaStringLiteralExpression}, ${col.referrerPropertyNameCommaStringLiteralExpression}, ${col.classificationMetaSettingExpression});
#end

#foreach ($col in $table.columns)
    public ColumnInfo column${col.javaBeansRulePropertyNameInitCap}() { return _column${col.javaBeansRulePropertyNameInitCap}; }
#end

    protected List<ColumnInfo> ccil() {
        List<ColumnInfo> ls = newArrayList();
#foreach ($col in $table.columns)
        ls.add(column${col.javaBeansRulePropertyNameInitCap}());
#end
        return ls;
    }

    { initializeInformationResource(); }

    // ===================================================================================
    //                                                                         Unique Info
    //                                                                         ===========
    // -----------------------------------------------------
    //                                       Primary Element
    //                                       ---------------
#if ($table.hasPrimaryKey())
#if ($table.hasSinglePrimaryKey())
    public UniqueInfo getPrimaryUniqueInfo() { return cpui(column${table.primaryKeyAsOne.javaBeansRulePropertyNameInitCap}()); }
#else
    public UniqueInfo getPrimaryUniqueInfo() {
        List<ColumnInfo> ls = newArrayList();
#foreach ($col in $table.primaryKey)
        ls.add(column${col.javaBeansRulePropertyNameInitCap}());
#end
        return cpui(ls);
    }
#end
#else
    public UniqueInfo getPrimaryUniqueInfo() {
        throw new UnsupportedOperationException("The table does not have primary key: " + getTableDbName());
    }
#end
    public boolean hasPrimaryKey() { return ${table.hasPrimaryKey()}; }
    public boolean hasCompoundPrimaryKey() { return ${table.hasCompoundPrimaryKey()}; }

    // ===================================================================================
    //                                                                       Relation Info
    //                                                                       =============
    // -----------------------------------------------------
    //                                      Foreign Property
    //                                      ----------------
#foreach ($fk in $table.foreignKeys)
    public ForeignInfo foreign${fk.foreignJavaBeansRulePropertyNameInitCap}() {
#if ($fk.isSimpleKeyFK())
#set ($col = $fk.localColumnAsOne)
#set ($yourCol = ${fk.getForeignColumnByLocalColumn(${col})})
        Map<ColumnInfo, ColumnInfo> map = newLinkedHashMap(column${col.javaBeansRulePropertyNameInitCap}(), ${fk.foreignTableDBMetaClassName}.getInstance().column${yourCol.javaBeansRulePropertyNameInitCap}());
#else
        Map<ColumnInfo, ColumnInfo> map = newLinkedHashMap();
#foreach ($col in $fk.localColumnList)
#set ($yourCol = ${fk.getForeignColumnByLocalColumn(${col})})
        map.put(column${col.javaBeansRulePropertyNameInitCap}(), ${fk.foreignTableDBMetaClassName}.getInstance().column${yourCol.javaBeansRulePropertyNameInitCap}());
#end
#end
        return cfi("${fk.foreignJavaBeansRulePropertyName}", this, ${fk.foreignTableDBMetaClassName}.getInstance(), map, ${table.resolveForeignIndex($fk)}, ${fk.isOneToOne()}, ${fk.isBizOneToOne()});
    }
#end
#foreach ($referrer in $table.referrerAsOneList)
#set ($genericsColumnInfoMap = "ColumnInfo, ColumnInfo")
    public ForeignInfo foreign${referrer.referrerJavaBeansRulePropertyNameAsOneInitCap}() {
#if ($referrer.isSimpleKeyFK())
#set ($col = $referrer.foreignColumnAsOne)
#set ($yourCol = ${referrer.getLocalColumnByForeignColumn(${col})})
        Map<ColumnInfo, ColumnInfo> map = newLinkedHashMap(column${col.javaBeansRulePropertyNameInitCap}(), ${referrer.referrerTableDBMetaClassName}.getInstance().column${yourCol.javaBeansRulePropertyNameInitCap}());
#else
        Map<ColumnInfo, ColumnInfo> map = newLinkedHashMap();
#foreach ($col in $referrer.foreignColumnList)
#set ($yourCol = ${referrer.getLocalColumnByForeignColumn(${col})})
        map.put(column${col.javaBeansRulePropertyNameInitCap}(), ${referrer.referrerTableDBMetaClassName}.getInstance().column${yourCol.javaBeansRulePropertyNameInitCap}());
#end
#end
        return cfi("${referrer.referrerJavaBeansRulePropertyNameAsOne}", this, ${referrer.referrerTableDBMetaClassName}.getInstance(), map, ${table.resolveReferrerIndexAsOne($referrer)}, ${referrer.isOneToOne()}, ${referrer.isBizOneToOne()});
    }
#end

    // -----------------------------------------------------
    //                                     Referrer Property
    //                                     -----------------
#foreach ($referrer in $table.referrerAsManyList)
    public ReferrerInfo referrer${referrer.referrerJavaBeansRulePropertyNameInitCap}() {
#if ($referrer.isSimpleKeyFK())
#set ($col = $referrer.foreignColumnAsOne)
        Map<ColumnInfo, ColumnInfo> map = newLinkedHashMap(column${col.javaBeansRulePropertyNameInitCap}(), ${referrer.referrerTableDBMetaClassName}.getInstance().column${referrer.getLocalColumnByForeignColumn(${col}).javaBeansRulePropertyNameInitCap}());
#else
        Map<ColumnInfo, ColumnInfo> map = newLinkedHashMap();
#foreach ($col in $referrer.foreignColumnList)
        map.put(column${col.javaBeansRulePropertyNameInitCap}(), ${referrer.referrerTableDBMetaClassName}.getInstance().column${referrer.getLocalColumnByForeignColumn(${col}).javaBeansRulePropertyNameInitCap}());
#end
#end
        return cri("${referrer.referrerJavaBeansRulePropertyName}", this, ${referrer.referrerTableDBMetaClassName}.getInstance(), map, ${referrer.isOneToOne()});
    }
#end
#if ($database.isMakeFlatExpansion())

    // -----------------------------------------------------
    //                                        Relation Trace
    //                                        --------------
    public ${table.relationTraceClassName}RelationTrace createRelationTrace(RelationTraceFixHandler relationTraceFixHandler) {
        return new ${table.relationTraceClassName}RelationTrace(relationTraceFixHandler);
    }

    public ${table.relationTraceClassName}RelationTrace createRelationTrace(List<RelationInfo> relationList, List<AbstractRelationTrace> relationTraceList) {
        return new ${table.relationTraceClassName}RelationTrace(relationList, relationTraceList);
    }

    public static class ${table.relationTraceClassName}RelationTrace extends AbstractRelationTrace {

        /**
         * Constructor for first step.
         * @param relationTraceFixHandler The handler of fixed relation trace. (Nullable)
         */
        public ${table.relationTraceClassName}RelationTrace(RelationTraceFixHandler relationTraceFixHandler) {
            super(relationTraceFixHandler);
        }

        /**
         * Constructor for relation step.
         * @param relationList The list of relation. (NotNull)
         * @param relationTraceList The list of relation trace. (NotNull)
         */
        public ${table.relationTraceClassName}RelationTrace(List<RelationInfo> relationList, List<AbstractRelationTrace> relationTraceList) {
            super(relationList, relationTraceList);
        }

#foreach ($foreignKeys in $table.foreignKeys)
        public ${foreignKeys.foreignTableDBMetaClassName}.${foreignKeys.foreignTable.relationTraceClassName}RelationTrace foreign${foreignKeys.foreignJavaBeansRulePropertyNameInitCap}() {
            _relationList.add(${myDBMetaClassName}.getInstance().foreign${foreignKeys.foreignJavaBeansRulePropertyNameInitCap}());
            return ${foreignKeys.foreignTableDBMetaClassName}.getInstance().createRelationTrace(_relationList, _relationTraceList);
        }
#end
#foreach ($referrer in $table.referrerAsOneList)
        public ${referrer.referrerTableDBMetaClassName}.${referrer.table.relationTraceClassName}RelationTrace foreign${referrer.referrerJavaBeansRulePropertyNameAsOneInitCap}() {
            _relationList.add(${myDBMetaClassName}.getInstance().foreign${referrer.referrerJavaBeansRulePropertyNameAsOneInitCap}());
            return ${referrer.referrerTableDBMetaClassName}.getInstance().createRelationTrace(_relationList, _relationTraceList);
        }
#end
#foreach ($referrer in $table.referrerAsManyList)
        public ${referrer.referrerTableDBMetaClassName}.${referrer.table.relationTraceClassName}RelationTrace referrer${referrer.referrerJavaBeansRulePropertyNameInitCap}() {
            _relationList.add(${myDBMetaClassName}.getInstance().referrer${referrer.referrerJavaBeansRulePropertyNameInitCap}());
            return ${referrer.referrerTableDBMetaClassName}.getInstance().createRelationTrace(_relationList, _relationTraceList);
        }
#end

#foreach ($col in $table.columns)
        public RelationTrace column${col.javaBeansRulePropertyNameInitCap}() { return fixTrace(_relationList, ${myDBMetaClassName}.getInstance().column${col.javaBeansRulePropertyNameInitCap}()); }
#end
    }
#end

    // ===================================================================================
    //                                                                        Various Info
    //                                                                        ============
#if ($table.isUseIdentity())
    public boolean hasIdentity() { return true; }
#end
#if ($table.isUseSequence())
    public boolean hasSequence() { return true; }
    public String getSequenceName() { return "${table.sequenceSqlName}"; }
    public Integer getSequenceIncrementSize() { return ${table.sequenceIncrementSizeExpression}; }
    public Integer getSequenceCacheSize() { return ${table.sequenceCacheSizeExpression}; }
#end
#if ($table.isUseVersionNo())
    public boolean hasVersionNo() { return true; }
    public ColumnInfo getVersionNoColumnInfo() { return _column${table.versionNoJavaName}; }
#end
#if ($table.isUseUpdateDate())
    public boolean hasUpdateDate() { return true; }
    public ColumnInfo getUpdateDateColumnInfo() { return _column${table.updateDateJavaName}; }
#end
#if ($table.hasAllCommonColumn())
    public boolean hasCommonColumn() { return true; }
#end

    // ===================================================================================
    //                                                                           Type Name
    //                                                                           =========
    public String getEntityTypeName() { return "${myExtendedEntityPackageName}.${myExtendedObjectClassName}"; }
#if ($isExistConditionBean)
    public String getConditionBeanTypeName() { return "${glPackageBaseCB}.${myConditionBeanClassName}"; }
#else
    public String getConditionBeanTypeName() { return null; }
#end
#if ($isExistDao)
    public String getDaoTypeName() { return "${myExtendedDaoPackageName}.${myExtendedDaoClassName}"; }
#else
    public String getDaoTypeName() { return null; }
#end
#if ($isExistBehavior)
    public String getBehaviorTypeName() { return "${myExtendedBhvPackageName}.${myExtendedBhvClassName}"; }
#else
    public String getBehaviorTypeName() { return null; }
#end

    // ===================================================================================
    //                                                                         Object Type
    //                                                                         ===========
    public Class<${myExtendedObjectClassName}> getEntityType() { return ${myExtendedObjectClassName}.class; }

    // ===================================================================================
    //                                                                     Object Instance
    //                                                                     ===============
    public Entity newEntity() { return newMyEntity(); }
    public ${myExtendedObjectClassName} newMyEntity() { return new ${myExtendedObjectClassName}(); }

    // ===================================================================================
    //                                                                     Entity Handling
    //                                                                     ===============  
    public void acceptPrimaryKeyMap(Entity e, Map<String, ? extends Object> m)
    { doAcceptPrimaryKeyMap((${myExtendedObjectClassName})e, m, _epsMap); }
    public Map<String, Object> extractPrimaryKeyMap(Entity e) { return doExtractPrimaryKeyMap(e); }
    public Map<String, Object> extractAllColumnMap(Entity e) { return doExtractAllColumnMap(e); }

    // ===================================================================================
    //                                                               Entity Property Setup
    //                                                               =====================
    // It's very INTERNAL!
    protected final Map<String, Eps<${myExtendedObjectClassName}>> _epsMap = StringKeyMap.createAsFlexibleConcurrent();
    {
#foreach ($col in $table.columns)
        setupEps(_epsMap, new Eps${col.javaName}(), column${col.javaBeansRulePropertyNameInitCap}());
#end
    }

    public boolean hasEntityPropertySetupper(String propertyName) { return _epsMap.containsKey(propertyName); }
    public void setupEntityProperty(String propertyName, Object entity, Object value)
    { findEps(_epsMap, propertyName).setup((${myExtendedObjectClassName})entity, value); }

#foreach ($col in $table.columns)
#set ($setupperClassName = "Eps${col.javaName}")
#if ($col.isCheckSelectedClassification() || $col.isForceClassificationSetting())
    public class ${setupperClassName} implements Eps<${myExtendedObjectClassName}>
    { public void setup(${myExtendedObjectClassName} e, Object v) {
        ColumnInfo col = column${col.javaBeansRulePropertyNameInitCap}();
#if ($col.isCheckSelectedClassification())
        ccls(col, v);
#end
        e.set${col.javaName}As${col.classificationName}((${glCDef}.${col.classificationName})gcls(col, v));
    } }
#else
## /- - - - - - - - - - - - - - - - - - - -
## for different type between relation
## (Integer, Long and BigDecimal are prior)
## - - - - - - - - - -/
#if ($col.isJavaNativeNumberObject())
    public class ${setupperClassName} implements Eps<${myExtendedObjectClassName}>
#if ($col.isJavaNativeInteger())
    { public void setup(${myExtendedObjectClassName} e, Object v) { e.set${col.javaName}(cti(v)); } }
#elseif ($col.isJavaNativeLong())
    { public void setup(${myExtendedObjectClassName} e, Object v) { e.set${col.javaName}(ctl(v)); } }
#elseif ($col.isJavaNativeBigDecimal())
    { public void setup(${myExtendedObjectClassName} e, Object v) { e.set${col.javaName}(ctb(v)); } }
#else
    { public void setup(${myExtendedObjectClassName} e, Object v) { e.set${col.javaName}(ctn(v, ${col.javaNative}.class)); } }
#end
#else
    public static class ${setupperClassName} implements Eps<${myExtendedObjectClassName}>
#if ($col.isJavaNativeUtilList())
    { @SuppressWarnings("unchecked")
    public void setup(${myExtendedObjectClassName} e, Object v) { e.set${col.javaName}((${col.javaNative})v); } }
#else
    { public void setup(${myExtendedObjectClassName} e, Object v) { e.set${col.javaName}((${col.javaNative})v); } }
#end
#end
#end
#end
}
