package com.chenyang.druid.sql.parser;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLPartitionBy;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLConstraint;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLTableElement;
import com.chenyang.druid.sql.dialect.oracle.parser.OracleSelectParser;
import com.chenyang.druid.util.FnvHash;
import java.util.List;

public class SQLCreateTableParser extends SQLDDLParser {
   public SQLCreateTableParser(String sql) {
      super(sql);
   }

   public SQLCreateTableParser(SQLExprParser exprParser) {
      super(exprParser);
      this.dbType = exprParser.dbType;
   }

   public SQLCreateTableStatement parseCreateTable() {
      List<String> comments = null;
      if (this.lexer.isKeepComments() && this.lexer.hasComment()) {
         comments = this.lexer.readAndResetComments();
      }

      SQLCreateTableStatement stmt = this.parseCreateTable(true);
      if (comments != null) {
         stmt.addBeforeComment(comments);
      }

      return stmt;
   }

   public SQLCreateTableStatement parseCreateTable(boolean acceptCreate) {
      SQLCreateTableStatement createTable = this.newCreateStatement();
      createTable.setDbType(this.getDbType());
      if (acceptCreate) {
         if (this.lexer.hasComment() && this.lexer.isKeepComments()) {
            createTable.addBeforeComment(this.lexer.readAndResetComments());
         }

         this.accept(Token.CREATE);
      }

      if (this.lexer.identifierEquals("GLOBAL")) {
         this.lexer.nextToken();
         if (!this.lexer.identifierEquals("TEMPORARY")) {
            throw new ParserException("syntax error " + this.lexer.info());
         }

         this.lexer.nextToken();
         createTable.setType(SQLCreateTableStatement.Type.GLOBAL_TEMPORARY);
      } else if (this.lexer.token == Token.IDENTIFIER && this.lexer.stringVal().equalsIgnoreCase("LOCAL")) {
         this.lexer.nextToken();
         if (this.lexer.token != Token.IDENTIFIER || !this.lexer.stringVal().equalsIgnoreCase("TEMPORAY")) {
            throw new ParserException("syntax error. " + this.lexer.info());
         }

         this.lexer.nextToken();
         createTable.setType(SQLCreateTableStatement.Type.LOCAL_TEMPORARY);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.DIMENSION)) {
         this.lexer.nextToken();
         createTable.setDimension(true);
      }

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

      createTable.setName(this.exprParser.name());
      if (this.lexer.token == Token.LPAREN) {
         this.lexer.nextToken();

         do {
            Token token = this.lexer.token;
            if (this.lexer.identifierEquals(FnvHash.Constants.SUPPLEMENTAL) && DbType.oracle == this.dbType) {
               SQLTableElement element = this.parseCreateTableSupplementalLogingProps();
               element.setParent(createTable);
               createTable.getTableElementList().add(element);
            } else if (token != Token.IDENTIFIER && token != Token.LITERAL_ALIAS) {
               if (token != Token.PRIMARY && token != Token.UNIQUE && token != Token.CHECK && token != Token.CONSTRAINT && token != Token.FOREIGN) {
                  if (token == Token.TABLESPACE) {
                     throw new ParserException("TODO " + this.lexer.info());
                  }

                  SQLColumnDefinition column = this.exprParser.parseColumn();
                  createTable.getTableElementList().add(column);
               } else {
                  SQLConstraint constraint = this.exprParser.parseConstaint();
                  constraint.setParent(createTable);
                  createTable.getTableElementList().add((SQLTableElement)constraint);
               }
            } else {
               SQLColumnDefinition column = this.exprParser.parseColumn(createTable);
               column.setParent(createTable);
               createTable.getTableElementList().add(column);
            }

            if (this.lexer.token != Token.COMMA) {
               break;
            }

            this.lexer.nextToken();
         } while(this.lexer.token != Token.RPAREN);

         this.accept(Token.RPAREN);
         if (this.lexer.identifierEquals(FnvHash.Constants.INHERITS)) {
            this.lexer.nextToken();
            this.accept(Token.LPAREN);
            SQLName inherits = this.exprParser.name();
            createTable.setInherits(new SQLExprTableSource(inherits));
            this.accept(Token.RPAREN);
         }
      }

      if (this.lexer.token == Token.AS) {
         this.lexer.nextToken();
         SQLSelect select = null;
         if (DbType.oracle == this.dbType) {
            select = (new OracleSelectParser(this.exprParser)).select();
         } else {
            select = this.createSQLSelectParser().select();
         }

         createTable.setSelect(select);
      }

      if (this.lexer.token == Token.WITH && DbType.postgresql == this.dbType) {
         this.lexer.nextToken();
         this.accept(Token.LPAREN);
         this.parseAssignItems(createTable.getTableOptions(), createTable, false);
         this.accept(Token.RPAREN);
      }

      if (this.lexer.token == Token.TABLESPACE) {
         this.lexer.nextToken();
         createTable.setTablespace(this.exprParser.name());
      }

      if (this.lexer.token() == Token.PARTITION) {
         SQLPartitionBy partitionClause = this.parsePartitionBy();
         createTable.setPartitioning(partitionClause);
      }

      this.parseCreateTableRest(createTable);
      return createTable;
   }

   protected void parseCreateTableRest(SQLCreateTableStatement stmt) {
   }

   public SQLPartitionBy parsePartitionBy() {
      return null;
   }

   public SQLTableElement parseCreateTableSupplementalLogingProps() {
      throw new ParserException("TODO " + this.lexer.info());
   }

   protected SQLCreateTableStatement newCreateStatement() {
      return new SQLCreateTableStatement(this.getDbType());
   }
}
