/**
   * It is called when parser enters grammar rule (typedef), it perform validations and updates the
   * data model tree.
   *
   * @param listener listener's object
   * @param ctx context object of the grammar rule
   */
  public static void processTypeDefEntry(
      TreeWalkListener listener, GeneratedYangParser.TypedefStatementContext ctx) {

    // Check for stack to be non empty.
    checkStackIsNotEmpty(listener, MISSING_HOLDER, TYPEDEF_DATA, ctx.identifier().getText(), ENTRY);

    String identifier = getValidIdentifier(ctx.identifier().getText(), TYPEDEF_DATA, ctx);

    // Validate sub statement cardinality.
    validateSubStatementsCardinality(ctx);

    /*
     * Create a derived type information, the base type must be set in type
     * listener.
     */
    YangTypeDef typeDefNode = getYangTypeDefNode(JAVA_GENERATION);
    typeDefNode.setName(identifier);

    Parsable curData = listener.getParsedDataStack().peek();

    if (curData instanceof YangModule
        || curData instanceof YangSubModule
        || curData instanceof YangContainer
        || curData instanceof YangList
        || curData instanceof YangNotification
        || curData instanceof YangRpc
        || curData instanceof YangInput
        || curData instanceof YangOutput
        || curData instanceof YangGrouping) {

      YangNode curNode = (YangNode) curData;
      try {
        curNode.addChild(typeDefNode);
      } catch (DataModelException e) {
        throw new ParserException(
            constructExtendedListenerErrorMessage(
                UNHANDLED_PARSED_DATA,
                TYPEDEF_DATA,
                ctx.identifier().getText(),
                ENTRY,
                e.getMessage()));
      }
      listener.getParsedDataStack().push(typeDefNode);
    } else {
      throw new ParserException(
          constructListenerErrorMessage(
              INVALID_HOLDER, TYPEDEF_DATA, ctx.identifier().getText(), ENTRY));
    }
  }
  /**
   * It is called when parser enters grammar rule (bit), it perform validations and updates the data
   * model tree.
   *
   * @param listener listener's object
   * @param ctx context object of the grammar rule
   */
  public static void processBitEntry(
      TreeWalkListener listener, GeneratedYangParser.BitStatementContext ctx) {

    // Check for stack to be non empty.
    checkStackIsNotEmpty(listener, MISSING_HOLDER, BIT_DATA, ctx.identifier().getText(), ENTRY);

    String identifier = getValidIdentifier(ctx.identifier().getText(), BIT_DATA, ctx);

    YangBit bitNode = new YangBit();
    bitNode.setBitName(identifier);
    listener.getParsedDataStack().push(bitNode);
  }
  /**
   * It is called when parser exits from grammar rule (typedef), it perform validations and updates
   * the data model tree.
   *
   * @param listener listener's object
   * @param ctx context object of the grammar rule
   */
  public static void processTypeDefExit(
      TreeWalkListener listener, GeneratedYangParser.TypedefStatementContext ctx) {

    // Check for stack to be non empty.
    checkStackIsNotEmpty(listener, MISSING_HOLDER, TYPEDEF_DATA, ctx.identifier().getText(), EXIT);

    if (listener.getParsedDataStack().peek() instanceof YangTypeDef) {
      YangTypeDef typeDefNode = (YangTypeDef) listener.getParsedDataStack().peek();
      try {
        typeDefNode.validateDataOnExit();
      } catch (DataModelException e) {
        throw new ParserException(
            constructListenerErrorMessage(
                INVALID_CONTENT, TYPEDEF_DATA, ctx.identifier().getText(), EXIT));
      }

      listener.getParsedDataStack().pop();
    } else {
      throw new ParserException(
          constructListenerErrorMessage(
              MISSING_CURRENT_HOLDER, TYPEDEF_DATA, ctx.identifier().getText(), EXIT));
    }
  }
  /**
   * It is called when parser exits from grammar rule (bit), it perform validations and update the
   * data model tree.
   *
   * @param listener Listener's object
   * @param ctx context object of the grammar rule
   */
  public static void processBitExit(
      TreeWalkListener listener, GeneratedYangParser.BitStatementContext ctx) {

    // Check for stack to be non empty.
    checkStackIsNotEmpty(listener, MISSING_HOLDER, BIT_DATA, ctx.identifier().getText(), EXIT);

    Parsable tmpBitNode = listener.getParsedDataStack().peek();
    if (tmpBitNode instanceof YangBit) {
      listener.getParsedDataStack().pop();

      // Check for stack to be non empty.
      checkStackIsNotEmpty(listener, MISSING_HOLDER, BIT_DATA, ctx.identifier().getText(), EXIT);

      Parsable tmpNode = listener.getParsedDataStack().peek();
      switch (tmpNode.getYangConstructType()) {
        case BITS_DATA:
          {
            YangBits yangBits = (YangBits) tmpNode;
            if (ctx.bitBodyStatement() == null
                || ctx.bitBodyStatement().positionStatement() == null) {
              int maxPosition = 0;
              boolean isPositionPresent = false;

              for (YangBit curBit : yangBits.getBitSet()) {
                if (maxPosition <= curBit.getPosition()) {
                  maxPosition = curBit.getPosition();
                  isPositionPresent = true;
                }
              }
              if (isPositionPresent) {
                maxPosition++;
              }
              ((YangBit) tmpBitNode).setPosition(maxPosition);
            }
            try {
              yangBits.addBitInfo((YangBit) tmpBitNode);
            } catch (DataModelException e) {
              ParserException parserException =
                  new ParserException(
                      constructExtendedListenerErrorMessage(
                          INVALID_CONTENT,
                          BIT_DATA,
                          ctx.identifier().getText(),
                          EXIT,
                          e.getMessage()));
              parserException.setLine(ctx.getStart().getLine());
              parserException.setCharPosition(ctx.getStart().getCharPositionInLine());
              throw parserException;
            }
            break;
          }
        default:
          throw new ParserException(
              constructListenerErrorMessage(
                  INVALID_HOLDER, BIT_DATA, ctx.identifier().getText(), EXIT));
      }
    } else {
      throw new ParserException(
          constructListenerErrorMessage(
              MISSING_CURRENT_HOLDER, BIT_DATA, ctx.identifier().getText(), EXIT));
    }
  }