package com.chenyang.druid.sql.ast;

import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.List;

public class SQLOver extends SQLObjectImpl implements SQLReplaceable {
   protected final List<SQLExpr> partitionBy = new ArrayList();
   protected SQLOrderBy orderBy;
   protected SQLOrderBy distributeBy;
   protected SQLOrderBy sortBy;
   protected SQLName of;
   protected SQLName name;
   protected WindowingType windowingType;
   protected boolean windowingPreceding;
   protected boolean windowingFollowing;
   protected SQLExpr windowingBetweenBegin;
   protected WindowingBound windowingBetweenBeginBound;
   protected SQLExpr windowingBetweenEnd;
   protected WindowingBound windowingBetweenEndBound;

   public SQLOver() {
   }

   public SQLOver(SQLOrderBy orderBy) {
      this.setOrderBy(orderBy);
   }

   protected void accept0(SQLASTVisitor visitor) {
      if (visitor.visit(this)) {
         if (this.partitionBy != null) {
            for(SQLExpr item : this.partitionBy) {
               if (item != null) {
                  item.accept(visitor);
               }
            }
         }

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

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

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

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

      visitor.endVisit(this);
   }

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

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

      this.orderBy = orderBy;
   }

   public SQLOrderBy getDistributeBy() {
      return this.distributeBy;
   }

   public void setDistributeBy(SQLOrderBy x) {
      if (x != null) {
         x.setParent(this);
      }

      this.distributeBy = x;
   }

   public SQLOrderBy getSortBy() {
      return this.sortBy;
   }

   public void setSortBy(SQLOrderBy x) {
      if (x != null) {
         x.setParent(this);
      }

      this.sortBy = x;
   }

   public SQLName getOf() {
      return this.of;
   }

   public void setOf(SQLName of) {
      if (of != null) {
         of.setParent(this);
      }

      this.of = of;
   }

   public List<SQLExpr> getPartitionBy() {
      return this.partitionBy;
   }

   public WindowingType getWindowingType() {
      return this.windowingType;
   }

   public void setWindowingType(WindowingType windowingType) {
      this.windowingType = windowingType;
   }

   public boolean isWindowingPreceding() {
      return this.windowingPreceding;
   }

   public void setWindowingPreceding(boolean windowingPreceding) {
      this.windowingPreceding = windowingPreceding;
   }

   public SQLExpr getWindowingBetweenBegin() {
      return this.windowingBetweenBegin;
   }

   public void setWindowingBetweenBegin(SQLExpr windowingBetweenBegin) {
      this.windowingBetweenBegin = windowingBetweenBegin;
   }

   public SQLExpr getWindowingBetweenEnd() {
      return this.windowingBetweenEnd;
   }

   public void setWindowingBetweenEnd(SQLExpr windowingBetweenEnd) {
      this.windowingBetweenEnd = windowingBetweenEnd;
   }

   public boolean isWindowingBetweenEndPreceding() {
      return this.windowingBetweenEndBound == WindowingBound.PRECEDING;
   }

   public boolean isWindowingBetweenEndFollowing() {
      return this.windowingBetweenEndBound == WindowingBound.FOLLOWING;
   }

   public WindowingBound getWindowingBetweenBeginBound() {
      return this.windowingBetweenBeginBound;
   }

   public void setWindowingBetweenBeginBound(WindowingBound windowingBetweenBeginBound) {
      this.windowingBetweenBeginBound = windowingBetweenBeginBound;
   }

   public WindowingBound getWindowingBetweenEndBound() {
      return this.windowingBetweenEndBound;
   }

   public void setWindowingBetweenEndBound(WindowingBound windowingBetweenEndBound) {
      this.windowingBetweenEndBound = windowingBetweenEndBound;
   }

   public SQLName getName() {
      return this.name;
   }

   public void setName(SQLName name) {
      this.name = name;
   }

