package com.chenyang.druid.sql.dialect.oracle.ast.stmt;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLLimit;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOperator;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.dialect.oracle.ast.OracleSQLObject;
import com.chenyang.druid.sql.dialect.oracle.ast.clause.ModelClause;
import com.chenyang.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;

public class OracleSelectQueryBlock extends SQLSelectQueryBlock implements OracleSQLObject {
   private ModelClause modelClause;
   private boolean skipLocked = false;

   public OracleSelectQueryBlock clone() {
      OracleSelectQueryBlock x = new OracleSelectQueryBlock();
      super.cloneTo(x);
      if (this.modelClause != null) {
         x.setModelClause(this.modelClause.clone());
      }

      if (this.forUpdateOf != null) {
         for(SQLExpr item : this.forUpdateOf) {
            SQLExpr item1 = item.clone();
            item1.setParent(x);
            x.getForUpdateOf().add(item1);
         }
      }

      x.skipLocked = this.skipLocked;
      return x;
   }

   public OracleSelectQueryBlock() {
      this.dbType = DbType.oracle;
   }

   public ModelClause getModelClause() {
      return this.modelClause;
   }

   public void setModelClause(ModelClause modelClause) {
      this.modelClause = modelClause;
   }

   public boolean isSkipLocked() {
      return this.skipLocked;
   }

   public void setSkipLocked(boolean skipLocked) {
      this.skipLocked = skipLocked;
   }

   protected void accept0(SQLASTVisitor visitor) {
      if (visitor instanceof OracleASTVisitor) {
         this.accept0((OracleASTVisitor)visitor);
      } else {
         super.accept0(visitor);
      }
   }

   public void accept0(OracleASTVisitor visitor) {
      if (visitor.visit(this)) {
         this.acceptChild(visitor, this.hints);
         this.acceptChild(visitor, this.selectList);
         this.acceptChild(visitor, this.into);
         this.acceptChild(visitor, this.from);
         this.acceptChild(visitor, this.where);
         this.acceptChild(visitor, this.startWith);
         this.acceptChild(visitor, this.connectBy);
         this.acceptChild(visitor, this.groupBy);
         this.acceptChild(visitor, this.orderBy);
         this.acceptChild(visitor, this.waitTime);
         this.acceptChild(visitor, this.limit);
         this.acceptChild(visitor, this.modelClause);
         this.acceptChild(visitor, this.forUpdateOf);
      }

      visitor.endVisit(this);
   }

   public String toString() {
      return SQLUtils.toOracleString(this);
   }

   public void limit(int rowCount, int offset) {
      if (offset <= 0) {
         SQLExpr rowCountExpr = new SQLIntegerExpr(rowCount);
         SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanAnd, rowCountExpr, false, this.where);
         this.setWhere(newCondition);
      } else {
         throw new UnsupportedOperationException("not support offset");
      }
   }

   public void setFrom(String tableName) {
      SQLExprTableSource from;
      if (tableName != null && tableName.length() != 0) {
         from = new OracleSelectTableReference(new SQLIdentifierExpr(tableName));
      } else {
         from = null;
      }

      this.setFrom(from);
   }

   public void setFirst(SQLExpr first, boolean percent) {
      if (this.limit == null) {
         this.limit = new SQLLimit();
      }

      this.limit.setRowCount(first);
      this.limit.setPercent(percent);
   }
}
