${database.allClassCopyright}package ${glPackageBaseCB};
#set ($myClassName = "${myBaseConditionBeanClassName}")

import java.util.Map;

import org.seasar.dbflute.cbean.AbstractConditionBean;
import org.seasar.dbflute.cbean.ConditionBean;
import org.seasar.dbflute.cbean.ConditionQuery;
import org.seasar.dbflute.cbean.OrQuery;
import org.seasar.dbflute.cbean.SpecifyQuery;
import org.seasar.dbflute.cbean.SubQuery;
import org.seasar.dbflute.cbean.UnionQuery;
import org.seasar.dbflute.cbean.chelper.*;
import org.seasar.dbflute.cbean.sqlclause.SqlClause;
import org.seasar.dbflute.dbmeta.DBMetaProvider;
import org.seasar.dbflute.twowaysql.factory.SqlAnalyzerFactory;
import ${glPackageBaseCommon}.${glDBFluteConfig};
import ${glPackageBaseCommon}.${glDBMetaInstanceHandler};
import ${glPackageBaseCommon}.${glImplementedInvokerAssistant};
import ${glPackageBaseCommon}.${glImplementedSqlClauseCreator};
import ${glPackageCB}.*;
import ${glPackageCQ}.*;
#if ($table.hasForeignKeyOrReferrerAsOne())
import ${glPackageNss}.*;
#end

/**
 * The base condition-bean of ${table.name}.
 * @author ${database.classAuthor}
 */
public class ${myClassName} extends AbstractConditionBean {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    private final DBMetaProvider _dbmetaProvider = new ${glDBMetaInstanceHandler}();
    protected ${myConditionQueryClassName} _conditionQuery;

    // ===================================================================================
    //                                                                           SqlClause
    //                                                                           =========
    @Override
    protected SqlClause createSqlClause() {
        return new ${glImplementedSqlClauseCreator}().createSqlClause(this);
    }

    // ===================================================================================
    //                                                                     DBMeta Provider
    //                                                                     ===============
    @Override
    protected DBMetaProvider getDBMetaProvider() {
        return _dbmetaProvider;
    }

    // ===================================================================================
    //                                                                          Table Name
    //                                                                          ==========
    public String getTableDbName() {
        return "${table.name}";
    }

    // ===================================================================================
    //                                                                      PrimaryKey Map
    //                                                                      ==============
    public void acceptPrimaryKeyMap(Map<String, ? extends Object> primaryKeyMap) {
#if ($table.hasPrimaryKey())
        assertPrimaryKeyMap(primaryKeyMap);
#foreach ($col in $table.primaryKey)
        {
            Object obj = primaryKeyMap.get("${col.name}");
            if (obj instanceof ${col.javaNative}) {
                query().set${col.javaName}_Equal((${col.javaNative})obj);
            } else {
#if ($col.isJavaNativeStringObject())
                checkTypeString(obj, "${col.uncapitalisedJavaName}", "${col.javaNative}");
                query().set${col.javaName}_Equal((String)obj);
            }
        }
#else
#if ($col.isJavaNativeDateObject())
                query().set${col.javaName}_Equal(new ${col.javaNative}(parseDateStringAsMillis(obj, "${col.uncapitalisedJavaName}", "${col.javaNative}")));
            }
        }
#else
#if (${col.isJavaNativeBinaryObject()})
                query().set${col.javaName}_Equal(null);// Binary as String is out of target.
            }
        }
#else
#if (${col.isJavaNativeUUIDObject()})
                query().set${col.javaName}_Equal(java.util.UUID.fromString((String)obj));
            }
        }
#else
                query().set${col.javaName}_Equal(new ${col.javaNative}((String)obj));
            }
        }
#end
#end
#end
#end
#end
#else

        String msg = "This table has no primary-keys: " + getTableDbName();
        throw new IllegalStateException(msg);