   public boolean equals(Object o) {
      if (this == o) {
         return true;
      } else if (o != null && this.getClass() == o.getClass()) {
         SQLOver sqlOver = (SQLOver)o;
         if (this.windowingPreceding != sqlOver.windowingPreceding) {
            return false;
         } else if (this.windowingFollowing != sqlOver.windowingFollowing) {
            return false;
         } else if (!this.partitionBy.equals(sqlOver.partitionBy)) {
            return false;
         } else {
            if (this.orderBy != null) {
               if (!this.orderBy.equals(sqlOver.orderBy)) {
                  return false;
               }
            } else if (sqlOver.orderBy != null) {
               return false;
            }

            if (this.of != null) {
               if (!this.of.equals(sqlOver.of)) {
                  return false;
               }
            } else if (sqlOver.of != null) {
               return false;
            }

            if (this.windowingType != sqlOver.windowingType) {
               return false;
            } else {
               if (this.windowingBetweenBegin != null) {
                  if (!this.windowingBetweenBegin.equals(sqlOver.windowingBetweenBegin)) {
                     return false;
                  }
               } else if (sqlOver.windowingBetweenBegin != null) {
                  return false;
               }

               if (this.windowingBetweenBeginBound != sqlOver.windowingBetweenBeginBound) {
                  return false;
               } else {
                  if (this.windowingBetweenEnd != null) {
                     if (!this.windowingBetweenEnd.equals(sqlOver.windowingBetweenEnd)) {
                        return false;
                     }
                  } else if (sqlOver.windowingBetweenEnd != null) {
                     return false;
                  }

                  return this.windowingBetweenEndBound == sqlOver.windowingBetweenEndBound;
               }
            }
         }
      } else {
         return false;
      }
   }

   public int hashCode() {
      int result = this.partitionBy != null ? this.partitionBy.hashCode() : 0;
      result = 31 * result + (this.orderBy != null ? this.orderBy.hashCode() : 0);
      result = 31 * result + (this.of != null ? this.of.hashCode() : 0);
      result = 31 * result + (this.windowingType != null ? this.windowingType.hashCode() : 0);
      result = 31 * result + (this.windowingPreceding ? 1 : 0);
      result = 31 * result + (this.windowingFollowing ? 1 : 0);
      result = 31 * result + (this.windowingBetweenBegin != null ? this.windowingBetweenBegin.hashCode() : 0);
      result = 31 * result + (this.windowingBetweenBeginBound != null ? this.windowingBetweenBeginBound.hashCode() : 0);
      result = 31 * result + (this.windowingBetweenEnd != null ? this.windowingBetweenEnd.hashCode() : 0);
      result = 31 * result + (this.windowingBetweenEndBound != null ? this.windowingBetweenEndBound.hashCode() : 0);
      return result;
   }

   public void cloneTo(SQLOver x) {
      for(SQLExpr item : this.partitionBy) {
         SQLExpr item1 = item.clone();
         item1.setParent(x);
         x.partitionBy.add(item1);
      }

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

      if (this.of != null) {
         x.setOf(this.of.clone());
      }

      x.windowingType = this.windowingType;
      x.windowingPreceding = this.windowingPreceding;
      x.windowingFollowing = this.windowingFollowing;
      if (this.windowingBetweenBegin != null) {
         x.setWindowingBetweenBegin(this.windowingBetweenBegin.clone());
      }

      x.windowingBetweenBeginBound = this.windowingBetweenBeginBound;
      x.windowingBetweenEndBound = this.windowingBetweenEndBound;
      if (this.windowingBetweenEnd != null) {
         x.setWindowingBetweenEnd(this.windowingBetweenEnd.clone());
      }

   }

   public SQLOver clone() {
      SQLOver x = new SQLOver();
      this.cloneTo(x);
      return x;
   }

   public boolean replace(SQLExpr expr, SQLExpr target) {
      if (this.windowingBetweenBegin == expr) {
         this.setWindowingBetweenBegin(target);
         return true;
      } else if (this.windowingBetweenEnd == expr) {
         this.setWindowingBetweenEnd(target);
         return true;
      } else {
         for(int i = 0; i < this.partitionBy.size(); ++i) {
            if (this.partitionBy.get(i) == expr) {
               this.partitionBy.set(i, target);
               target.setParent(this);
            }
         }

         return false;
      }
   }

   public static enum WindowingType {
      ROWS("ROWS"),
      RANGE("RANGE"),
      GROUPS("GROUPS");

      public final String name;
      public final String name_lower;

      private WindowingType(String name) {
         this.name = name;
         this.name_lower = name.toLowerCase();
      }
   }

   public static enum WindowingBound {
      UNBOUNDED_PRECEDING("UNBOUNDED PRECEDING"),
      PRECEDING("PRECEDING"),
      CURRENT_ROW("CURRENT ROW"),
      FOLLOWING("FOLLOWING"),
      UNBOUNDED_FOLLOWING("UNBOUNDED FOLLOWING");

      public final String name;
      public final String name_lower;

      private WindowingBound(String name) {
         this.name = name;
         this.name_lower = name.toLowerCase();
      }
   }
}
