package com.alibaba.druid.sql.ast.statement;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLDbTypedObject;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLHint;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SQLSelect extends SQLObjectImpl implements SQLDbTypedObject {
   protected SQLWithSubqueryClause withSubQuery;
   protected SQLSelectQuery query;
   protected SQLOrderBy orderBy;
   protected SQLLimit limit;
   protected List<SQLHint> hints;
   protected SQLObject restriction;
   protected boolean forBrowse;
   protected List<String> forXmlOptions = null;
   protected SQLExpr xmlPath;
   protected SQLExpr rowCount;
   protected SQLExpr offset;
   protected boolean forUpdate = false;
   protected List<SQLExpr> forUpdateOf;
   protected boolean noWait = false;
   protected SQLExpr waitTime;
   protected boolean skipLocked = false;
   private SQLHint headHint;

   public SQLSelect() {
   }

   public List<SQLHint> getHints() {
      if (this.hints == null) {
         this.hints = new ArrayList(2);
      }

      return this.hints;
   }

   public int getHintsSize() {
      return this.hints == null ? 0 : this.hints.size();
   }

   public SQLSelect(SQLSelectQuery query) {
      this.setQuery(query);
   }

   public SQLWithSubqueryClause getWithSubQuery() {
      return this.withSubQuery;
   }

   public void setWithSubQuery(SQLWithSubqueryClause x) {
      if (x != null) {
         x.setParent(this);
      }

      this.withSubQuery = x;
   }

   public SQLSelectQuery getQuery() {
      return this.query;
   }

   public void setQuery(SQLSelectQuery query) {
      if (query != null) {
         query.setParent(this);
      }

      this.query = query;
   }

   public SQLSelectQueryBlock getQueryBlock() {
      return this.query instanceof SQLSelectQueryBlock ? (SQLSelectQueryBlock)this.query : null;
   }

   public SQLOrderBy getOrderBy() {
      return this.orderBy;
   }

   public void setOrderBy(SQLOrderBy orderBy) {
      if (orderBy != null) {
         orderBy.setParent(this);
      }

      this.orderBy = orderBy;
   }

   protected void accept0(SQLASTVisitor v) {
      if (v.visit(this)) {
         if (this.withSubQuery != null) {
            this.withSubQuery.accept0(v);
         }

         if (this.query != null) {
            this.query.accept(v);
         }

         if (this.restriction != null) {
            this.restriction.accept(v);
         }

         if (this.orderBy != null) {
            this.orderBy.accept(v);
         }

         if (this.hints != null) {
            for(SQLHint hint : this.hints) {
               hint.accept(v);
            }
         }

         if (this.offset != null) {
            this.offset.accept(v);
         }

         if (this.rowCount != null) {
            this.rowCount.accept(v);
         }

         if (this.forUpdateOf != null) {
            for(SQLExpr sqlExpr : this.forUpdateOf) {
               sqlExpr.accept(v);
            }
         }

         if (this.waitTime != null) {
            this.waitTime.accept(v);
         }

         if (this.headHint != null) {
            this.headHint.accept(v);
         }
      }

      v.endVisit(this);
   }

   public DbType getDbType() {
      DbType dbType = null;
      SQLObject parent = this.getParent();
      if (parent instanceof SQLStatement) {
         dbType = ((SQLStatement)parent).getDbType();
      }

      if (dbType == null && parent instanceof OracleSQLObject) {
         dbType = DbType.oracle;
      }

      if (dbType == null && this.query instanceof SQLSelectQueryBlock) {
         dbType = ((SQLSelectQueryBlock)this.query).dbType;
      }

      return dbType;
   }

   public SQLSelect clone() {
      SQLSelect x = new SQLSelect();
      x.withSubQuery = this.withSubQuery;
      if (this.query != null) {
         x.setQuery(this.query.clone());
      }

      if (this.orderBy != null) {
         x.setOrderBy(this.orderBy.clone());
      }

      if (this.restriction != null) {
         x.setRestriction(this.restriction.clone());
      }

      if (this.hints != null) {
         for(SQLHint hint : this.hints) {
            x.hints.add(hint);
         }
      }

      x.forBrowse = this.forBrowse;
      if (this.forXmlOptions != null) {
         x.forXmlOptions = new ArrayList(this.forXmlOptions);
      }

      if (this.xmlPath != null) {
         x.setXmlPath(this.xmlPath.clone());
      }

      if (this.rowCount != null) {
         x.setRowCount(this.rowCount.clone());
      }

      if (this.offset != null) {
         x.setOffset(this.offset.clone());
      }

      if (this.headHint != null) {
         x.setHeadHint(this.headHint.clone());
      }

      return x;
   }

   public boolean isSimple() {
      return this.withSubQuery == null && (this.hints == null || this.hints.size() == 0) && this.restriction == null && !this.forBrowse && (this.forXmlOptions == null || this.forXmlOptions.size() == 0) && this.xmlPath == null && this.rowCount == null && this.offset == null;
   }

   public SQLObject getRestriction() {
      return this.restriction;
   }

   public void setRestriction(SQLObject restriction) {
      if (restriction != null) {
         restriction.setParent(this);
      }

      this.restriction = restriction;
   }

   public boolean isForBrowse() {
      return this.forBrowse;
   }

   public void setForBrowse(boolean forBrowse) {
      this.forBrowse = forBrowse;
   }

   public List<String> getForXmlOptions() {
      if (this.forXmlOptions == null) {
         this.forXmlOptions = new ArrayList(4);
      }

      return this.forXmlOptions;
   }

   public int getForXmlOptionsSize() {
      return this.forXmlOptions == null ? 0 : this.forXmlOptions.size();
   }

   public SQLExpr getRowCount() {
      return this.rowCount;
   }

   public void setRowCount(SQLExpr rowCount) {
      if (rowCount != null) {
         rowCount.setParent(this);
      }

      this.rowCount = rowCount;
   }

   public SQLHint getHeadHint() {
      return this.headHint;
   }

   public void setHeadHint(SQLHint headHint) {
      this.headHint = headHint;
   }

   public SQLExpr getOffset() {
      return this.offset;
   }

   public void setOffset(SQLExpr offset) {
      if (offset != null) {
         offset.setParent(this);
      }

      this.offset = offset;
   }

   public SQLExpr getXmlPath() {
      return this.xmlPath;
   }

   public void setXmlPath(SQLExpr xmlPath) {
      if (xmlPath != null) {
         xmlPath.setParent(this);
      }

      this.xmlPath = xmlPath;
   }

   public List<String> computeSelecteListAlias() {
      SQLSelectQueryBlock firstQuery = this.getFirstQueryBlock();
      return firstQuery != null ? firstQuery.computeSelecteListAlias() : Collections.emptyList();
   }

   public SQLSelectQueryBlock getFirstQueryBlock() {
      if (this.query instanceof SQLSelectQueryBlock) {
         return (SQLSelectQueryBlock)this.query;
      } else if (!(this.query instanceof SQLUnionQuery)) {
         return null;
      } else {
         SQLUnionQuery union;
         for(union = (SQLUnionQuery)this.query; union.getLeft() instanceof SQLUnionQuery; union = (SQLUnionQuery)union.getLeft()) {
         }

         return union.getFirstQueryBlock();
      }
   }

   public boolean equals(Object o) {
      if (this == o) {
         return true;
      } else if (o != null && this.getClass() == o.getClass()) {
         SQLSelect sqlSelect = (SQLSelect)o;
         if (this.forBrowse != sqlSelect.forBrowse) {
            return false;
         } else {
            if (this.withSubQuery != null) {
               if (!this.withSubQuery.equals(sqlSelect.withSubQuery)) {
                  return false;
               }
            } else if (sqlSelect.withSubQuery != null) {
               return false;
            }

            if (this.query != null) {
               if (!this.query.equals(sqlSelect.query)) {
                  return false;
               }
            } else if (sqlSelect.query != null) {
               return false;
            }

            if (this.orderBy != null) {
               if (!this.orderBy.equals(sqlSelect.orderBy)) {
                  return false;
               }
            } else if (sqlSelect.orderBy != null) {
               return false;
            }

            if (this.limit != null) {
               if (!this.limit.equals(sqlSelect.limit)) {
                  return false;
               }
            } else if (sqlSelect.limit != null) {
               return false;
            }

            if (this.hints != null) {
               if (!this.hints.equals(sqlSelect.hints)) {
                  return false;
               }
            } else if (sqlSelect.hints != null) {
               return false;
            }

            if (this.restriction != null) {
               if (!this.restriction.equals(sqlSelect.restriction)) {
                  return false;
               }
            } else if (sqlSelect.restriction != null) {
               return false;
            }

            if (this.forXmlOptions != null) {
               if (!this.forXmlOptions.equals(sqlSelect.forXmlOptions)) {
                  return false;
               }
            } else if (sqlSelect.forXmlOptions != null) {
               return false;
            }

            if (this.xmlPath != null) {
               if (!this.xmlPath.equals(sqlSelect.xmlPath)) {
                  return false;
               }
            } else if (sqlSelect.xmlPath != null) {
               return false;
            }

            if (this.rowCount != null) {
               if (!this.rowCount.equals(sqlSelect.rowCount)) {
                  return false;
               }
            } else if (sqlSelect.rowCount != null) {
               return false;
            }

            if (this.offset != null) {
               if (!this.offset.equals(sqlSelect.offset)) {
                  return false;
               }
            } else if (sqlSelect.offset != null) {
               return false;
            }

            return this.headHint != null ? this.headHint.equals(sqlSelect.headHint) : sqlSelect.headHint == null;
         }
      } else {
         return false;
      }
   }

   public int hashCode() {
      int result = this.withSubQuery != null ? this.withSubQuery.hashCode() : 0;
      result = 31 * result + (this.query != null ? this.query.hashCode() : 0);
      result = 31 * result + (this.orderBy != null ? this.orderBy.hashCode() : 0);
      result = 31 * result + (this.limit != null ? this.limit.hashCode() : 0);
      result = 31 * result + (this.hints != null ? this.hints.hashCode() : 0);
      result = 31 * result + (this.restriction != null ? this.restriction.hashCode() : 0);
      result = 31 * result + (this.forBrowse ? 1 : 0);
      result = 31 * result + (this.forXmlOptions != null ? this.forXmlOptions.hashCode() : 0);
      result = 31 * result + (this.xmlPath != null ? this.xmlPath.hashCode() : 0);
      result = 31 * result + (this.rowCount != null ? this.rowCount.hashCode() : 0);
      result = 31 * result + (this.offset != null ? this.offset.hashCode() : 0);
      result = 31 * result + (this.headHint != null ? this.headHint.hashCode() : 0);
      return result;
   }

   public boolean addWhere(SQLExpr where) {
      if (where == null) {
         return false;
      } else if (this.query instanceof SQLSelectQueryBlock) {
         ((SQLSelectQueryBlock)this.query).addWhere(where);
         return true;
      } else if (this.query instanceof SQLUnionQuery) {
         SQLSelectQueryBlock queryBlock = new SQLSelectQueryBlock(this.getDbType());
         queryBlock.setFrom(new SQLSelect(this.query), "u");
         queryBlock.addSelectItem((SQLExpr)(new SQLAllColumnExpr()));
         queryBlock.setParent(queryBlock);
         this.query = queryBlock;
         return true;
      } else {
         return false;
      }
   }

   public boolean replace(SQLSelectQuery cmp, SQLSelectQuery target) {
      if (cmp == this.query) {
         this.setQuery(target);
         return true;
      } else {
         return false;
      }
   }

   public SQLLimit getLimit() {
      return this.limit;
   }

   public void setLimit(SQLLimit x) {
      if (x != null) {
         x.setParent(this);
      }

      this.limit = x;
   }

   public boolean isForUpdate() {
      return this.forUpdate;
   }

   public void setForUpdate(boolean forUpdate) {
      this.forUpdate = forUpdate;
   }

   public List<SQLExpr> getForUpdateOf() {
      return this.forUpdateOf;
   }

   public void setForUpdateOf(List<SQLExpr> forUpdateOf) {
      this.forUpdateOf = forUpdateOf;
   }

   public boolean isNoWait() {
      return this.noWait;
   }

   public void setNoWait(boolean noWait) {
      this.noWait = noWait;
   }

   public SQLExpr getWaitTime() {
      return this.waitTime;
   }

   public void setWaitTime(SQLExpr waitTime) {
      this.waitTime = waitTime;
   }

   public int getForUpdateOfSize() {
      return this.forUpdateOf == null ? 0 : this.forUpdateOf.size();
   }

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

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