package com.chenyang.druid.sql.dialect.clickhouse.parser;

import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.expr.SQLArrayExpr;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.parser.Lexer;
import com.chenyang.druid.sql.parser.SQLExprParser;
import com.chenyang.druid.sql.parser.SQLParserFeature;
import com.chenyang.druid.sql.parser.Token;
import com.chenyang.druid.util.FnvHash;
import java.util.Arrays;

public class ClickhouseExprParser extends SQLExprParser {
   private static final String[] AGGREGATE_FUNCTIONS;
   private static final long[] AGGREGATE_FUNCTIONS_CODES;

   public ClickhouseExprParser(String sql) {
      this((Lexer)(new ClickhouseLexer(sql)));
      this.lexer.nextToken();
   }

   public ClickhouseExprParser(String sql, SQLParserFeature... features) {
      this((Lexer)(new ClickhouseLexer(sql, features)));
      this.lexer.nextToken();
   }

   public ClickhouseExprParser(Lexer lexer) {
      super(lexer);
      this.aggregateFunctions = AGGREGATE_FUNCTIONS;
      this.aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES;
   }

   protected SQLExpr parseAliasExpr(String alias) {
      String chars = alias.substring(1, alias.length() - 1);
      return new SQLCharExpr(chars);
   }

   public SQLExpr primaryRest(SQLExpr expr) {
      if (this.lexer.token() == Token.LBRACKET) {
         SQLArrayExpr array = new SQLArrayExpr();
         array.setExpr(expr);
         this.lexer.nextToken();
         this.exprList(array.getValues(), array);
         this.accept(Token.RBRACKET);
         return this.primaryRest(array);
      } else {
         return super.primaryRest(expr);
      }
   }

   static {
      String[] strings = new String[]{"AVG", "COUNT", "MAX", "MIN", "STDDEV", "SUM", "ROW_NUMBER", "ROWNUMBER"};
      AGGREGATE_FUNCTIONS_CODES = FnvHash.fnv1a_64_lower(strings, true);
      AGGREGATE_FUNCTIONS = new String[AGGREGATE_FUNCTIONS_CODES.length];

      for(String str : strings) {
         long hash = FnvHash.fnv1a_64_lower(str);
         int index = Arrays.binarySearch(AGGREGATE_FUNCTIONS_CODES, hash);
         AGGREGATE_FUNCTIONS[index] = str;
      }

   }
}
