# AliasesShouldFollowStandardConventionListener.java

    package org.thewonderlemming.c4plantuml.linter.rules.builtin;

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    import org.antlr.v4.runtime.ParserRuleContext;
    import org.antlr.v4.runtime.tree.ParseTreeListener;
    import org.antlr.v4.runtime.tree.TerminalNode;
    import org.thewonderlemming.c4plantuml.commons.Reporter;
    import org.thewonderlemming.c4plantuml.grammars.C4BaseListener;
    import org.thewonderlemming.c4plantuml.grammars.SourceType;
    import org.thewonderlemming.c4plantuml.grammars.generated.C4L1Parser;
    import org.thewonderlemming.c4plantuml.grammars.generated.C4L2Parser;
    import org.thewonderlemming.c4plantuml.grammars.generated.C4L3Parser;

    /**
     * An ANTLR 4 {@link ParseTreeListener} implementation that verifies that aliases follow a defined format.
     *
     * @author thewonderlemming
     *
     */
    public class AliasesShouldFollowStandardConventionListener extends C4BaseListener {

        private static final String MESSAGE_FORMAT = "Alias <%s> does not follow the expected conventions /%s/ in expression: <%s>";

        private final String aliasFormat;

        private final Pattern aliasFormatPattern;

        private final Reporter reporter;

        private final AliasesShouldFollowStandardConventionRule rule;

        /**
         * Default constructor.
         *
         * @param rule the {@link AliasesShouldBeUniqueRule} instance to refer to.
         * @param reporter {@link Reporter} instance to report to.
         * @param aliasFormat the alias regular expression to follow.
         */
        public AliasesShouldFollowStandardConventionListener(final AliasesShouldFollowStandardConventionRule rule,
            final Reporter reporter, final String aliasFormat) {

            this.aliasFormat = aliasFormat;
            this.aliasFormatPattern = Pattern.compile(aliasFormat);
            this.rule = rule;
            this.reporter = reporter;
        }

        /**
         * Checks that the aliases of a boundary definition in a {@link SourceType#C4_L1} grammar have the expected format
         * or reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterBoundary(final C4L1Parser.BoundaryContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the aliases of a boundary definition in a {@link SourceType#C4_L2} have the expected format or
         * reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterBoundary(final C4L2Parser.BoundaryContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the aliases of a boundary definition in a {@link SourceType#C4_L3} have the expected format or
         * reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterBoundary(final C4L3Parser.BoundaryContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the alias of a cloud definition in a {@link SourceType#C4_L1} grammar has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterCloud(final C4L1Parser.CloudContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a cloud definition in a {@link SourceType#C4_L2} has the expected format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterCloud(final C4L2Parser.CloudContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a cloud definition in a {@link SourceType#C4_L3} has the expected format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterCloud(final C4L3Parser.CloudContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a component definition in a {@link SourceType#C4_L3} has the expected format or reports
         * it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterComponent(final C4L3Parser.ComponentContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a container definition in a {@link SourceType#C4_L2} has the expected format or reports
         * it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterContainer(final C4L2Parser.ContainerContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a container definition in a {@link SourceType#C4_L3} has the expected format or reports
         * it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterContainer(final C4L3Parser.ContainerContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a container boundary definition in a {@link SourceType#C4_L3} has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterContainer_boundary(final C4L3Parser.Container_boundaryContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a enterprise boundary definition in a {@link SourceType#C4_L1} grammar has the expected
         * format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterEnterprise_boundary(final C4L1Parser.Enterprise_boundaryContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a enterprise boundary definition in a {@link SourceType#C4_L2} has the expected format
         * or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterEnterprise_boundary(final C4L2Parser.Enterprise_boundaryContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a enterprise boundary definition in a {@link SourceType#C4_L3} has the expected format
         * or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterEnterprise_boundary(final C4L3Parser.Enterprise_boundaryContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the aliases of a layout definition in a {@link SourceType#C4_L1} grammar have the expected format or
         * reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterLayout(final C4L1Parser.LayoutContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the aliases of a layout definition in a {@link SourceType#C4_L2} have the expected format or reports
         * them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterLayout(final C4L2Parser.LayoutContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the aliases of a layout definition in a {@link SourceType#C4_L3} have the expected format or reports
         * them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterLayout(final C4L3Parser.LayoutContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the alias of a person definition in a {@link SourceType#C4_L1} grammar has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterPerson(final C4L1Parser.PersonContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a person definition in a {@link SourceType#C4_L2} has the expected format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterPerson(final C4L2Parser.PersonContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a person definition in a {@link SourceType#C4_L3} has the expected format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterPerson(final C4L3Parser.PersonContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of an external person definition in a {@link SourceType#C4_L1} grammar has the expected
         * format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterPerson_ext(final C4L1Parser.Person_extContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of an external person definition in a {@link SourceType#C4_L2} has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterPerson_ext(final C4L2Parser.Person_extContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of an external person definition in a {@link SourceType#C4_L3} has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterPerson_ext(final C4L3Parser.Person_extContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the aliases of a relationship definition in a {@link SourceType#C4_L1} grammar have the expected
         * format or reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterRelationship(final C4L1Parser.RelationshipContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the aliases of a relationship definition in a {@link SourceType#C4_L2} have the expected format or
         * reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterRelationship(final C4L2Parser.RelationshipContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the aliases of a relationship definition in a {@link SourceType#C4_L3} have the expected format or
         * reports them.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterRelationship(final C4L3Parser.RelationshipContext ctx) {
            ctx.Alias().forEach(alias -> checkAliasFormat(alias, ctx));
        }

        /**
         * Checks that the alias of a system definition in a {@link SourceType#C4_L1} grammar has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem(final C4L1Parser.SystemContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a system definition in a {@link SourceType#C4_L2} has the expected format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem(final C4L2Parser.SystemContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a system definition in a {@link SourceType#C4_L3} has the expected format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem(final C4L3Parser.SystemContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of a system boundary definition in a {@link SourceType#C4_L2} has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem_boundary(final C4L2Parser.System_boundaryContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of an external system definition in a {@link SourceType#C4_L1} grammar has the expected
         * format or reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem_ext(final C4L1Parser.System_extContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of an external system definition in a {@link SourceType#C4_L2} has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem_ext(final C4L2Parser.System_extContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        /**
         * Checks that the alias of an external system definition in a {@link SourceType#C4_L3} has the expected format or
         * reports it.
         * <p>
         * {@inheritDoc}
         */
        @Override
        public void enterSystem_ext(final C4L3Parser.System_extContext ctx) {
            checkAliasFormat(ctx.Alias(), ctx);
        }

        private void checkAliasFormat(final TerminalNode alias, final ParserRuleContext context) {

            final Matcher matcher = this.aliasFormatPattern.matcher(alias.getText());

            if (!matcher.matches()) {

                final String message = String
                    .format(MESSAGE_FORMAT,
                        alias.getText(),
                        this.aliasFormat,
                        context.getText());

                this.reporter.report(message);
                rule.getLogger().debug(message);
            }
        }
    }