/* 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 "tree/Trees.h"
#include "misc/Interval.h"
#include "Parser.h"
#include "atn/ATN.h"
#include "atn/ATNState.h"
#include "tree/ParseTreeVisitor.h"

#include "RuleContext.h"

using namespace antlr4;
using namespace antlr4::atn;
using namespace antlr4::tree;

RuleContext::RuleContext() : ParseTree(ParseTreeType::RULE) {
  InitializeInstanceFields();
}

RuleContext::RuleContext(RuleContext *parent_, size_t invokingState_) : ParseTree(ParseTreeType::RULE) {
  InitializeInstanceFields();
  this->parent = parent_;
  this->invokingState = invokingState_;
}

int RuleContext::depth() {
  int n = 1;
  RuleContext *p = this;
  while (true) {
    if (p->parent == nullptr)
      break;
    p = static_cast<RuleContext *>(p->parent);
    n++;
  }
  return n;
}

bool RuleContext::isEmpty() {
  return invokingState == ATNState::INVALID_STATE_NUMBER;
}

misc::Interval RuleContext::getSourceInterval() {
  return misc::Interval::INVALID;
}

std::string RuleContext::getText() {
  if (children.empty()) {
    return "";
  }

  std::stringstream ss;
  for (size_t i = 0; i < children.size(); i++) {
    ParseTree *tree = children[i];
    if (tree != nullptr)
      ss << tree->getText();
  }

  return ss.str();
}

size_t RuleContext::getRuleIndex() const {
  return INVALID_INDEX;
}

size_t RuleContext::getAltNumber() const {
  return atn::ATN::INVALID_ALT_NUMBER;
}

void RuleContext::setAltNumber(size_t /*altNumber*/) {
}

std::any RuleContext::accept(tree::ParseTreeVisitor *visitor) {
  return visitor->visitChildren(this);
}

std::string RuleContext::toStringTree(Parser *recog, bool pretty) {
  return tree::Trees::toStringTree(this, recog, pretty);
}

std::string RuleContext::toStringTree(std::vector<std::string> &ruleNames, bool pretty) {
  return tree::Trees::toStringTree(this, ruleNames, pretty);
}

std::string RuleContext::toStringTree(bool pretty) {
  return toStringTree(nullptr, pretty);
}


std::string RuleContext::toString(const std::vector<std::string> &ruleNames) {
  return toString(ruleNames, nullptr);
}


std::string RuleContext::toString(const std::vector<std::string> &ruleNames, RuleContext *stop) {
  std::stringstream ss;

  RuleContext *currentParent = this;
  ss << "[";
  while (currentParent != stop) {
    if (ruleNames.empty()) {
      if (!currentParent->isEmpty()) {
        ss << currentParent->invokingState;
      }
    } else {
      size_t ruleIndex = currentParent->getRuleIndex();

      std::string ruleName = (ruleIndex < ruleNames.size()) ? ruleNames[ruleIndex] : std::to_string(ruleIndex);
      ss << ruleName;
    }

    if (currentParent->parent == nullptr) // No parent anymore.
      break;
    currentParent = static_cast<RuleContext *>(currentParent->parent);
    if (!ruleNames.empty() || !currentParent->isEmpty()) {
      ss << " ";
    }
  }

  ss << "]";

  return ss.str();
}

std::string RuleContext::toString() {
  return toString(nullptr);
}

std::string RuleContext::toString(Recognizer *recog) {
  return toString(recog, &ParserRuleContext::EMPTY);
}

std::string RuleContext::toString(Recognizer *recog, RuleContext *stop) {
  if (recog == nullptr)
    return toString(std::vector<std::string>(), stop); // Don't use an initializer {} here or we end up calling ourselve recursivly.
  return toString(recog->getRuleNames(), stop);
}

void RuleContext::InitializeInstanceFields() {
  invokingState = INVALID_INDEX;
}