#end

    }

    // ===================================================================================
    //                                                                     OrderBy Setting
    //                                                                     ===============
    public ConditionBean addOrderBy_PK_Asc() {
#if ($table.hasPrimaryKey())
#foreach ($col in $table.primaryKey)
        query().addOrderBy_${col.JavaName}_Asc();
#end
        return this;
#else
        String msg = "This table has no primary-keys: " + getTableDbName();
        throw new IllegalStateException(msg);
#end
    }

    public ConditionBean addOrderBy_PK_Desc() {
#if ($table.hasPrimaryKey())
#foreach ($col in $table.primaryKey)
        query().addOrderBy_${col.JavaName}_Desc();
#end
        return this;
#else
        String msg = "This table has no primary-keys: " + getTableDbName();
        throw new IllegalStateException(msg);
#end
    }

    // ===================================================================================
    //                                                                               Query
    //                                                                               =====
    public ${myConditionQueryClassName} query() {
        return getConditionQuery();
    }

    public ${myConditionQueryClassName} getConditionQuery() { // public for parameter comment
        if (_conditionQuery == null) {
            _conditionQuery = createLocalCQ();
        }
        return _conditionQuery;
    }

    protected ${myConditionQueryClassName} createLocalCQ() {
        return xcreateCQ(null, getSqlClause(), getSqlClause().getLocalTableAliasName(), 0);
    }

    protected ${myConditionQueryClassName} xcreateCQ(ConditionQuery childQuery, SqlClause sqlClause, String aliasName, int nestLevel) {
        return new ${myConditionQueryClassName}(childQuery, sqlClause, aliasName, nestLevel);
    }

    /**
     * ${database.implementComment}
     */
    public ConditionQuery localCQ() {
        return getConditionQuery();
    }

    // ===================================================================================
    //                                                                               Union
    //                                                                               =====
    /**
     * Set up 'union'.
     * <pre>
     * cb.query().union(new UnionQuery&lt;${myConditionBeanClassName}&gt;() {
     *     public void query(${myConditionBeanClassName} unionCB) {
     *         unionCB.query().setXxx...
     *     }
     * });
     * </pre>
     * @param unionQuery The query of 'union'. (NotNull)
     */
    public void union(UnionQuery<${myConditionBeanClassName}> unionQuery) {
        final ${myConditionBeanClassName} cb = new ${myConditionBeanClassName}();
        cb.xsetupForUnion(); xsyncUQ(cb); unionQuery.query(cb);
        final ${myConditionQueryClassName} cq = cb.query(); query().xsetUnionQuery(cq);
    }

    /**
     * Set up 'union all'.
     * <pre>
     * cb.query().unionAll(new UnionQuery&lt;${myConditionBeanClassName}&gt;() {
     *     public void query(${myConditionBeanClassName} unionCB) {
     *         unionCB.query().setXxx...
     *     }
     * });
     * </pre>
     * @param unionQuery The query of 'union'. (NotNull)
     */
    public void unionAll(UnionQuery<${myConditionBeanClassName}> unionQuery) {
        final ${myConditionBeanClassName} cb = new ${myConditionBeanClassName}();
        cb.xsetupForUnion(); xsyncUQ(cb); unionQuery.query(cb);
        final ${myConditionQueryClassName} cq = cb.query(); query().xsetUnionAllQuery(cq);
    }
#if ($database.isAvailableDatabaseDependency())
#if ($database.isDatabasePostgreSQL())

    // ===================================================================================
    //                                                                           Lock Wait
    //                                                                           =========
    public ConditionBean lockForUpdateNoWait()
    { if (xhelpIsSqlClausePostgreSql()) { xhelpGettingSqlClausePostgreSql().lockForUpdateNoWait(); } return this; }

    protected boolean xhelpIsSqlClausePostgreSql() {
        return getSqlClause() instanceof org.seasar.dbflute.cbean.sqlclause.SqlClausePostgreSql;
    }

    protected org.seasar.dbflute.cbean.sqlclause.SqlClausePostgreSql xhelpGettingSqlClausePostgreSql() {
        return (org.seasar.dbflute.cbean.sqlclause.SqlClausePostgreSql)getSqlClause();
    }
