package grammar;

import org.eclipse.lsp4j.FoldingRange;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Visitor for collecting FoldingRanges from a Progress parse tree.
 *
 * <p>This class traverses the parse tree generated by ANTLR for the Progress language
 * and produces folding ranges suitable for use in a Language Server Protocol (LSP)
 * server implementation. Folding ranges allow an editor to collapse code sections
 * (e.g., DO...END blocks).</p>
 *
 * <p>The visitor returns a list of {@link FoldingRange} objects:
 * <ul>
 *     <li>{@link #visitProgram(ProgressParser.ProgramContext)} returns all folding ranges
 *         for the entire program, aggregating the results of all DO statements.</li>
 *     <li>{@link #visitDoStatement(ProgressParser.DoStatementContext)} returns a single
 *         folding range for the DO...END block.</li>
 * </ul>
 * </p>
 */
public class FoldingRangeCollectorParserVisitor extends ProgressParserBaseVisitor<List<FoldingRange>> {

   /**
    * Visits a program parse tree node and collects folding ranges from all
    * DO statements in the program.
    *
    * @param ctx the parse tree context for the program
    * @return a list of {@link FoldingRange} objects representing all collapsible
    *         DO blocks in the program
    */
   @Override
   public List<FoldingRange> visitProgram(ProgressParser.ProgramContext ctx) {
      List<FoldingRange> ranges = new ArrayList<>();

      // Visit each doStatement and collect their folding ranges
      for (ProgressParser.DoStatementContext doCtx : ctx.doStatement()) {
         ranges.addAll(visitDoStatement(doCtx));
      }

      return ranges;
   }

   /**
    * Visits a DO statement parse tree node and generates a folding range for it.
    *
    * <p>In LSP (Language Server Protocol), folding ranges indicate sections of code
    * that can be collapsed in an editor. This method creates one folding range for
    * the entire DO...END block.</p>
    *
    * <p>The folding range is calculated using the starting and ending tokens of the
    * DO statement:
    * <ul>
    *     <li>{@code ctx.start} represents the 'DO' keyword token.</li>
    *     <li>{@code ctx.stop} represents the 'END.' token (inclusive).</li>
    * </ul>
    * Lines are converted to 0-based indices because LSP expects folding ranges to use
    * 0-based line numbers. The end line is adjusted by -2 to ensure correct collapse
    * behavior, accounting for inclusive parsing and the DO/END syntax.</p>
    *
    * @param ctx the parse tree context for a DO statement
    * @return a list containing a single {@link FoldingRange} for this DO statement
    */
   @Override
   public List<FoldingRange> visitDoStatement(ProgressParser.DoStatementContext ctx) {
      List<FoldingRange> ranges = new LinkedList<>();

      // Start line: the line where 'DO' appears (0-based)
      int startLine = ctx.start.getLine() - 1;

      // End line: the line before 'END.' (adjusted for LSP)
      int endLine   = ctx.stop.getLine() - 2;

      // Create the folding range
      FoldingRange range = new FoldingRange(startLine, endLine);

      // Add it to the list
      ranges.add(range);

      return ranges;
   }
}
