package com.chenyang.druid.sql.ast.expr;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLExprImpl;
import com.chenyang.druid.sql.ast.SQLReplaceable;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class SQLBinaryOpExprGroup extends SQLExprImpl implements SQLReplaceable {
   private final SQLBinaryOperator operator;
   private final List<SQLExpr> items = new ArrayList();
   private DbType dbType;

   public SQLBinaryOpExprGroup(SQLBinaryOperator operator) {
      this.operator = operator;
   }

   public SQLBinaryOpExprGroup(SQLBinaryOperator operator, DbType dbType) {
      this.operator = operator;
      this.dbType = dbType;
   }

   public boolean equals(Object o) {
      if (this == o) {
         return true;
      } else if (o != null && this.getClass() == o.getClass()) {
         SQLBinaryOpExprGroup that = (SQLBinaryOpExprGroup)o;
         return this.operator != that.operator ? false : this.items.equals(that.items);
      } else {
         return false;
      }
   }

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

   protected void accept0(SQLASTVisitor visitor) {
      if (visitor.visit(this)) {
         for(int i = 0; i < this.items.size(); ++i) {
            SQLExpr item = (SQLExpr)this.items.get(i);
            item.accept(visitor);
         }
      }

      visitor.endVisit(this);
   }

   public SQLExpr clone() {
      SQLBinaryOpExprGroup x = new SQLBinaryOpExprGroup(this.operator);

      for(SQLExpr item : this.items) {
         SQLExpr item2 = item.clone();
         item2.setParent(this);
         x.items.add(item2);
      }

      return x;
   }

   public List getChildren() {
      return this.items;
   }

   public void add(SQLExpr item) {
      this.add(this.items.size(), item);
   }

   public void add(int index, SQLExpr item) {
      if (item instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr)item;
         if (binaryOpExpr.getOperator() == this.operator) {
            this.add(binaryOpExpr.getLeft());
            this.add(binaryOpExpr.getRight());
            return;
         }
      } else if (item instanceof SQLBinaryOpExprGroup) {
         SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)item;
         if (group.operator == this.operator) {
            for(SQLExpr sqlExpr : group.getItems()) {
               this.add(sqlExpr);
            }

            return;
         }
      }

      if (item != null) {
         item.setParent(this);
      }

      this.items.add(index, item);
   }

   public List<SQLExpr> getItems() {
      return this.items;
   }

   public SQLBinaryOperator getOperator() {
      return this.operator;
   }

   public String toString() {
      return SQLUtils.toSQLString(this, (DbType)this.dbType);
   }

   public boolean replace(SQLExpr expr, SQLExpr target) {
      boolean replaced = false;

      for(int i = 0; i < this.items.size(); ++i) {
         if (this.items.get(i) == expr) {
            if (target == null) {
               this.items.remove(i);
            } else if (target instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)target).getOperator() == this.operator) {
               this.items.remove(i);
               List<SQLExpr> list = SQLBinaryOpExpr.split(target, this.operator);

               for(int j = 0; j < list.size(); ++j) {
                  SQLExpr o = (SQLExpr)list.get(j);
                  o.setParent(this);
                  this.items.add(i + j, o);
               }
            } else {
               target.setParent(this);
               this.items.set(i, target);
            }

            replaced = true;
         }
      }

      if (this.items.size() == 1 && replaced) {
         SQLUtils.replaceInParent((SQLExpr)this, (SQLExpr)((SQLExpr)this.items.get(0)));
      }

      if (this.items.size() == 0) {
         SQLUtils.replaceInParent((SQLExpr)this, (SQLExpr)null);
      }

      return replaced;
   }

   public void optimize() {
      List<Integer> dupIndexList = null;
      Set<SQLExpr> itemSet = new LinkedHashSet();

      for(int i = 0; i < this.items.size(); ++i) {
         if (!itemSet.add(this.items.get(i))) {
            if (dupIndexList == null) {
               dupIndexList = new ArrayList();
            }

            dupIndexList.add(i);
         }
      }

      if (dupIndexList != null) {
         for(int i = dupIndexList.size() - 1; i >= 0; --i) {
            int index = (Integer)dupIndexList.get(i);
            this.items.remove(index);
         }
      }

   }
}
