# AbstractLintingRule.java

    package org.thewonderlemming.c4plantuml.linter.rules;

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Optional;
    import java.util.Set;

    import org.antlr.v4.runtime.Parser;
    import org.antlr.v4.runtime.tree.ParseTree;
    import org.antlr.v4.runtime.tree.ParseTreeListener;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.thewonderlemming.c4plantuml.commons.Reporter;
    import org.thewonderlemming.c4plantuml.linter.SyntaxError;

    /**
     * Represents a linting rule and exposes the methods to be implemented/customized by concrete linting rules.
     *
     * @author thewonderlemming
     *
     */
    public abstract class AbstractLintingRule {

        private final RuleParameters parameters;

        private final List<SyntaxError> syntaxErrors = new ArrayList<>();

        /**
         * Default constructor.
         *
         * @param parameters the {@link RuleParameters} to pass to control the behavior of the rule.
         */
        protected AbstractLintingRule(final RuleParameters parameters) {
            this.parameters = parameters;
        }

        /**
         * Returns a list of supported ANTLR4 {@link Parser}.
         *
         * @return the list of supported {@link Parser}.
         */
        public abstract Set<Class<? extends Parser>> acceptableParsersTypes();

        /**
         * Returns a {@link ParseTreeListener} given a {@link Parser} type.
         * <p>
         * The {@link Reporter} can be passed at the {@link ParseTreeListener} if needed.
         *
         * @param reporter the {@link Reporter} to pass to the new {@link ParseTreeListener}.
         * @param parserType the {@link Parser} for the current C4 grammar.
         * @return the {@link ParseTreeListener} that matches the {@link Parser} grammar.
         */
        public abstract Optional<? extends ParseTreeListener> createParseTreeListener(final Reporter reporter,
            final Class<? extends Parser> parserType);

        /**
         * Returns the logger to be used within custom {@link AbstractLintingRule}.
         *
         * @return the logger to be used within the rules.
         */
        public final Logger getLogger() {
            return LoggerFactory.getLogger(getClass().getName());
        }

        /**
         * Returns a list of reported {@link SyntaxError}.
         *
         * @return a list of {@link SyntaxError}.
         */
        public List<SyntaxError> getSyntaxErrors() {
            return Collections.unmodifiableList(this.syntaxErrors);
        }

        /**
         * Collects a new {@link SyntaxError}.
         *
         * @param parseError the {@link SyntaxError} to report.
         */
        public final void reportSyntaxError(final SyntaxError parseError) {
            this.syntaxErrors.add(parseError);
        }

        /**
         * Selects a {@link ParseTree} to process, given a {@link Parser} grammar.
         *
         * @param parser the {@link Parser} instance to parse the current grammar.
         * @return the {@link ParseTree} that matches the current grammar.
         */
        public abstract Optional<ParseTree> selectParseTree(final Parser parser);

        /**
         * A call that takes place after the parsing process of a file.
         * <p>
         * Implements that call if you need post processing at the end of the linting operation.
         */
        public abstract void wrapUp();

        /**
         * Clears the reported {@link SyntaxError} within the rule.
         */
        protected final void clearSyntaxErrors() {
            this.syntaxErrors.clear();
        }

        /**
         * Returns the current {@link AbstractLintingRule} parameters.
         *
         * @return the rule {@link RuleParameters}.
         */
        protected final RuleParameters getParameters() {
            return this.parameters;
        }
    }