#end
#if ($database.isDatabaseOracle())

    // ===================================================================================
    //                                                                           Lock Wait
    //                                                                           =========
    public ConditionBean lockForUpdateNoWait()
    { if (xhelpIsSqlClauseOracle()) { xhelpGettingSqlClauseOracle().lockForUpdateNoWait(); } return this; }
    public ConditionBean lockForUpdateWait(int waitSec)
    { if (xhelpIsSqlClauseOracle()) { xhelpGettingSqlClauseOracle().lockForUpdateWait(waitSec); } return this; }

    protected boolean xhelpIsSqlClauseOracle() {
        return getSqlClause() instanceof org.seasar.dbflute.cbean.sqlclause.SqlClauseOracle;
    }

    protected org.seasar.dbflute.cbean.sqlclause.SqlClauseOracle xhelpGettingSqlClauseOracle() {
        return (org.seasar.dbflute.cbean.sqlclause.SqlClauseOracle)getSqlClause();
    }
#end
#if ($database.isDatabaseDB2())

    // [DBFlute-0.7.9]
    // ===================================================================================
    //                                                                     Isolation Level
    //                                                                     ===============
    // *Database Dependency
    public void lockWithRR() { if (xhelpIsSqlClauseDb2()) { xhelpGettingSqlClauseDb2().lockWithRR(); } }
    public void lockWithRS() { if (xhelpIsSqlClauseDb2()) { xhelpGettingSqlClauseDb2().lockWithRS(); } }
    public void lockWithCS() { if (xhelpIsSqlClauseDb2()) { xhelpGettingSqlClauseDb2().lockWithCS(); } }
    public void lockWithUR() { if (xhelpIsSqlClauseDb2()) { xhelpGettingSqlClauseDb2().lockWithUR(); } }

    protected boolean xhelpIsSqlClauseDb2() {
        return getSqlClause() instanceof org.seasar.dbflute.cbean.sqlclause.SqlClauseDb2;
    }

    protected org.seasar.dbflute.cbean.sqlclause.SqlClauseDb2 xhelpGettingSqlClauseDb2() {
        return (org.seasar.dbflute.cbean.sqlclause.SqlClauseDb2)getSqlClause();
    }
#end
#end

    // ===================================================================================
    //                                                                         SetupSelect
    //                                                                         ===========
#foreach ($fk in $table.foreignKeys)
#set ($tmpPropertyName = "${fk.foreignPropertyName}")
#set ($tmpPropertyNameInitCap = "${fk.foreignPropertyNameInitCap}")
#set ($nestSelectSetuppperClassName = "${fk.foreignTableNestSelectSetupperClassName}")
#set ($dynamicFixedConditionArgs = "")
#set ($dynamicFixedConditionVariables = "")
#if ($fk.hasDynamicFixedCondition())
#set ($dynamicFixedConditionArgs = "${fk.dynamicFixedConditionFinalArgs}")
#set ($dynamicFixedConditionVariables = "${fk.dynamicFixedConditionVariables}")
#end
    protected ${nestSelectSetuppperClassName} _nss${tmpPropertyNameInitCap};
    public ${nestSelectSetuppperClassName} getNss${tmpPropertyNameInitCap}() {
        if (_nss${tmpPropertyNameInitCap} == null) { _nss${tmpPropertyNameInitCap} = new ${nestSelectSetuppperClassName}(null); }
        return _nss${tmpPropertyNameInitCap};
    }
    public ${nestSelectSetuppperClassName} setupSelect_${tmpPropertyNameInitCap}(${dynamicFixedConditionArgs}) {
        doSetupSelect(new SsCall() { public ConditionQuery qf() { return query().query${tmpPropertyNameInitCap}(${dynamicFixedConditionVariables}); } });
        if (_nss${tmpPropertyNameInitCap} == null || !_nss${tmpPropertyNameInitCap}.hasConditionQuery())
        { _nss${tmpPropertyNameInitCap} = new ${nestSelectSetuppperClassName}(query().query${tmpPropertyNameInitCap}(${dynamicFixedConditionVariables})); }
        return _nss${tmpPropertyNameInitCap};
    }
