package zemberek.tokenization.antlr;

import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.LexerATNSimulator;
import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.dfa.DFAState;

// For speeding up lexer, we had to make this hack.
// Refer to: https://github.com/antlr/antlr4/issues/1613#issuecomment-273514372

public class CustomLexerATNSimulator extends LexerATNSimulator {

  public static final int MAX_DFA_EDGE = 368;

  public CustomLexerATNSimulator(ATN atn, DFA[] decisionToDFA,
      PredictionContextCache sharedContextCache) {
    super(atn, decisionToDFA, sharedContextCache);
  }

  public CustomLexerATNSimulator(Lexer recog, ATN atn, DFA[] decisionToDFA,
      PredictionContextCache sharedContextCache) {
    super(recog, atn, decisionToDFA, sharedContextCache);
  }

  @Override
  protected DFAState getExistingTargetState(DFAState s, int t) {
    if (s.edges == null || t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) {
      return null;
    }

    DFAState target = s.edges[t - MIN_DFA_EDGE];
    if (debug && target != null) {
      System.out.println("reuse state " + s.stateNumber +
          " edge to " + target.stateNumber);
    }

    return target;
  }

  @Override
  protected void addDFAEdge(DFAState p, int t, DFAState q) {
    if (t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) {
      // Only track edges within the DFA bounds
      return;
    }

    if (debug) {
      System.out.println("EDGE " + p + " -> " + q + " upon " + ((char) t));
    }

    synchronized (p) {
      if (p.edges == null) {
        //  make room for tokens 1..n and -1 masquerading as index 0
        p.edges = new DFAState[MAX_DFA_EDGE - MIN_DFA_EDGE + 1];
      }
      p.edges[t - MIN_DFA_EDGE] = q; // connect
    }
  }
}