package com.chenyang.druid.sql.ast;

import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.statement.SQLAssignItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import com.chenyang.druid.util.FnvHash;
import java.util.ArrayList;
import java.util.List;

public class SQLIndexDefinition extends SQLObjectImpl implements SQLIndex {
   private boolean hasConstraint;
   private SQLName symbol;
   private boolean global;
   private boolean local;
   private String type;
   private boolean hashMapType;
   private boolean hashType;
   private boolean index;
   private boolean key;
   private SQLName name;
   private SQLTableSource table;
   private List<SQLSelectOrderByItem> columns = new ArrayList();
   private SQLIndexOptions options;
   private SQLExpr dbPartitionBy;
   private SQLExpr tbPartitionBy;
   private SQLExpr tbPartitions;
   private List<SQLName> covering = new ArrayList();
   private SQLName analyzerName;
   private SQLName indexAnalyzerName;
   private SQLName queryAnalyzerName;
   private SQLName withDicName;
   private List<SQLAssignItem> compatibleOptions = new ArrayList();

   public boolean hasConstraint() {
      return this.hasConstraint;
   }

   public void setHasConstraint(boolean hasConstraint) {
      this.hasConstraint = hasConstraint;
   }

   public SQLName getSymbol() {
      return this.symbol;
   }

   public void setSymbol(SQLName symbol) {
      if (symbol != null) {
         if (this.getParent() != null) {
            symbol.setParent(this.getParent());
         } else {
            symbol.setParent(this);
         }
      }

      this.symbol = symbol;
   }

   public boolean isGlobal() {
      return this.global;
   }

   public void setGlobal(boolean global) {
      this.global = global;
   }

   public boolean isLocal() {
      return this.local;
   }

   public void setLocal(boolean local) {
      this.local = local;
   }

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

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

   public boolean isHashMapType() {
      return this.hashMapType;
   }

   public void setHashMapType(boolean hashMapType) {
      this.hashMapType = hashMapType;
   }

   public boolean isHashType() {
      return this.hashType;
   }

   public void setHashType(boolean hashType) {
      this.hashType = hashType;
   }

   public boolean isIndex() {
      return this.index;
   }

   public void setIndex(boolean index) {
      this.index = index;
   }

   public boolean isKey() {
      return this.key;
   }

   public void setKey(boolean key) {
      this.key = key;
   }

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

   public void setName(SQLName name) {
      if (name != null) {
         if (this.getParent() != null) {
            name.setParent(this.getParent());
         } else {
            name.setParent(this);
         }
      }

      this.name = name;
   }

   public SQLTableSource getTable() {
      return this.table;
   }

   public void setTable(SQLTableSource table) {
      if (table != null) {
         if (this.getParent() != null) {
            table.setParent(this.getParent());
         } else {
            table.setParent(this);
         }
      }

      this.table = table;
   }

   public List<SQLSelectOrderByItem> getColumns() {
      return this.columns;
   }

   public void setColumns(List<SQLSelectOrderByItem> columns) {
      this.columns = columns;
   }

   public boolean hasOptions() {
      return this.options != null;
   }

   public SQLIndexOptions getOptions() {
      if (null == this.options) {
         this.options = new SQLIndexOptions();
         this.options.setParent(this);
      }

      return this.options;
   }

   public SQLExpr getDbPartitionBy() {
      return this.dbPartitionBy;
   }

   public void setDbPartitionBy(SQLExpr dbPartitionBy) {
      if (dbPartitionBy != null) {
         if (this.getParent() != null) {
            dbPartitionBy.setParent(this.getParent());
         } else {
            dbPartitionBy.setParent(this);
         }
      }

      this.dbPartitionBy = dbPartitionBy;
   }

   public SQLExpr getTbPartitionBy() {
      return this.tbPartitionBy;
   }

   public void setTbPartitionBy(SQLExpr tbPartitionBy) {
      if (tbPartitionBy != null) {
         if (this.getParent() != null) {
            tbPartitionBy.setParent(this.getParent());
         } else {
            tbPartitionBy.setParent(this);
         }
      }

      this.tbPartitionBy = tbPartitionBy;
   }

   public SQLExpr getTbPartitions() {
      return this.tbPartitions;
   }

   public void setTbPartitions(SQLExpr tbPartitions) {
      if (tbPartitions != null) {
         if (this.getParent() != null) {
            tbPartitions.setParent(this.getParent());
         } else {
            tbPartitions.setParent(this);
         }
      }

      this.tbPartitions = tbPartitions;
   }

   public List<SQLName> getCovering() {
      return this.covering;
   }

   public void setCovering(List<SQLName> covering) {
      this.covering = covering;
   }

   public SQLName getAnalyzerName() {
      return this.analyzerName;
   }

   public void setAnalyzerName(SQLName analyzerName) {
      if (analyzerName != null) {
         if (this.getParent() != null) {
            analyzerName.setParent(this.getParent());
         } else {
            analyzerName.setParent(this);
         }
      }

      this.analyzerName = analyzerName;
   }

   public SQLName getIndexAnalyzerName() {
      return this.indexAnalyzerName;
   }

   public void setIndexAnalyzerName(SQLName indexAnalyzerName) {
      if (indexAnalyzerName != null) {
         if (this.getParent() != null) {
            indexAnalyzerName.setParent(this.getParent());
         } else {
            indexAnalyzerName.setParent(this);
         }
      }

      this.indexAnalyzerName = indexAnalyzerName;
   }

