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

import com.alibaba.druid.sql.ast.SQLCurrentTimeExpr;
import com.alibaba.druid.sql.ast.SQLCurrentUserExpr;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLArrayExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLExternalRecordFormat;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.HiveRowFormat;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkColumnDef;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkDateExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkDefProperty;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkIntervalExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkIntervalType;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkLimit;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkNullsExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkNumberExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkTransformExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkValuesExpr;
import com.alibaba.druid.sql.dialect.spark.ast.expr.SparkWithExpr;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLParser;
import com.alibaba.druid.sql.parser.SQLParserFeature;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.util.FnvHash;
import java.util.Arrays;

public class SparkExprParser extends SQLExprParser {
   private static final String[] AGGREGATE_FUNCTIONS;
   private static final long[] AGGREGATE_FUNCTIONS_CODES;
   private SQLParser sparkSqlParser;

   public SQLParser getSparkSqlParser() {
      return this.sparkSqlParser;
   }

   public void setSparkSqlParser(SQLParser sparkSqlParser) {
      this.sparkSqlParser = sparkSqlParser;
   }

   public SparkExprParser(String sql) {
      this((Lexer)(new SparkLexer(sql)));
      this.lexer.nextToken();
   }

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

   public SparkSelectParser createSelectParser() {
      return new SparkSelectParser(this);
   }

