/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */

#include "ConsoleErrorListener.h"
#include "RecognitionException.h"
#include "support/CPPUtils.h"
#include "support/StringUtils.h"
#include "Token.h"
#include "atn/ATN.h"
#include "atn/ATNSimulator.h"
#include "support/CPPUtils.h"

#include "Vocabulary.h"

#include "Recognizer.h"

using namespace antlr4;
using namespace antlr4::atn;

std::map<const dfa::Vocabulary*, std::map<std::string, size_t>> Recognizer::_tokenTypeMapCache;
std::map<std::vector<std::string>, std::map<std::string, size_t>> Recognizer::_ruleIndexMapCache;

Recognizer::Recognizer() {
  InitializeInstanceFields();
  _proxListener.addErrorListener(&ConsoleErrorListener::INSTANCE);
}

Recognizer::~Recognizer() {
}

dfa::Vocabulary const& Recognizer::getVocabulary() const {
  static dfa::Vocabulary vocabulary = dfa::Vocabulary::fromTokenNames(getTokenNames());
  return vocabulary;
}

std::map<std::string, size_t> Recognizer::getTokenTypeMap() {
  const dfa::Vocabulary& vocabulary = getVocabulary();

  std::lock_guard<std::mutex> lck(_mutex);
  std::map<std::string, size_t> result;
  auto iterator = _tokenTypeMapCache.find(&vocabulary);
  if (iterator != _tokenTypeMapCache.end()) {
    result = iterator->second;
  } else {
    for (size_t i = 0; i <= getATN().maxTokenType; ++i) {
      std::string literalName = vocabulary.getLiteralName(i);
      if (!literalName.empty()) {
        result[literalName] = i;
      }

      std::string symbolicName = vocabulary.getSymbolicName(i);
      if (!symbolicName.empty()) {
        result[symbolicName] = i;
      }
				}
    result["EOF"] = EOF;
    _tokenTypeMapCache[&vocabulary] = result;
  }

  return result;
}

std::map<std::string, size_t> Recognizer::getRuleIndexMap() {
  const std::vector<std::string>& ruleNames = getRuleNames();
  if (ruleNames.empty()) {
    throw "The current recognizer does not provide a list of rule names.";
  }

  std::lock_guard<std::mutex> lck(_mutex);
  std::map<std::string, size_t> result;
  auto iterator = _ruleIndexMapCache.find(ruleNames);
  if (iterator != _ruleIndexMapCache.end()) {
    result = iterator->second;
  } else {
    result = antlrcpp::toMap(ruleNames);
    _ruleIndexMapCache[ruleNames] = result;
  }
  return result;
}

size_t Recognizer::getTokenType(const std::string &tokenName) {
  const std::map<std::string, size_t> &map = getTokenTypeMap();
  auto iterator = map.find(tokenName);
  if (iterator == map.end())
    return Token::INVALID_TYPE;

  return iterator->second;
}

void Recognizer::setInterpreter(atn::ATNSimulator *interpreter) {
  // Usually the interpreter is set by the descendant (lexer or parser (simulator), but can also be exchanged
  // by the profiling ATN simulator.
  delete _interpreter;
  _interpreter = interpreter;
}

std::string Recognizer::getErrorHeader(RecognitionException *e) {
  // We're having issues with cross header dependencies, these two classes will need to be
  // rewritten to remove that.
  size_t line = e->getOffendingToken()->getLine();
  size_t charPositionInLine = e->getOffendingToken()->getCharPositionInLine();
  return std::string("line ") + std::to_string(line) + ":" + std::to_string(charPositionInLine);

}

std::string Recognizer::getTokenErrorDisplay(Token *t) {
  if (t == nullptr) {
    return "<no Token>";
  }
  std::string s = t->getText();
  if (s == "") {
    if (t->getType() == EOF) {
      s = "<EOF>";
    } else {
      s = std::string("<") + std::to_string(t->getType()) + std::string(">");
    }
  }

  antlrcpp::replaceAll(s, "\n", "\\n");
  antlrcpp::replaceAll(s, "\r","\\r");
  antlrcpp::replaceAll(s, "\t", "\\t");

  return "'" + s + "'";
}

void Recognizer::addErrorListener(ANTLRErrorListener *listener) {
  _proxListener.addErrorListener(listener);
}

void Recognizer::removeErrorListener(ANTLRErrorListener *listener) {
  _proxListener.removeErrorListener(listener);
}

void Recognizer::removeErrorListeners() {
  _proxListener.removeErrorListeners();
}

ProxyErrorListener& Recognizer::getErrorListenerDispatch() {
  return _proxListener;
}

bool Recognizer::sempred(RuleContext * /*localctx*/, size_t /*ruleIndex*/, size_t /*actionIndex*/) {
  return true;
}

bool Recognizer::precpred(RuleContext * /*localctx*/, int /*precedence*/) {
  return true;
}

void Recognizer::action(RuleContext * /*localctx*/, size_t /*ruleIndex*/, size_t /*actionIndex*/) {
}

size_t Recognizer::getState() const {
  return _stateNumber;
}

void Recognizer::setState(size_t atnState) {
  _stateNumber = atnState;
}

void Recognizer::InitializeInstanceFields() {
  _stateNumber = ATNState::INVALID_STATE_NUMBER;
  _interpreter = nullptr;
}

