package net.ranides.assira.grammar;

import net.ranides.assira.generic.Ref;

import java.util.Collection;

public abstract class G4ParserCoverage {

    /**
     * Please note, that we store there both grammar rules and token rules
     *
     * @return rules
     */
    public abstract Collection<RuleCoverage> rules();

    public abstract Collection<BranchCoverage> branches();

    public abstract Ref<RuleCoverage> rule(String ruleName);

    public abstract Ref<BranchCoverage> branch(String ruleName);

    public void use(String ruleName) {
        rule(ruleName).ifPresent(rule -> {
            rule.use();
            // update back-references
            rules().stream().filter(v -> v.inner().contains(rule.name())).forEach(ref -> {
                use(ref.name());
            });
            branches().stream().filter(v -> v.inner().contains(rule.name())).forEach(ref -> {
                use(ref.qualifier());
            });
        });
        branch(ruleName).ifPresent(branch -> {
            branch.use();
            // update if all branches are visited
            rule(branch.rule()).ifPresent(parent -> {
                if(parent.branches().stream().allMatch(v -> v.used() > 0)) {
                    use(parent.name());
                }
            });
        });
    }

    public void use(G4Selector<?> selector) {
        selector.coverage().forEach(this::use);
    }

    public interface RuleCoverage {

        String name();

        Collection<BranchCoverage> branches();

        Ref<String> inner();

        int used();

        void use();
    }

    public interface BranchCoverage {

        String rule();

        String qualifier();

        Ref<String> inner();

        int used();

        void use();
    }
}