#end
#foreach ($referrer in $table.referrers)
#if (${referrer.isOneToOne()})
#set ($tmpPropertyName = "${referrer.referrerPropertyNameAsOne}")
#set ($tmpPropertyNameInitCap = "${referrer.referrerPropertyNameInitCapAsOne}")
#set ($nestSelectSetuppperClassName = "${referrer.referrerTableNestSelectSetupperClassName}")

    protected ${nestSelectSetuppperClassName} _nss${tmpPropertyNameInitCap};
    public ${nestSelectSetuppperClassName} getNss${tmpPropertyNameInitCap}() {
        if (_nss${tmpPropertyNameInitCap} == null) { _nss${tmpPropertyNameInitCap} = new ${nestSelectSetuppperClassName}(null); }
        return _nss${tmpPropertyNameInitCap};
    }
    public ${nestSelectSetuppperClassName} setupSelect_${tmpPropertyNameInitCap}() {
        doSetupSelect(new SsCall() { public ConditionQuery qf() { return query().query${tmpPropertyNameInitCap}(); } });
        if (_nss${tmpPropertyNameInitCap} == null || !_nss${tmpPropertyNameInitCap}.hasConditionQuery()) { _nss${tmpPropertyNameInitCap} = new ${nestSelectSetuppperClassName}(query().query${tmpPropertyNameInitCap}()); }
        return _nss${tmpPropertyNameInitCap};
    }
#end
#end

    // [DBFlute-0.7.4]
    // ===================================================================================
    //                                                                             Specify
    //                                                                             =======
    protected HpSpecification _specification;
    public HpSpecification specify() {
        if (_specification == null) { _specification = new HpSpecification(this
            , new HpSpQyCall<${myConditionQueryClassName}>() {
                public boolean has() { return true; }
                public ${myConditionQueryClassName} qy() { return query(); }
            }
            , _forDerivedReferrer, _forScalarSelect, _forScalarSubQuery, getDBMetaProvider()); }
        return _specification;
    }
    protected HpAbstractSpecification<? extends ConditionQuery> localSp() {
        return specify();
    }

    public static class HpSpecification extends HpAbstractSpecification<${myConditionQueryClassName}> {
        protected HpSpQyCall<${myConditionQueryClassName}> _myQyCall;
#foreach ($fk in $table.foreignKeys)
#set ($tmpPropertyName = "${fk.foreignPropertyName}")
#set ($tmpCBClassName = "${fk.foreignTableExtendedConditionBeanClassName}")
        protected ${tmpCBClassName}.HpSpecification _${tmpPropertyName};
#end
#foreach ($referrer in $table.referrers)
#if (${referrer.isOneToOne()})
#set ($tmpPropertyName = "${referrer.referrerPropertyNameAsOne}")
#set ($tmpCBClassName = "${referrer.referrerTableExtendedConditionBeanClassName}")
        protected ${tmpCBClassName}.HpSpecification _${tmpPropertyName};
#end
#end
        public HpSpecification(ConditionBean baseCB, HpSpQyCall<${myConditionQueryClassName}> qyCall
                             , boolean forDeriveReferrer, boolean forScalarSelect, boolean forScalarSubQuery
                             , DBMetaProvider dbmetaProvider)
        { super(baseCB, qyCall, forDeriveReferrer, forScalarSelect, forScalarSubQuery, dbmetaProvider); _myQyCall = qyCall; }
#foreach ($col in $table.columns)
        /** ${col.aliasExpression}${col.name}: {${col.columnDefinitionLineDisp}} */
        public void column${col.javaName}() { doColumn("${col.name}"); }
#end
        protected void doSpecifyRequiredColumn() {
#foreach ($col in $table.primaryKey)
            column${col.javaName}(); // PK
#end
#foreach ($fk in $table.foreignKeys)
#set ($tmpPropertyName = "${fk.foreignPropertyName}")
#set ($tmpPropertyNameInitCap = "${fk.foreignPropertyNameInitCap}")
#if ($fk.hasLocalColumnExceptPrimaryKey())
            if (_myQyCall.qy().hasConditionQuery${tmpPropertyNameInitCap}()) {
#foreach ($col in $fk.localColumnList)
#if (!$col.isPrimaryKey())
                column${col.javaName}(); // FK
#end
#end
            }
#end
#end
        }
        protected String getTableDbName() { return "$table.name"; }
#foreach ($fk in $table.foreignKeys)
#set ($tmpPropertyName = "${fk.foreignPropertyName}")
#set ($tmpPropertyNameInitCap = "${fk.foreignPropertyNameInitCap}")
#set ($tmpCBClassName = "${fk.foreignTableExtendedConditionBeanClassName}")
#set ($tmpCQClassName = "${fk.foreignTableExtendedConditionQueryClassName}")
        /**
         * ${fk.foreignTable.aliasExpression}${fk.foreignTable.name} as '${fk.foreignJavaBeansRulePropertyName}'.
         * @return Next specification. (NotNull)
         */
        public ${tmpCBClassName}.HpSpecification specify${tmpPropertyNameInitCap}() {
            assertForeign("${tmpPropertyName}");
            if (_${tmpPropertyName} == null) {
                _${tmpPropertyName} = new ${tmpCBClassName}.HpSpecification(_baseCB, new HpSpQyCall<${tmpCQClassName}>() {
                    public boolean has() { return _myQyCall.has() && _myQyCall.qy().hasConditionQuery${tmpPropertyNameInitCap}(); }
#if ($fk.hasDynamicFixedCondition())
                    public ${tmpCQClassName} qy() { return _myQyCall.qy().getConditionQuery${tmpPropertyNameInitCap}(); } }
#else
                    public ${tmpCQClassName} qy() { return _myQyCall.qy().query${tmpPropertyNameInitCap}(); } }
#end
                    , _forDerivedReferrer, _forScalarSelect, _forScalarSubQuery, _dbmetaProvider);
                    if (_forGeneralOneSpecificaion) { _${tmpPropertyName}.xsetupForGeneralOneSpecification(null); }
            }
            return _${tmpPropertyName};
        }
