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

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLCommentHint;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterCharacter;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.ast.statement.SQLUnique;
import com.alibaba.druid.sql.dialect.ads.visitor.AdsOutputVisitor;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExprImpl;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlShowColumnOutpuVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MySqlCreateTableStatement extends SQLCreateTableStatement implements MySqlStatement {
   private List<SQLCommentHint> hints = new ArrayList();
   private List<SQLCommentHint> optionHints = new ArrayList();
   private SQLName tableGroup;
   protected SQLExpr dbPartitionBy;
   protected SQLExpr dbPartitions;
   protected SQLExpr tablePartitionBy;
   protected SQLExpr tablePartitions;
   protected MySqlExtPartition exPartition;
   protected SQLName storedBy;
   protected SQLName distributeByType;
   protected List<SQLName> distributeBy = new ArrayList();
   protected boolean isBroadCast;
   protected Map<String, SQLName> with = new HashMap(3);
   protected SQLName archiveBy;
   protected Boolean withData;

   public MySqlCreateTableStatement() {
      super(DbType.mysql);
   }

   public List<SQLCommentHint> getHints() {
      return this.hints;
   }

   public void setHints(List<SQLCommentHint> hints) {
      this.hints = hints;
   }

   /** @deprecated */
   @Deprecated
   public SQLSelect getQuery() {
      return this.select;
   }

   /** @deprecated */
   @Deprecated
   public void setQuery(SQLSelect query) {
      this.select = query;
   }

   protected void accept0(SQLASTVisitor visitor) {
      if (visitor instanceof MySqlASTVisitor) {
         this.accept0((MySqlASTVisitor)visitor);
      } else if (visitor instanceof AdsOutputVisitor) {
         this.accept0((AdsOutputVisitor)visitor);
      } else {
         super.accept0(visitor);
      }

   }

   public void accept0(AdsOutputVisitor visitor) {
      if (visitor.visit((MySqlCreateTableStatement)this)) {
         for(int i = 0; i < this.hints.size(); ++i) {
            SQLCommentHint hint = (SQLCommentHint)this.hints.get(i);
            if (hint != null) {
               hint.accept(visitor);
            }
         }

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

         for(int i = 0; i < this.tableElementList.size(); ++i) {
            SQLTableElement element = (SQLTableElement)this.tableElementList.get(i);
            if (element != null) {
               element.accept(visitor);
            }
         }

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

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

      visitor.endVisit(this);
   }

   public void accept0(MySqlASTVisitor visitor) {
      if (visitor.visit(this)) {
         for(int i = 0; i < this.hints.size(); ++i) {
            SQLCommentHint hint = (SQLCommentHint)this.hints.get(i);
            if (hint != null) {
               hint.accept(visitor);
            }
         }

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

         for(int i = 0; i < this.tableElementList.size(); ++i) {
            SQLTableElement element = (SQLTableElement)this.tableElementList.get(i);
            if (element != null) {
               element.accept(visitor);
            }
         }

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

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

      visitor.endVisit(this);
   }

   public List<SQLCommentHint> getOptionHints() {
      return this.optionHints;
   }

   public void setOptionHints(List<SQLCommentHint> optionHints) {
      this.optionHints = optionHints;
   }

   public SQLName getTableGroup() {
      return this.tableGroup;
   }

   public void setTableGroup(SQLName tableGroup) {
      this.tableGroup = tableGroup;
   }

   public void setTableGroup(String tableGroup) {
      if (StringUtils.isEmpty(tableGroup)) {
         this.tableGroup = null;
      } else {
         this.tableGroup = new SQLIdentifierExpr(tableGroup);
      }

   }

   public void simplify() {
      this.tableOptions.clear();
      this.tblProperties.clear();
      super.simplify();
   }

   public void showCoumns(Appendable out) throws IOException {
      this.accept(new MySqlShowColumnOutpuVisitor(out));
   }

   public List<MySqlKey> getMysqlKeys() {
      List<MySqlKey> mySqlKeys = new ArrayList();

      for(SQLTableElement element : this.getTableElementList()) {
         if (element instanceof MySqlKey) {
            mySqlKeys.add((MySqlKey)element);
         }
      }

      return mySqlKeys;
   }

   public List<MySqlTableIndex> getMysqlIndexes() {
      List<MySqlTableIndex> indexList = new ArrayList();

      for(SQLTableElement element : this.getTableElementList()) {
         if (element instanceof MySqlTableIndex) {
            indexList.add((MySqlTableIndex)element);
         }
      }

      return indexList;
   }

   public boolean apply(MySqlRenameTableStatement x) {
      for(MySqlRenameTableStatement.Item item : x.getItems()) {
         if (this.apply(item)) {
            return true;
         }
      }

      return false;
   }

   protected boolean alterApply(SQLAlterTableItem item) {
      if (item instanceof MySqlAlterTableAlterColumn) {
         return this.apply((MySqlAlterTableAlterColumn)item);
      } else if (item instanceof MySqlAlterTableChangeColumn) {
         return this.apply((MySqlAlterTableChangeColumn)item);
      } else if (item instanceof SQLAlterCharacter) {
         return this.apply((SQLAlterCharacter)item);
      } else if (item instanceof MySqlAlterTableModifyColumn) {
         return this.apply((MySqlAlterTableModifyColumn)item);
      } else {
         return item instanceof MySqlAlterTableOption ? this.apply((MySqlAlterTableOption)item) : super.alterApply(item);
      }
   }

   public boolean apply(SQLAlterTableAddIndex item) {
      SQLName name = item.getIndexDefinition().getName();
      if (name != null) {
         long nameHashCode = name.nameHashCode64();

         for(int i = 0; i < this.tableElementList.size(); ++i) {
            SQLTableElement e = (SQLTableElement)this.tableElementList.get(i);
            if (e instanceof MySqlTableIndex) {
               SQLName name1 = ((MySqlTableIndex)e).getName();
               if (name1 != null && name1.nameHashCode64() == nameHashCode) {
                  return false;
               }
            }
         }
      }

      if (item.isUnique()) {
         MySqlUnique x = new MySqlUnique();
         item.cloneTo((MySqlKey)x);
         x.setParent(this);
         this.tableElementList.add(x);
         return true;
      } else if (item.isKey()) {
         MySqlKey x = new MySqlKey();
         item.cloneTo(x);
         x.setParent(this);
         this.tableElementList.add(x);
         return true;
      } else {
         MySqlTableIndex x = new MySqlTableIndex();
         item.cloneTo(x);
         x.setParent(this);
         this.tableElementList.add(x);
         return true;
      }
   }

   public boolean apply(MySqlAlterTableOption item) {
      this.addOption(item.getName(), (SQLExpr)item.getValue());
      return true;
   }

   public boolean apply(SQLAlterCharacter item) {
      SQLExpr charset = item.getCharacterSet();
      if (charset != null) {
         this.addOption("CHARACTER SET", charset);
      }

      SQLExpr collate = item.getCollate();
      if (collate != null) {
         this.addOption("COLLATE", collate);
      }

      return true;
   }

   public boolean apply(MySqlRenameTableStatement.Item item) {
      if (!SQLUtils.nameEquals(item.getName(), this.getName())) {
         return false;
      } else {
         this.setName(item.getTo().clone());
         return true;
      }
   }

   public boolean apply(MySqlAlterTableAlterColumn x) {
      int columnIndex = this.columnIndexOf(x.getColumn());
      if (columnIndex == -1) {
         return false;
      } else {
         SQLExpr defaultExpr = x.getDefaultExpr();
         SQLColumnDefinition column = (SQLColumnDefinition)this.tableElementList.get(columnIndex);
         if (x.isDropDefault()) {
            column.setDefaultExpr((SQLExpr)null);
         } else if (defaultExpr != null) {
            column.setDefaultExpr(defaultExpr);
         }

         return true;
      }
   }

   public boolean apply(MySqlAlterTableChangeColumn item) {
      SQLName columnName = item.getColumnName();
      int columnIndex = this.columnIndexOf(columnName);
      if (columnIndex == -1) {
         return false;
      } else {
         int afterIndex = this.columnIndexOf(item.getAfterColumn());
         int beforeIndex = this.columnIndexOf(item.getFirstColumn());
         int insertIndex = -1;
         if (beforeIndex != -1) {
            insertIndex = beforeIndex;
         } else if (afterIndex != -1) {
            insertIndex = afterIndex + 1;
         } else if (item.isFirst()) {
            insertIndex = 0;
         }

         SQLColumnDefinition column = item.getNewColumnDefinition().clone();
         column.setParent(this);
         if (insertIndex != -1 && insertIndex != columnIndex) {
            if (insertIndex > columnIndex) {
               this.tableElementList.add(insertIndex, column);
               this.tableElementList.remove(columnIndex);
            } else {
               this.tableElementList.remove(columnIndex);
               this.tableElementList.add(insertIndex, column);
            }
         } else {
            this.tableElementList.set(columnIndex, column);
         }

         for(int i = 0; i < this.tableElementList.size(); ++i) {
            SQLTableElement e = (SQLTableElement)this.tableElementList.get(i);
            if (e instanceof MySqlTableIndex) {
               ((MySqlTableIndex)e).applyColumnRename(columnName, column);
            } else if (e instanceof SQLUnique) {
               SQLUnique unique = (SQLUnique)e;
               unique.applyColumnRename(columnName, column);
            }
         }

         return true;
      }
   }

   public boolean apply(MySqlAlterTableModifyColumn item) {
      SQLColumnDefinition column = item.getNewColumnDefinition().clone();
      SQLName columnName = column.getName();
      int columnIndex = this.columnIndexOf(columnName);
      if (columnIndex == -1) {
         return false;
      } else {
         int afterIndex = this.columnIndexOf(item.getAfterColumn());
         int beforeIndex = this.columnIndexOf(item.getFirstColumn());
         int insertIndex = -1;
         if (beforeIndex != -1) {
            insertIndex = beforeIndex;
         } else if (afterIndex != -1) {
            insertIndex = afterIndex + 1;
         }

         if (item.isFirst()) {
            insertIndex = 0;
         }

         column.setParent(this);
         if (insertIndex != -1 && insertIndex != columnIndex) {
            if (insertIndex > columnIndex) {
               this.tableElementList.add(insertIndex, column);
               this.tableElementList.remove(columnIndex);
            } else {
               this.tableElementList.remove(columnIndex);
               this.tableElementList.add(insertIndex, column);
            }

            for(int i = 0; i < this.tableElementList.size(); ++i) {
               SQLTableElement e = (SQLTableElement)this.tableElementList.get(i);
               if (e instanceof MySqlTableIndex) {
                  ((MySqlTableIndex)e).applyColumnRename(columnName, column);
               } else if (e instanceof SQLUnique) {
                  SQLUnique unique = (SQLUnique)e;
                  unique.applyColumnRename(columnName, column);
               }
            }

            return true;
         } else {
            this.tableElementList.set(columnIndex, column);
            return true;
         }
      }
   }

   public void cloneTo(MySqlCreateTableStatement x) {
      super.cloneTo(x);
      if (this.partitioning != null) {
         x.setPartitioning(this.partitioning.clone());
      }

      for(SQLCommentHint hint : this.hints) {
         SQLCommentHint h2 = hint.clone();
         h2.setParent(x);
         x.hints.add(h2);
      }

      for(SQLCommentHint hint : this.optionHints) {
         SQLCommentHint h2 = hint.clone();
         h2.setParent(x);
         x.optionHints.add(h2);
      }

      if (this.like != null) {
         x.setLike(this.like.clone());
      }

      if (this.tableGroup != null) {
         x.setTableGroup(this.tableGroup.clone());
      }

      if (this.dbPartitionBy != null) {
         x.setDbPartitionBy(this.dbPartitionBy.clone());
      }

      if (this.dbPartitions != null) {
         x.setDbPartitionBy(this.dbPartitions.clone());
      }

      if (this.tablePartitionBy != null) {
         x.setTablePartitionBy(this.tablePartitionBy.clone());
      }

      if (this.tablePartitions != null) {
         x.setTablePartitions(this.tablePartitions.clone());
      }

      if (this.exPartition != null) {
         x.setExPartition(this.exPartition.clone());
      }

      if (this.archiveBy != null) {
         x.setArchiveBy(this.archiveBy.clone());
      }

      if (this.distributeByType != null) {
         x.setDistributeByType(this.distributeByType.clone());
      }

      if (this.distributeByType != null) {
         for(SQLName sqlName : this.distributeBy) {
            x.getDistributeBy().add(sqlName.clone());
         }
      }

   }

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

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

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

      this.dbPartitionBy = x;
   }

   public SQLExpr getTablePartitionBy() {
      return this.tablePartitionBy;
   }

   public void setTablePartitionBy(SQLExpr x) {
      if (x != null) {
         x.setParent(this);
      }

      this.tablePartitionBy = x;
   }

   public SQLName getDistributeByType() {
      return this.distributeByType;
   }

   public void setDistributeByType(SQLName distributeByType) {
      this.distributeByType = distributeByType;
   }

   public List<SQLName> getDistributeBy() {
      return this.distributeBy;
   }

   public SQLExpr getTbpartitions() {
      return this.tablePartitions;
   }

   public SQLExpr getTablePartitions() {
      return this.tablePartitions;
   }

   public void setTablePartitions(SQLExpr x) {
      this.tablePartitions = x;
   }

   public SQLExpr getDbpartitions() {
      return this.dbPartitions;
   }

   public void setDbPartitions(SQLExpr x) {
      if (x != null) {
         x.setParent(this);
      }

      this.dbPartitions = x;
   }

   public MySqlExtPartition getExtPartition() {
      return this.exPartition;
   }

   public void setExPartition(MySqlExtPartition x) {
      if (x != null) {
         x.setParent(this);
      }

      this.exPartition = x;
   }

   public SQLExpr getDbPartitions() {
      return this.dbPartitions;
   }

   public SQLName getStoredBy() {
      return this.storedBy;
   }

   public void setStoredBy(SQLName storedBy) {
      this.storedBy = storedBy;
   }

   public Map<String, SQLName> getWith() {
      return this.with;
   }

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

   public void setBroadCast(boolean broadCast) {
      this.isBroadCast = broadCast;
   }

   public SQLName getArchiveBy() {
      return this.archiveBy;
   }

   public void setArchiveBy(SQLName archiveBy) {
      this.archiveBy = archiveBy;
   }

   public Boolean getWithData() {
      return this.withData;
   }

   public void setWithData(Boolean withData) {
      this.withData = withData;
   }

   public static class TableSpaceOption extends MySqlExprImpl {
      private SQLName name;
      private SQLExpr storage;

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

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

         this.name = name;
      }

      public SQLExpr getStorage() {
         return this.storage;
      }

      public void setStorage(SQLExpr storage) {
         if (storage != null) {
            storage.setParent(this);
         }

         this.storage = storage;
      }

      public void accept0(MySqlASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.getName());
            this.acceptChild(visitor, this.getStorage());
         }

         visitor.endVisit(this);
      }

      public TableSpaceOption clone() {
         TableSpaceOption x = new TableSpaceOption();
         if (this.name != null) {
            x.setName(this.name.clone());
         }

         if (this.storage != null) {
            x.setStorage(this.storage.clone());
         }

         return x;
      }

      public List<SQLObject> getChildren() {
         return null;
      }
   }
}
