package com.chenyang.druid.sql.ast;

import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class SQLLimit extends SQLObjectImpl implements SQLReplaceable {
   private SQLExpr rowCount;
   private SQLExpr offset;
   private List<SQLExpr> by;
   private boolean percent;
   private boolean fetchFirst;
   private Type type;

   public SQLLimit() {
   }

   public SQLLimit(int rowCount) {
      this.setRowCount(new SQLIntegerExpr(rowCount));
   }

   public SQLLimit(SQLExpr rowCount) {
      this.setRowCount(rowCount);
   }

   public SQLLimit(SQLExpr offset, SQLExpr rowCount) {
      this.setOffset(offset);
      this.setRowCount(rowCount);
   }

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

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

      this.rowCount = rowCount;
   }

   public void setRowCount(int rowCount) {
      this.setRowCount(new SQLIntegerExpr(rowCount));
   }

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

   public void setOffset(int offset) {
      this.setOffset(new SQLIntegerExpr(offset));
   }

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

      this.offset = offset;
   }

   public void merge(SQLLimit other) {
      if (other != null) {
         if (other.offset != null && this.offset == null) {
            this.offset = other.offset.clone();
         }

         if (other.rowCount != null && this.rowCount == null) {
            this.rowCount = other.rowCount.clone();
         }

         if (other.by != null) {
            for(SQLExpr item : other.by) {
               this.addBy(item.clone());
            }
         }

      }
   }

   protected void accept0(SQLASTVisitor visitor) {
      if (visitor.visit(this)) {
         if (this.offset != null) {
            this.offset.accept(visitor);
         }

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

         if (this.by != null) {
            for(SQLExpr item : this.by) {
               item.accept(visitor);
            }
         }
      }

      visitor.endVisit(this);
   }

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

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

      if (this.by != null) {
         for(SQLExpr item : this.by) {
            x.addBy(item);
         }
      }

      if (this.attributes != null) {
         x.attributes = (HashMap)((HashMap)this.attributes).clone();
      }

      return x;
   }

   public void addBy(SQLExpr item) {
      if (item != null) {
         if (this.by == null) {
            this.by = new ArrayList(1);
         }

         this.by.add(item);
         item.setParent(this);
      }
   }

   public List<SQLExpr> getBy() {
      return this.by;
   }

   public boolean replace(SQLExpr expr, SQLExpr target) {
      if (this.rowCount == expr) {
         this.setRowCount(target);
         return true;
      } else if (this.offset == expr) {
         this.setOffset(target);
         return true;
      } else {
         return false;
      }
   }

   public boolean equals(Object o) {
      if (this == o) {
         return true;
      } else if (o != null && this.getClass() == o.getClass()) {
         SQLLimit limit = (SQLLimit)o;
         if (this.rowCount != null) {
            if (!this.rowCount.equals(limit.rowCount)) {
               return false;
            }
         } else if (limit.rowCount != null) {
            return false;
         }

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

   public int hashCode() {
      int result = this.rowCount != null ? this.rowCount.hashCode() : 0;
      result = 31 * result + (this.offset != null ? this.offset.hashCode() : 0);
      return result;
   }

   public boolean isPercent() {
      return this.percent;
   }

   public void setPercent(boolean percent) {
      this.percent = percent;
   }

   public void setBy(List<SQLExpr> by) {
      this.by = by;
   }

   public boolean isFetchFirst() {
      return this.fetchFirst;
   }

   public void setFetchFirst(boolean fetchFirst) {
      this.fetchFirst = fetchFirst;
   }

   public Type getType() {
      return this.type;
   }

   public void setType(Type type) {
      this.type = type;
   }

   public boolean isLimitOffsetType() {
      return this.getType() != null && this.getType() == Type.LIMIT_OFFSET;
   }

   public static enum Type {
      LIMIT,
      LIMIT_OFFSET,
      FETCH;
   }
}