#end
#foreach ($referrer in $table.referrers)
#if (${referrer.isOneToOne()})
#set ($tmpPropertyName = "${referrer.referrerPropertyNameAsOne}")
#set ($tmpPropertyNameInitCap = "${referrer.referrerPropertyNameInitCapAsOne}")
#set ($tmpCBClassName = "${referrer.referrerTableExtendedConditionBeanClassName}")
#set ($tmpCQClassName = "${referrer.referrerTableExtendedConditionQueryClassName}")
        /**
         * ${referrer.table.aliasExpression}${referrer.table.name} as '${referrer.referrerJavaBeansRulePropertyNameAsOne}'.
         * @return Next specification. (NotNull)
         */
        public ${tmpCBClassName}.HpSpecification specify${tmpPropertyNameInitCap}() {
            assertForeign("${tmpPropertyName}");
            if (_${tmpPropertyName} == null) {
                _${tmpPropertyName} = new ${tmpCBClassName}.HpSpecification(_baseCB, new HpSpQyCall<${tmpCQClassName}>() {
                    public boolean has() { return _myQyCall.has() && _myQyCall.qy().hasConditionQuery${tmpPropertyNameInitCap}(); }
                    public ${tmpCQClassName} qy() { return _myQyCall.qy().query${tmpPropertyNameInitCap}(); } }
                    , _forDerivedReferrer, _forScalarSelect, _forScalarSubQuery, _dbmetaProvider);
                if (_forGeneralOneSpecificaion) { _${tmpPropertyName}.xsetupForGeneralOneSpecification(null); }
            }
            return _${tmpPropertyName};
        }
