001package gudusoft.gsqlparser.pp2;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.List;
006
007/**
008 * Immutable result of a {@code Pp2Formatter.format(...)} call.
009 *
010 * <p>Carries the formatted SQL text, the overall outcome
011 * ({@link FormatStatus}), the per-region rendering record
012 * ({@link Region}), and the diagnostic events the engine emitted along the
013 * way ({@link FormatDiagnostic}).
014 *
015 * <p>Built only by pp2 internals. Callers consume the immutable accessors:
016 * {@link #getText()}, {@link #getStatus()}, {@link #getRegions()},
017 * {@link #getDiagnostics()}. The two list accessors return unmodifiable
018 * views.
019 */
020public final class Pp2FormatResult {
021
022    /**
023     * Per-region rendering record. Spans are byte offsets into the
024     * <b>original</b> input string (not the formatted output), so multiple
025     * regions can be reconstructed against the source.
026     *
027     * <p>Carries the {@link RendererId} that the engine actually used and a
028     * region-local {@link FormatStatus} that may be {@link FormatStatus#OK}
029     * even when the result's overall status is
030     * {@link FormatStatus#OK_WITH_RECOVERY} (i.e., some other region needed
031     * recovery, but this one did not).
032     */
033    public static final class Region {
034        private final int startOffset;
035        private final int endOffset;
036        private final RendererId rendererId;
037        private final FormatStatus status;
038
039        public Region(int startOffset, int endOffset, RendererId rendererId,
040                      FormatStatus status) {
041            if (rendererId == null) throw new NullPointerException("rendererId");
042            if (status == null) throw new NullPointerException("status");
043            if (startOffset < 0) {
044                throw new IllegalArgumentException("startOffset < 0: " + startOffset);
045            }
046            if (endOffset < startOffset) {
047                throw new IllegalArgumentException(
048                    "endOffset < startOffset: " + endOffset + " < " + startOffset);
049            }
050            this.startOffset = startOffset;
051            this.endOffset = endOffset;
052            this.rendererId = rendererId;
053            this.status = status;
054        }
055
056        public int getStartOffset() { return startOffset; }
057        public int getEndOffset() { return endOffset; }
058        public RendererId getRendererId() { return rendererId; }
059        public FormatStatus getStatus() { return status; }
060
061        @Override
062        public String toString() {
063            return "Region{[" + startOffset + ".." + endOffset + "] "
064                + rendererId + " " + status + "}";
065        }
066    }
067
068    private final String text;
069    private final FormatStatus status;
070    private final List<Region> regions;
071    private final List<FormatDiagnostic> diagnostics;
072
073    public Pp2FormatResult(String text, FormatStatus status,
074                           List<Region> regions,
075                           List<FormatDiagnostic> diagnostics) {
076        if (text == null) throw new NullPointerException("text");
077        if (status == null) throw new NullPointerException("status");
078        this.text = text;
079        this.status = status;
080        this.regions = regions == null || regions.isEmpty()
081            ? Collections.<Region>emptyList()
082            : Collections.unmodifiableList(new ArrayList<Region>(regions));
083        this.diagnostics = diagnostics == null || diagnostics.isEmpty()
084            ? Collections.<FormatDiagnostic>emptyList()
085            : Collections.unmodifiableList(new ArrayList<FormatDiagnostic>(diagnostics));
086    }
087
088    public String getText() { return text; }
089    public FormatStatus getStatus() { return status; }
090
091    /** Unmodifiable view; never {@code null}, may be empty. */
092    public List<Region> getRegions() { return regions; }
093
094    /** Unmodifiable view; never {@code null}, may be empty. */
095    public List<FormatDiagnostic> getDiagnostics() { return diagnostics; }
096
097    @Override
098    public String toString() {
099        return "Pp2FormatResult{status=" + status
100            + ", regions=" + regions.size()
101            + ", diagnostics=" + diagnostics.size()
102            + ", textLen=" + text.length() + "}";
103    }
104}