package com.alibaba.druid.sql.dialect.hive.parser;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLAssignItem;
import com.alibaba.druid.sql.ast.statement.SQLCreateContextStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateDirectoryStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateDomainStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExternalRecordFormat;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLCreateTableParser;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.util.FnvHash;
import java.util.List;

public class HiveCreateParser extends SQLStatementParser {
   public HiveCreateParser(SQLExprParser exprParser) {
      super(exprParser);
   }

   public HiveCreateParser(Lexer lexer) {
      super((SQLExprParser)(new HiveExprParser(lexer)));
   }

   public SQLStatement parseCreate() {
      char markChar = this.lexer.current();
      int markBp = this.lexer.bp();
      List<String> comments = null;
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         comments = this.lexer.readAndResetComments();
      }

      this.accept(Token.CREATE);
      boolean global = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.GLOBAL)) {
         this.lexer.nextToken();
         global = true;
      }

      boolean temporary = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.TEMPORARY) || this.lexer.token() == Token.TEMPORARY) {
         this.lexer.nextToken();
         temporary = true;
      }

      boolean nonclustered = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.NONCLUSTERED)) {
         this.lexer.nextToken();
         nonclustered = true;
      }

      boolean external = false;
      if (this.lexer.identifierEquals(FnvHash.Constants.EXTERNAL)) {
         this.lexer.nextToken();
         external = true;
      }

      Token token = this.lexer.token();
      switch (this.lexer.token()) {
         case TABLE:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            SQLCreateTableParser createTableParser = this.getSQLCreateTableParser();
            SQLCreateTableStatement stmt = createTableParser.parseCreateTable();
            if (temporary) {
               if (global) {
                  stmt.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY);
               } else {
                  stmt.setType(SQLCreateTableStatement.Type.TEMPORARY);
               }
            }

            if (comments != null) {
               stmt.addBeforeComment(comments);
            }

            return stmt;
         case INDEX:
         case NOT:
         case UNIQUE:
            SQLCreateIndexStatement createIndex = this.parseCreateIndex(false);
            if (nonclustered) {
               createIndex.setType("NONCLUSTERED");
            }

            return createIndex;
         case SEQUENCE:
            return this.parseCreateSequence(false);
         case DATABASE:
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("LINK")) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateDbLink();
            }

            this.lexer.reset(markBp, markChar, Token.CREATE);
            SQLStatement stmt2 = this.parseCreateDatabase();
            if (comments != null) {
               stmt2.addBeforeComment(comments);
               List<String> var12 = null;
            }

            return stmt2;
         case SCHEMA:
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("LINK")) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateDbLink();
            }

            this.lexer.reset(markBp, markChar, Token.CREATE);
            SQLStatement stmt3 = this.parseCreateSchema();
            if (comments != null) {
               stmt3.addBeforeComment(comments);
               List<String> var11 = null;
            }

            return stmt3;
         case USER:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateUser();
         case FUNCTION:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            SQLStatement createFunct = this.parseCreateFunction();
            return createFunct;
         case TABLESPACE:
            this.lexer.reset(markBp, markChar, Token.CREATE);
            return this.parseCreateTableSpace();
         default:
            if (token == Token.OR) {
               this.lexer.nextToken();
               this.accept(Token.REPLACE);
               if (this.lexer.identifierEquals(FnvHash.Constants.FORCE)) {
                  this.lexer.nextToken();
               }

               if (this.lexer.token() == Token.PROCEDURE) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateProcedure();
               } else if (this.lexer.token() == Token.VIEW) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateViewA();
               } else if (this.lexer.token() == Token.TRIGGER) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateTrigger();
               } else if (this.lexer.token() == Token.FUNCTION) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateFunction();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.PACKAGE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreatePackage();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.TYPE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateType();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.PUBLIC)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateSynonym();
               } else if (this.lexer.identifierEquals(FnvHash.Constants.SYNONYM)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateSynonym();
               } else if (this.lexer.token() != Token.INDEX && !this.lexer.identifierEquals("CLUSTER") && this.lexer.token() != Token.NOT && this.lexer.token() != Token.UNIQUE && !this.lexer.identifierEquals("SPATIAL") && !this.lexer.identifierEquals("BITMAP")) {
                  if (this.lexer.identifierEquals("CONTEXT")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateContextStatement contextStatement = this.parseCreateContext();
                     return contextStatement;
                  } else if (this.lexer.identifierEquals("DIRECTORY")) {
                     this.lexer.reset(markBp, markChar, Token.CREATE);
                     SQLCreateDirectoryStatement createDirectory = this.parseCreateDirectory();
                     return createDirectory;
                  } else {
                     throw new ParserException("TODO " + this.lexer.info());
                  }
               } else {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateIndexStatement createIndex4 = this.parseCreateIndex(true);
                  if (nonclustered) {
                     createIndex4.setType("NONCLUSTERED");
                  }

                  return createIndex4;
               }
            } else if (this.lexer.identifierEquals(FnvHash.Constants.PUBLIC)) {
               this.lexer.nextToken();
               if (this.lexer.identifierEquals("SYNONYM")) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateSynonym();
               } else {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreateDbLink();
               }
            } else if (this.lexer.identifierEquals("SHARE")) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateDbLink();
            } else if (this.lexer.identifierEquals("SYNONYM")) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateSynonym();
            } else if (token == Token.VIEW) {
               return this.parseCreateViewA();
            } else if (token == Token.MATERIALIZED) {
               return this.parseCreateViewB();
            } else if (token == Token.TRIGGER) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateTrigger();
            } else if (token == Token.PROCEDURE) {
               SQLCreateProcedureStatement stmt5 = this.parseCreateProcedure();
               stmt5.setCreate(true);
               return stmt5;
            } else if (this.lexer.identifierEquals(FnvHash.Constants.BITMAP)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateIndex(true);
            } else if (this.lexer.identifierEquals(FnvHash.Constants.TYPE)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateType();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.EXTERNAL)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               SQLCreateTableStatement createTable = this.parseCreateTable();
               if (comments != null) {
                  createTable.addBeforeComment(comments);
                  List<String> var13 = null;
               }

               return createTable;
            } else if (this.lexer.identifierEquals(FnvHash.Constants.TABLEGROUP)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateTableGroup();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.DIMENSION)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateTable();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.ROLE)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateRole();
            } else if (this.lexer.identifierEquals(FnvHash.Constants.RESOURCE)) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateResourceGroup();
            } else if (this.lexer.token() == Token.FOREIGN) {
               this.lexer.reset(markBp, markChar, Token.CREATE);
               return this.parseCreateTable();
            } else if (!this.lexer.identifierEquals("CLUSTER") && !this.lexer.identifierEquals("SPATIAL") && !this.lexer.identifierEquals("BITMAP") && !this.lexer.identifierEquals("CONTEXT")) {
               if (this.lexer.identifierEquals("DOMAIN")) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateDomainStatement createDomain = this.parseCreateDomain();
                  return createDomain;
               } else if (this.lexer.identifierEquals("DIRECTORY")) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateDirectoryStatement createDirectory = this.parseCreateDirectory();
                  return createDirectory;
               } else if (this.lexer.identifierEquals(FnvHash.Constants.PACKAGE)) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  return this.parseCreatePackage();
               } else {
                  throw new ParserException("TODO " + this.lexer.info());
               }
            } else {
               this.lexer.nextToken();
               this.lexer.nextToken();
               if (this.lexer.token() == Token.USING) {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateContextStatement contextStatement = this.parseCreateContext();
                  return contextStatement;
               } else {
                  this.lexer.reset(markBp, markChar, Token.CREATE);
                  SQLCreateIndexStatement createIndex6 = this.parseCreateIndex(true);
                  if (nonclustered) {
                     createIndex6.setType("NONCLUSTERED");
                  }

                  return createIndex6;
               }
            }
      }
   }

   public SQLCreateTableStatement parseCreateViewA() {
      HiveCreateTableParser parser = new HiveCreateTableParser(this.exprParser);
      return parser.parseCreateViewA();
   }

   public SQLCreateTableStatement parseCreateViewB() {
      HiveCreateTableParser parser = new HiveCreateTableParser(this.exprParser);
      return parser.parseCreateViewB();
   }

   public SQLCreateFunctionStatement parseCreateFunction() {
      return this.parseHiveCreateFunction();
   }

   public SQLCreateTableStatement parseCreateTable() {
      SQLCreateTableParser parser = new HiveCreateTableParser(this.exprParser);
      return parser.parseCreateTable();
   }

   public SQLCreateIndexStatement parseCreateIndex(boolean acceptCreate) {
      if (acceptCreate) {
         this.accept(Token.CREATE);
      }

      this.accept(Token.INDEX);
      SQLCreateIndexStatement stmt = new SQLCreateIndexStatement(this.dbType);
      stmt.setName(this.exprParser.name());
      this.accept(Token.ON);
      if (this.lexer.token() == Token.TABLE) {
         this.lexer.nextToken();
      }

      stmt.setTable(this.exprParser.name());
      this.accept(Token.LPAREN);

      while(true) {
         SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem();
         item.setParent(stmt);
         stmt.addItem(item);
         if (this.lexer.token() != Token.COMMA) {
            this.accept(Token.RPAREN);
            if (this.lexer.token() == Token.AS) {
               this.lexer.nextToken();
               String indexType = this.lexer.stringVal();
               this.accept(Token.LITERAL_CHARS);
               stmt.setType(indexType);
            }

            if (this.lexer.token() == Token.WITH) {
               this.lexer.nextToken();
               this.acceptIdentifier("DEFERRED");
               this.acceptIdentifier("REBUILD");
               stmt.setDeferedRebuild(true);
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.IDXPROPERTIES)) {
               this.lexer.nextToken();
               this.exprParser.parseAssignItem(stmt.getProperties(), stmt);
            }

            if (this.lexer.token() == Token.IN) {
               this.lexer.nextToken();
               this.accept(Token.TABLE);
               SQLName inTable = this.exprParser.name();
               stmt.setIn(inTable);
            }

            if (this.lexer.token() == Token.ROW || this.lexer.identifierEquals(FnvHash.Constants.ROW)) {
               SQLExternalRecordFormat format = this.getExprParser().parseRowFormat();
               stmt.setRowFormat(format);
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.STORED)) {
               this.lexer.nextToken();
               this.accept(Token.AS);
               SQLName name = this.exprParser.name();
               stmt.setStoredAs(name);
            }

            if (this.lexer.identifierEquals(FnvHash.Constants.TBLPROPERTIES)) {
               this.lexer.nextToken();
               this.exprParser.parseAssignItem(stmt.getTableProperties(), stmt);
            }

            return stmt;
         }

         this.lexer.nextToken();
      }
   }

   public SQLStatement parseCreateSchema() {
      return this.parseCreateDatabase();
   }

   public SQLStatement parseCreateDatabase() {
      SQLCreateDatabaseStatement stmt = new SQLCreateDatabaseStatement(this.dbType);
      if (this.lexer.hasComment() && this.lexer.isKeepComments()) {
         stmt.addBeforeComment(this.lexer.readAndResetComments());
      }

      if (this.lexer.token() == Token.CREATE) {
         this.lexer.nextToken();
      }

      if (this.lexer.token() == Token.SCHEMA && this.dbType == DbType.hive) {
         this.lexer.nextToken();
      } else {
         this.accept(Token.DATABASE);
      }

      if (this.lexer.token() == Token.IF || this.lexer.identifierEquals("IF")) {
         this.lexer.nextToken();
         this.accept(Token.NOT);
         this.accept(Token.EXISTS);
         stmt.setIfNotExists(true);
      }

      stmt.setName(this.exprParser.name());
      if (this.lexer.token() == Token.COMMENT) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr comment = this.exprParser.expr();
         stmt.setComment(comment);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.LOCATION)) {
         this.lexer.nextToken();
         SQLExpr location = this.exprParser.expr();
         stmt.setLocation(location);
      }

      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         if (!this.lexer.identifierEquals(FnvHash.Constants.DBPROPERTIES)) {
            throw new ParserException("TODO " + this.lexer.info());
         }

         this.lexer.nextToken();
         this.accept(Token.LPAREN);

         while(true) {
            SQLAssignItem assignItem = this.exprParser.parseAssignItem();
            assignItem.setParent(stmt);
            stmt.getDbProperties().add(assignItem);
            if (this.lexer.token() != Token.COMMA) {
               this.accept(Token.RPAREN);
               break;
            }

            this.lexer.nextToken();
         }
      }

      if (this.lexer.token() == Token.COMMENT) {
         this.lexer.nextToken();
         if (this.lexer.token() == Token.EQ) {
            this.lexer.nextToken();
         }

         SQLExpr comment = this.exprParser.expr();
         stmt.setComment(comment);
      }

      return stmt;
   }
}