   public SQLExpr primaryRest(SQLExpr expr) {
      SQLExpr e = null;
      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);
         e = this.primaryRest(array);
      } else {
         e = super.primaryRest(expr);
      }

      return this.nullsExpr(e);
   }

   public SQLExpr exprRest(SQLExpr expr) {
      SQLExpr e = super.exprRest(expr);
      return this.nullsExpr(e);
   }

   protected SQLExpr methodRest(SQLExpr expr, boolean acceptLPAREN) {
      SQLExpr e = super.methodRest(expr, acceptLPAREN);
      if (e instanceof SQLMethodInvokeExpr) {
         e = this.getTransformrExpr((SQLMethodInvokeExpr)e);
      }

      return this.nullsExpr(e);
   }

   public SQLExpr nullsExpr(SQLExpr e) {
      if (this.lexer.token() != Token.EOF) {
         this.lexer.mark();
         if (this.lexer.identifierEquals("IGNORE")) {
            this.lexer.nextToken();
            if (this.lexer.identifierEquals("NULLS")) {
               SparkNullsExpr nullsExpr = new SparkNullsExpr();
               nullsExpr.setExpr(e);
               nullsExpr.setIgnore(true);
               e = nullsExpr;
               this.lexer.nextToken();
            } else {
               this.lexer.reset();
            }
         }
      }

      return e;
   }

   public SQLExpr expr() {
      SQLExpr e = null;
      if (this.lexer.token() == Token.WITH) {
         SQLStatement statement = null;
         SparkWithExpr withExpr = new SparkWithExpr();
         if (this.sparkSqlParser instanceof SQLStatementParser) {
            SQLStatementParser parser = (SQLStatementParser)this.sparkSqlParser;
            statement = parser.parseWith();
            withExpr.setStatement(statement);
         } else if (this.sparkSqlParser instanceof SQLSelectParser) {
            SQLSelectParser selectParser = (SQLSelectParser)this.sparkSqlParser;
            SQLWithSubqueryClause with = selectParser.parseWith();
            if (this.lexer.token() == Token.SELECT || this.lexer.token() == Token.LPAREN) {
               SQLSelect select = selectParser.select();
               select.setWithSubQuery(with);
               statement = new SQLSelectStatement(select, this.dbType);
            }
         }

         withExpr.setStatement(statement);
         if (this.lexer.token() == Token.RPAREN) {
            return withExpr;
         }
      }

      if (this.lexer.token() == Token.ANY || this.lexer.token() == Token.SOME || this.lexer.token() == Token.ALL) {
         e = this.getValueExpr();
      }

      e = super.expr();
      this.nullsExpr(e);
      return e;
   }

   public SQLExpr getValueExpr() {
      SparkValuesExpr valuesExpr = new SparkValuesExpr();
      SQLIdentifierExpr type = new SQLIdentifierExpr(this.lexer.stringVal());
      valuesExpr.setTypeExpr(type);
      this.lexer.nextToken();
      this.accept(Token.LPAREN);

      while(this.lexer.token() != Token.RPAREN) {
         SQLExpr value = this.expr();
         valuesExpr.addValue(value);
         if (this.lexer.token() == Token.RPAREN) {
            break;
         }

         this.lexer.nextToken();
      }

      this.lexer.nextToken();
      return valuesExpr;
   }

   public SQLExpr primary() {
      Token tok = this.lexer.token();
      switch (tok) {
         case LITERAL_DBNUMBER:
            String s = this.lexer.stringVal();
            SparkNumberExpr numberExpr = new SparkNumberExpr(s);
            this.lexer.nextToken();
            return numberExpr;
         case ANY:
         case SOME:
         case ALL:
            return this.getValueExpr();
         case IDENTIFIER:
            long hash_lower = this.lexer.hash_lower();
            if (hash_lower == FnvHash.Constants.OUTLINE) {
               this.lexer.nextToken();
               SQLExpr file = this.primary();
               SQLExpr expr = new MySqlOutFileExpr(file);
               return this.primaryRest(expr);
            } else {
               SQLCurrentTimeExpr currentTimeExpr = null;
               if (hash_lower == FnvHash.Constants.CURRENT_TIMESTAMP) {
                  currentTimeExpr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr.Type.CURRENT_TIMESTAMP);
               } else if (hash_lower == FnvHash.Constants.CURRENT_DATE) {
                  currentTimeExpr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr.Type.CURRENT_DATE);
               } else if (hash_lower == FnvHash.Constants.CURRENT_USER && this.isEnabled(SQLParserFeature.EnableCurrentUserExpr)) {
                  this.lexer.nextToken();
                  return this.primaryRest(new SQLCurrentUserExpr());
               }

               if (currentTimeExpr != null) {
                  String methodName = this.lexer.stringVal();
                  this.lexer.nextToken();
                  if (this.lexer.token() == Token.LPAREN) {
                     this.lexer.nextToken();
                     if (this.lexer.token() != Token.LPAREN) {
                        return this.primaryRest(this.methodRest(new SQLIdentifierExpr(methodName), false));
                     }

                     this.lexer.nextToken();
                  }

                  return this.primaryRest(currentTimeExpr);
               }
            }
         default:
            return super.primary();
         case DATE:
            this.lexer.nextToken();
            SQLExpr value = this.expr();
            SparkDateExpr date = new SparkDateExpr();
            date.setValue(value);
            return date;
      }
   }

   public SQLExternalRecordFormat parseRowFormat() {
      this.lexer.nextToken();
      this.acceptIdentifier("FORMAT");
      if (this.lexer.identifierEquals(FnvHash.Constants.DELIMITED)) {
         this.lexer.nextToken();
      }

      SQLExternalRecordFormat format = new SQLExternalRecordFormat();
      if (this.lexer.identifierEquals(FnvHash.Constants.FIELDS)) {
         this.lexer.nextToken();
         this.acceptIdentifier("TERMINATED");
         this.accept(Token.BY);
         format.setTerminatedBy(this.expr());
      } else if (this.lexer.identifierEquals("FIELD")) {
         throw new ParserException("syntax error, expect FIELDS, " + this.lexer.info());
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.LINES)) {
         this.lexer.nextToken();
         this.acceptIdentifier("TERMINATED");
         this.accept(Token.BY);
         format.setLinesTerminatedBy(this.expr());
      }

      if (this.lexer.token() == Token.ESCAPE || this.lexer.identifierEquals(FnvHash.Constants.ESCAPED)) {
         this.lexer.nextToken();
         this.accept(Token.BY);
         format.setEscapedBy(this.expr());
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.COLLECTION)) {
         this.lexer.nextToken();
         this.acceptIdentifier("ITEMS");
         this.acceptIdentifier("TERMINATED");
         this.accept(Token.BY);
         format.setCollectionItemsTerminatedBy(this.expr());
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.MAP)) {
         this.lexer.nextToken();
         this.acceptIdentifier("KEYS");
         this.acceptIdentifier("TERMINATED");
         this.accept(Token.BY);
         format.setMapKeysTerminatedBy(this.expr());
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.SERDE)) {
         this.lexer.nextToken();
         format.setSerde(this.expr());
      }

      return format;
   }

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

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

   public SQLColumnDefinition parseColumnRest(SQLColumnDefinition column) {
      if (this.lexer.identifierEquals(FnvHash.Constants.MAPPED)) {
         this.lexer.nextToken();
         this.accept(Token.BY);
         this.parseAssignItem(column.getMappedBy(), column);
      }

      if (this.lexer.identifierEquals(FnvHash.Constants.COLPROPERTIES)) {
         this.lexer.nextToken();
         this.parseAssignItem(column.getColProperties(), column);
      }

      return super.parseColumnRest(column);
   }

   public SQLLimit parseLimit() {
      if (this.lexer.token() != Token.LIMIT) {
         return null;
      } else {
         SparkLimit limit = new SparkLimit();
         limit.setType(SQLLimit.Type.LIMIT);
         this.lexer.nextTokenValue();
         if (this.lexer.token() == Token.ALL) {
            limit.setAll(true);
            this.lexer.nextToken();
            return limit;
         } else {
            SQLExpr temp;
            if (this.lexer.token() == Token.LITERAL_INT) {
               temp = new SQLIntegerExpr(this.lexer.integerValue());
               this.lexer.nextTokenComma();
               if (this.lexer.token() != Token.COMMA && this.lexer.token() != Token.EOF && this.lexer.token() != Token.IDENTIFIER) {
                  temp = this.primaryRest(temp);
                  temp = this.exprRest(temp);
               }
            } else {
               temp = this.expr();
            }

            if (this.lexer.token() == Token.COMMA) {
               limit.setOffset(temp);
               this.lexer.nextTokenValue();
               SQLExpr rowCount;
               if (this.lexer.token() == Token.LITERAL_INT) {
                  rowCount = new SQLIntegerExpr(this.lexer.integerValue());
                  this.lexer.nextToken();
                  if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.IDENTIFIER) {
                     rowCount = this.primaryRest(rowCount);
                     rowCount = this.exprRest(rowCount);
                  }
               } else {
                  rowCount = this.expr();
               }

               limit.setRowCount(rowCount);
            } else if (!this.lexer.identifierEquals(FnvHash.Constants.OFFSET) && this.lexer.token() != Token.OFFSET) {
               limit.setRowCount(temp);
            } else {
               limit.setType(SQLLimit.Type.LIMIT_OFFSET);
               limit.setRowCount(temp);
               this.lexer.nextToken();
               limit.setOffset(this.expr());
            }

            return limit;
         }
      }
   }

   public SQLExpr getTransformrExpr(SQLMethodInvokeExpr methodInvokeExpr) {
      if (!methodInvokeExpr.getMethodName().equalsIgnoreCase("TRANSFORM")) {
         return methodInvokeExpr;
      } else {
         SparkTransformExpr e = new SparkTransformExpr();

         for(SQLExpr argument : methodInvokeExpr.getArguments()) {
            e.addArgument(argument);
         }

         this.lexer.mark();

         try {
            boolean flag = true;

            while(flag) {
               if (this.lexer.token() == Token.ROW) {
                  HiveRowFormat format = this.parseHiveRowFormat();
                  if (e.getCommandScript() == null) {
                     e.setRowFormat(format);
                  } else {
                     e.setUsingRowFormat(format);
                  }
               } else if (this.lexer.identifierEquals("RECORDWRITER")) {
                  this.lexer.nextToken();
                  e.setRecordWriter(this.expr());
               } else if (this.lexer.token() == Token.USING) {
                  SparkTransformExpr.CommandScriptDef def = this.parseCommandScriptDef(e);
                  e.setCommandScript(def);
               } else if (this.lexer.identifierEquals("RECORDREADER")) {
                  this.lexer.nextToken();
                  e.setRecordReader(this.expr());
               } else {
                  flag = false;
               }
            }
         } catch (Exception var6) {
            this.lexer.reset();
         }

         return e;
      }
   }

   private SparkTransformExpr.CommandScriptDef parseCommandScriptDef(SparkTransformExpr e) {
      this.accept(Token.USING);
      SparkTransformExpr.CommandScriptDef def = new SparkTransformExpr.CommandScriptDef();
      def.setCommandOrScript(this.expr());
      if (this.lexer.token() == Token.AS) {
         this.lexer.nextToken();

         SQLExpr col;
         SQLExpr type;
         for(; this.lexer.token() != Token.RPAREN; def.getColDefs().add(new SparkColumnDef(col, type))) {
            this.lexer.nextToken();
            col = this.expr();
            type = null;
            if (this.lexer.token() != Token.COMMA && this.lexer.token() != Token.RPAREN) {
               type = this.expr();
            }
         }

         this.lexer.nextToken();
      }

      return def;
   }

   public HiveRowFormat parseHiveRowFormat() {
      this.accept(Token.ROW);
      HiveRowFormat clause = new HiveRowFormat();
      this.acceptIdentifier("FORMAT");
      boolean flag = true;

      while(flag) {
         if (this.lexer.identifierEquals("SERDE")) {
            clause.setSede(this.parseHiveRowFormatSede());
         } else if (this.lexer.identifierEquals("DELIMITED")) {
            clause.setDelimitor(this.parseHiveRowFormatDeimitor());
         } else {
            flag = false;
         }
      }

      return clause;
   }

   private HiveRowFormat.RowFormatSede parseHiveRowFormatSede() {
      this.acceptIdentifier("SERDE");
      HiveRowFormat.RowFormatSede sede = new HiveRowFormat.RowFormatSede();
      sede.setSedeClass(this.expr());
      if (this.lexer.token() == Token.WITH) {
         this.lexer.nextToken();
         this.acceptIdentifier("SERDEPROPERTIES");

         SQLExpr key;
         SQLExpr value;
         for(; this.lexer.token() != Token.RPAREN; sede.getProps().add(new SparkDefProperty(key, value))) {
            this.lexer.nextToken();
            value = null;
            key = this.expr();
            if (key instanceof SQLBinaryOpExpr) {
               SQLBinaryOpExpr b = (SQLBinaryOpExpr)key;
               value = b.getRight();
               key = b.getLeft();
            } else {
               this.accept(Token.EQ);
               value = this.expr();
            }
         }

         this.lexer.nextToken();
      }

      return sede;
   }

   private HiveRowFormat.RowFormatDelimitor parseHiveRowFormatDeimitor() {
      this.acceptIdentifier("DELIMITED");
      HiveRowFormat.RowFormatDelimitor d = new HiveRowFormat.RowFormatDelimitor();
      boolean flag = true;

      while(flag) {
         if (this.lexer.identifierEquals("FIELDS")) {
            this.lexer.nextToken();
            this.acceptIdentifier("TERMINATED");
            this.accept(Token.BY);
            d.setFieldTerminatedChar(this.expr());
            if (this.lexer.identifierEquals("ESCAPED")) {
               this.lexer.nextToken();
               this.accept(Token.BY);
               d.setEscapeChar(this.expr());
            }
         } else if (this.lexer.identifierEquals("COLLECTION")) {
            this.lexer.nextToken();
            this.acceptIdentifier("ITEMS");
            this.acceptIdentifier("TERMINATED");
            this.accept(Token.BY);
            d.setCollectionItemsTerminatedChar(this.expr());
         } else if (this.lexer.identifierEquals("MAP")) {
            this.lexer.nextToken();
            this.acceptIdentifier("KEYS");
            this.acceptIdentifier("TERMINATED");
            this.accept(Token.BY);
            d.setMapKeyTerminatedChar(this.expr());
         } else if (this.lexer.identifierEquals("LINES")) {
            this.lexer.nextToken();
            this.acceptIdentifier("TERMINATED");
            this.accept(Token.BY);
            d.setRowTerminatedChar(this.expr());
         } else if (this.lexer.token() == Token.NULL) {
            this.lexer.nextToken();
            this.acceptIdentifier("DEFINED");
            this.accept(Token.AS);
            d.setNullChar(this.expr());
         } else {
            flag = false;
         }
      }

      return d;
   }

   protected SQLExpr parseInterval() {
      this.accept(Token.INTERVAL);
      SparkIntervalExpr interval = new SparkIntervalExpr();
      SparkIntervalExpr.SparkIntervalItem item = null;
      boolean first = true;

      while(true) {
         item = this.getIntervalItem(first);
         if (item == null) {
            if (this.lexer.token() == Token.TO) {
               item = this.getIntervalItem(false);
               interval.setTo(item);
            }

            return interval;
         }

         interval.addItem(item);
         first = false;
      }
   }

   private SparkIntervalExpr.SparkIntervalItem getIntervalItem(boolean first) {
      if (this.lexer.token() != Token.EOF && this.lexer.token() != Token.AS && this.lexer.token() != Token.TABLE && this.lexer.token() != Token.FROM && this.lexer.token() != Token.SELECT && this.lexer.token() != Token.JOIN && this.lexer.token() != Token.INTO && this.lexer.token() != Token.EQ && this.lexer.token() != Token.NOT && this.lexer.token() != Token.LIKE && this.lexer.token() != Token.GTEQ && this.lexer.token() != Token.GT && this.lexer.token() != Token.LTEQ && this.lexer.token() != Token.LT && this.lexer.token() != Token.SLASH && this.lexer.token() != Token.STAR && this.lexer.token() != Token.LTLT && this.lexer.token() != Token.GTGT && this.lexer.token() != Token.LTGT && this.lexer.token() != Token.AND && this.lexer.token() != Token.OR && this.lexer.token() != Token.EXISTS && this.lexer.token() != Token.ORDER && this.lexer.token() != Token.GROUP && this.lexer.token() != Token.OVER && this.lexer.token() != Token.WITH && this.lexer.token() != Token.INTERVAL && this.lexer.token() != Token.COMMA && this.lexer.token() != Token.SEMI) {
         this.lexer.mark();
         SparkIntervalExpr.SparkIntervalItem item = new SparkIntervalExpr.SparkIntervalItem();
         SQLExpr value = this.expr();
         if (!this.lexer.identifierEquals(FnvHash.Constants.YEAR) && !this.lexer.identifierEquals(FnvHash.Constants.YEARS)) {
            if (!this.lexer.identifierEquals(FnvHash.Constants.MONTH) && !this.lexer.identifierEquals(FnvHash.Constants.MONTHS)) {
               if (!this.lexer.identifierEquals(FnvHash.Constants.WEEK) && !this.lexer.identifierEquals(FnvHash.Constants.WEEKS)) {
                  if (!this.lexer.identifierEquals(FnvHash.Constants.DAY) && !this.lexer.identifierEquals(FnvHash.Constants.DAYS)) {
                     if (!this.lexer.identifierEquals(FnvHash.Constants.HOUR) && !this.lexer.identifierEquals(FnvHash.Constants.HOURS)) {
                        if (!this.lexer.identifierEquals(FnvHash.Constants.MINUTE) && !this.lexer.identifierEquals(FnvHash.Constants.MINUTES)) {
                           if (!this.lexer.identifierEquals(FnvHash.Constants.SECOND) && !this.lexer.identifierEquals(FnvHash.Constants.SECONDS)) {
                              if (!this.lexer.identifierEquals(FnvHash.Constants.MILLISECOND) && !this.lexer.identifierEquals(FnvHash.Constants.MILLISECONDS)) {
                                 if (!this.lexer.identifierEquals(FnvHash.Constants.MICROSECOND) && !this.lexer.identifierEquals(FnvHash.Constants.MICROSECONDS)) {
                                    if (!first) {
                                       this.lexer.reset();
                                       return null;
                                    }
                                 } else {
                                    this.lexer.nextToken();
                                    item.setType(SparkIntervalType.MICROSECOND);
                                 }
                              } else {
                                 this.lexer.nextToken();
                                 item.setType(SparkIntervalType.MILLSECOND);
                              }
                           } else {
                              this.lexer.nextToken();
                              item.setType(SparkIntervalType.SECOND);
                           }
                        } else {
                           this.lexer.nextToken();
                           item.setType(SparkIntervalType.MINUTE);
                        }
                     } else {
                        this.lexer.nextToken();
                        item.setType(SparkIntervalType.HOUR);
                     }
                  } else {
                     this.lexer.nextToken();
                     item.setType(SparkIntervalType.DAY);
                  }
               } else {
                  this.lexer.nextToken();
                  item.setType(SparkIntervalType.WEEK);
               }
            } else {
               this.lexer.nextToken();
               item.setType(SparkIntervalType.MONTH);
            }
         } else {
            this.lexer.nextToken();
            item.setType(SparkIntervalType.YEAR);
         }

         item.setValue(value);
         return item;
      } else {
         return null;
      }
   }

   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;
      }

   }
}