   public SQLName getQueryAnalyzerName() {
      return this.queryAnalyzerName;
   }

   public void setQueryAnalyzerName(SQLName queryAnalyzerName) {
      if (queryAnalyzerName != null) {
         if (this.getParent() != null) {
            queryAnalyzerName.setParent(this.getParent());
         } else {
            queryAnalyzerName.setParent(this);
         }
      }

      this.queryAnalyzerName = queryAnalyzerName;
   }

   public SQLName getWithDicName() {
      return this.withDicName;
   }

   public void setWithDicName(SQLName withDicName) {
      if (withDicName != null) {
         if (this.getParent() != null) {
            withDicName.setParent(this.getParent());
         } else {
            withDicName.setParent(this);
         }
      }

      this.withDicName = withDicName;
   }

   public List<SQLAssignItem> getCompatibleOptions() {
      return this.compatibleOptions;
   }

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

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

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

      visitor.endVisit(this);
   }

   public void cloneTo(SQLIndexDefinition definition) {
      SQLObject parent;
      if (definition.getParent() != null) {
         parent = definition.getParent();
      } else {
         parent = definition;
      }

      definition.hasConstraint = this.hasConstraint;
      if (this.symbol != null) {
         definition.symbol = this.symbol.clone();
         definition.symbol.setParent(parent);
      }

      definition.global = this.global;
      definition.local = this.local;
      definition.type = this.type;
      definition.hashMapType = this.hashMapType;
      definition.index = this.index;
      definition.key = this.key;
      if (this.name != null) {
         definition.name = this.name.clone();
         definition.name.setParent(parent);
      }

      if (this.table != null) {
         definition.table = this.table.clone();
         definition.table.setParent(parent);
      }

      for(SQLSelectOrderByItem item : this.columns) {
         SQLSelectOrderByItem item1 = item.clone();
         item1.setParent(parent);
         definition.columns.add(item1);
      }

      if (this.options != null) {
         this.options.cloneTo(definition.getOptions());
      }

      if (this.dbPartitionBy != null) {
         definition.dbPartitionBy = this.dbPartitionBy.clone();
         definition.dbPartitionBy.setParent(parent);
      }

      if (this.tbPartitionBy != null) {
         definition.tbPartitionBy = this.tbPartitionBy.clone();
         definition.tbPartitionBy.setParent(parent);
      }

      if (this.tbPartitions != null) {
         definition.tbPartitions = this.tbPartitions.clone();
         definition.tbPartitions.setParent(parent);
      }

      for(SQLName name : this.covering) {
         SQLName name1 = name.clone();
         name1.setParent(parent);
         definition.covering.add(name1);
      }

      if (this.analyzerName != null) {
         definition.analyzerName = this.analyzerName.clone();
         definition.analyzerName.setParent(parent);
      }

      if (this.indexAnalyzerName != null) {
         definition.indexAnalyzerName = this.indexAnalyzerName.clone();
         definition.indexAnalyzerName.setParent(parent);
      }

      if (this.withDicName != null) {
         definition.withDicName = this.withDicName.clone();
         definition.withDicName.setParent(parent);
      }

      if (this.queryAnalyzerName != null) {
         definition.queryAnalyzerName = this.queryAnalyzerName.clone();
         definition.queryAnalyzerName.setParent(parent);
      }

      for(SQLAssignItem item : this.compatibleOptions) {
         SQLAssignItem item2 = item.clone();
         item2.setParent(parent);
         definition.compatibleOptions.add(item2);
      }

   }

   public void addOption(String name, SQLExpr value) {
      SQLAssignItem assignItem = new SQLAssignItem(new SQLIdentifierExpr(name), value);
      if (this.getParent() != null) {
         assignItem.setParent(this.getParent());
      } else {
         assignItem.setParent(this);
      }

      this.getCompatibleOptions().add(assignItem);
   }

   public SQLExpr getOption(String name) {
      return name == null ? null : this.getOption(FnvHash.hashCode64(name));
   }

   public SQLExpr getOption(long hash64) {
      for(SQLAssignItem item : this.compatibleOptions) {
         SQLExpr target = item.getTarget();
         if (target instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)target).hashCode64() == hash64) {
            return item.getValue();
         }
      }

      if (null == this.options) {
         return null;
      } else if (hash64 == FnvHash.Constants.KEY_BLOCK_SIZE) {
         return this.options.getKeyBlockSize();
      } else if (hash64 == FnvHash.Constants.ALGORITHM) {
         if (this.options.getAlgorithm() != null) {
            return new SQLIdentifierExpr(this.options.getAlgorithm());
         } else {
            return null;
         }
      } else if (hash64 == FnvHash.hashCode64("LOCK")) {
         if (this.options.getLock() != null) {
            return new SQLIdentifierExpr(this.options.getLock());
         } else {
            return null;
         }
      } else {
         for(SQLAssignItem item : this.options.getOtherOptions()) {
            SQLExpr target = item.getTarget();
            if (target instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)target).hashCode64() == hash64) {
               return item.getValue();
            }
         }

         return null;
      }
   }

   public String getDistanceMeasure() {
      SQLExpr expr = this.getOption(FnvHash.Constants.DISTANCEMEASURE);
      return expr == null ? null : expr.toString();
   }

   public String getAlgorithm() {
      if (this.options != null && this.options.getAlgorithm() != null) {
         return this.options.getAlgorithm();
      } else {
         SQLExpr expr = this.getOption(FnvHash.Constants.ALGORITHM);
         return expr == null ? null : expr.toString();
      }
   }
}