#end
#end
#foreach ($referrer in $table.singleKeyStringOrIntegerReferrers)
#if (!${referrer.isOneToOne()})
#set ($tmpPropertyName = "${referrer.referrerPropertyName}")
#set ($tmpPropertyNameInitCap = "${referrer.referrerPropertyNameInitCap}")
#set ($tmpCBClassName = "${referrer.referrerTableExtendedConditionBeanClassName}")
#set ($tmpLocalCQClassName = "${referrer.foreignTableExtendedConditionQueryClassName}")
        /**
         * ${referrer.table.aliasExpression}${referrer.table.name} as '${referrer.referrerJavaBeansRulePropertyName}'.
         * @return Function. (NotNull)
         */
        public HpSDRFunction<${tmpCBClassName}, ${tmpLocalCQClassName}> derived${tmpPropertyNameInitCap}() {
            return new HpSDRFunction<${tmpCBClassName}, ${tmpLocalCQClassName}>(_baseCB, _myQyCall.qy(), new HpSDRSetupper<${tmpCBClassName}, ${tmpLocalCQClassName}>() {
                public void setup(String function, SubQuery<${tmpCBClassName}> subQuery, ${tmpLocalCQClassName} cq, String aliasName) {
                    cq.xsderive${referrer.referrerPropertyNameInitCap}(function, subQuery, aliasName); } }, _dbmetaProvider);
        }
#end
#end

        public void xsetupForGeneralOneSpecification(HpSpQyCall<${myConditionQueryClassName}> qyCall) {
            if (qyCall != null) { _myQyCall = qyCall; _qyCall = qyCall; } _forGeneralOneSpecificaion = true;
        }
    }

    // [DBFlute-0.9.5.3]
    // ===================================================================================
    //                                                                         ColumnQuery
    //                                                                         ===========
    /**
     * @param leftSpecifyQuery The specify-query for left column. (NotNull)
     * @return The object for setting up operand and right column. (NotNull)
     */
    public HpColQyOperand<${myConditionBeanClassName}> columnQuery(final SpecifyQuery<${myConditionBeanClassName}> leftSpecifyQuery) {
        return new HpColQyOperand<${myConditionBeanClassName}>(new HpColQyHandler<${myConditionBeanClassName}>() {
            public void handle(SpecifyQuery<${myConditionBeanClassName}> rightSp, String operand) {
                ${myConditionBeanClassName} cb = new ${myConditionBeanClassName}();
                cb.specify().xsetupForGeneralOneSpecification(new HpSpQyCall<${myConditionQueryClassName}>() {
                    public boolean has() { return true; }
                    public ${myConditionQueryClassName} qy() { return query(); }
                });
                xcolqy(cb, leftSpecifyQuery, rightSp, operand);
            }
        });
    }

    // [DBFlute-0.9.6.3]
    // ===================================================================================
    //                                                                        OrScopeQuery
    //                                                                        ============
    public void orScopeQuery(OrQuery<${myConditionBeanClassName}> orQuery) {
        xorSQ((${myConditionBeanClassName})this, orQuery);
    }

    // ===================================================================================
    //                                                                          DisplaySQL
    //                                                                          ==========
    @Override
    protected SqlAnalyzerFactory getSqlAnalyzerFactory()
    { return new ${glImplementedInvokerAssistant}().assistSqlAnalyzerFactory(); }
    @Override
    protected String getLogDateFormat() { return ${glDBFluteConfig}.getInstance().getLogDateFormat(); }
    @Override
    protected String getLogTimestampFormat() { return ${glDBFluteConfig}.getInstance().getLogTimestampFormat(); }

    // ===================================================================================
    //                                                          Basic Status Determination
    //                                                          ==========================
    public boolean hasUnionQueryOrUnionAllQuery() {
        return query().hasUnionQueryOrUnionAllQuery();
    }

    // ===================================================================================
    //                                                                            Internal
    //                                                                            ========
    // Very Internal (for Suppressing Warn about 'Not Use Import')
    protected String getConditionBeanClassNameInternally() { return ${myConditionBeanClassName}.class.getName(); }
    protected String getConditionQueryClassNameInternally() { return ${myConditionQueryClassName}.class.getName(); }
    protected String getSubQueryClassNameInternally() { return SubQuery.class.getName(); }
}
