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

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlLexer;
import com.alibaba.druid.sql.parser.CharTypes;
import com.alibaba.druid.sql.parser.Keywords;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLParserFeature;
import com.alibaba.druid.sql.parser.SymbolTable;
import com.alibaba.druid.sql.parser.Token;
import java.util.HashMap;
import java.util.Map;

public class HiveLexer extends Lexer {
   public static final Keywords DEFAULT_HIVE_KEYWORDS;

   public HiveLexer(String input) {
      super(input);
      this.skipComment = true;
      this.keepComments = true;
      this.dbType = DbType.hive;
      this.features |= SQLParserFeature.SupportUnicodeCodePoint.mask;
      super.keywords = DEFAULT_HIVE_KEYWORDS;
   }

   public HiveLexer(String input, SQLParserFeature... features) {
      super(input);
      this.dbType = DbType.hive;
      this.skipComment = true;
      this.keepComments = true;
      super.keywords = DEFAULT_HIVE_KEYWORDS;
      this.features |= SQLParserFeature.SupportUnicodeCodePoint.mask;

      for(SQLParserFeature feature : features) {
         this.config(feature, true);
      }

   }

   public void scanIdentifier() {
      this.hash_lower = 0L;
      this.hash = 0L;
      char first = this.ch;
      if (this.ch == '`') {
         this.mark = this.pos;
         this.bufPos = 1;
         int startPos = this.pos + 1;
         int quoteIndex = this.text.indexOf(96, startPos);
         if (quoteIndex == -1) {
            throw new ParserException("illegal identifier. " + this.info());
         } else {
            this.hash_lower = -3750763034362895579L;
            this.hash = -3750763034362895579L;

            for(int i = startPos; i < quoteIndex; ++i) {
               char ch = this.text.charAt(i);
               this.hash_lower ^= (long)(ch >= 'A' && ch <= 'Z' ? ch + 32 : ch);
               this.hash_lower *= 1099511628211L;
               this.hash ^= (long)ch;
               this.hash *= 1099511628211L;
            }

            this.stringVal = MySqlLexer.quoteTable.addSymbol(this.text, this.pos, quoteIndex + 1 - this.pos, this.hash);
            this.pos = quoteIndex + 1;
            this.ch = this.charAt(this.pos);
            this.token = Token.IDENTIFIER;
         }
      } else {
         boolean firstFlag = CharTypes.isFirstIdentifierChar(first);
         if (!firstFlag) {
            throw new ParserException("illegal identifier. " + this.info());
         } else {
            this.hash_lower = -3750763034362895579L;
            this.hash = -3750763034362895579L;
            this.hash_lower ^= (long)(this.ch >= 'A' && this.ch <= 'Z' ? this.ch + 32 : this.ch);
            this.hash_lower *= 1099511628211L;
            this.hash ^= (long)this.ch;
            this.hash *= 1099511628211L;
            this.mark = this.pos;
            this.bufPos = 1;
            char ch = 0;

            while(true) {
               char c0 = ch;
               ch = this.charAt(++this.pos);
               if (!CharTypes.isIdentifierChar(ch)) {
                  if (ch != '（' && ch != '）' || c0 <= 256) {
                     this.ch = this.charAt(this.pos);
                     if (this.bufPos == 1) {
                        switch (first) {
                           case '（':
                              this.token = Token.LPAREN;
                              return;
                           case '）':
                              this.token = Token.RPAREN;
                              return;
                           default:
                              this.token = Token.IDENTIFIER;
                              this.stringVal = CharTypes.valueOf(first);
                              if (this.stringVal == null) {
                                 this.stringVal = Character.toString(first);
                              }

                              return;
                        }
                     } else {
                        Token tok = this.keywords.getKeyword(this.hash_lower);
                        if (tok != null) {
                           this.token = tok;
                           if (this.token == Token.IDENTIFIER) {
                              this.stringVal = SymbolTable.global.addSymbol(this.text, this.mark, this.bufPos, this.hash);
                           } else {
                              this.stringVal = null;
                              if (tok == Token.DEFAULT) {
                                 String temp = SymbolTable.global.addSymbol(this.text, this.mark, this.bufPos, this.hash);
                                 SavePoint mark = this.mark();
                                 this.nextToken();
                                 if (this.token == Token.DOT) {
                                    this.reset(mark);
                                    this.stringVal = temp;
                                    this.token = Token.IDENTIFIER;
                                 } else {
                                    this.reset(mark);
                                 }
                              }
                           }
                        } else {
                           this.token = Token.IDENTIFIER;
                           this.stringVal = SymbolTable.global.addSymbol(this.text, this.mark, this.bufPos, this.hash);
                        }

                        return;
                     }
                  }

                  ++this.bufPos;
               } else {
                  this.hash_lower ^= (long)(ch >= 'A' && ch <= 'Z' ? ch + 32 : ch);
                  this.hash_lower *= 1099511628211L;
                  this.hash ^= (long)ch;
                  this.hash *= 1099511628211L;
                  ++this.bufPos;
               }
            }
         }
      }
   }

   protected final void scanString() {
      this.scanString2();
   }

   public void scanComment() {
      this.scanHiveComment();
   }

   static {
      Map<String, Token> map = new HashMap();
      map.putAll(Keywords.DEFAULT_KEYWORDS.getKeywords());
      map.put("OF", Token.OF);
      map.put("CONCAT", Token.CONCAT);
      map.put("CONTINUE", Token.CONTINUE);
      map.put("MERGE", Token.MERGE);
      map.put("MATCHED", Token.MATCHED);
      map.put("USING", Token.USING);
      map.put("ROW", Token.ROW);
      map.put("LIMIT", Token.LIMIT);
      map.put("PARTITIONED", Token.PARTITIONED);
      map.put("PARTITION", Token.PARTITION);
      map.put("OVERWRITE", Token.OVERWRITE);
      map.put("IF", Token.IF);
      map.put("TRUE", Token.TRUE);
      map.put("FALSE", Token.FALSE);
      map.put("RLIKE", Token.RLIKE);
      map.put("CONSTRAINT", Token.CONSTRAINT);
      map.put("DIV", Token.DIV);
      map.put("DIRECTORY", Token.DIRECTORY);
      map.put("LOCAL", Token.LOCAL);
      map.put("ABORT", Token.ABORT);
      map.put("LOAD", Token.LOAD);
      DEFAULT_HIVE_KEYWORDS = new Keywords(map);
   }
}
