# BundleChecker.java

    /*******************************************************************************
     * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
     * All rights reserved. This program and the accompanying materials
     * are made available under the terms of the Eclipse Public License v1.0
     * which accompanies this distribution, and is available at
     * http://www.eclipse.org/legal/epl-v10.html
     *
     * Contributors:
     *    Marc R. Hoffmann - initial API and implementation
     *
     *******************************************************************************/
    package org.jacoco.report.check;

    import java.util.ArrayList;
    import java.util.Collection;

    import org.jacoco.core.analysis.IBundleCoverage;
    import org.jacoco.core.analysis.IClassCoverage;
    import org.jacoco.core.analysis.ICoverageNode;
    import org.jacoco.core.analysis.IMethodCoverage;
    import org.jacoco.core.analysis.IPackageCoverage;
    import org.jacoco.core.analysis.ISourceFileCoverage;
    import org.jacoco.report.ILanguageNames;

    /**
     * Internal class to check a list of rules against a {@link IBundleCoverage}
     * instance.
     */
    class BundleChecker {

    	private final ILanguageNames names;
    	private final IViolationsOutput output;

    	private final Collection<Rule> bundleRules;
    	private final Collection<Rule> packageRules;
    	private final Collection<Rule> classRules;
    	private final ArrayList<Rule> sourceFileRules;
    	private final Collection<Rule> methodRules;

    	private final boolean traversePackages;
    	private final boolean traverseClasses;
    	private final boolean traverseSourceFiles;
    	private final boolean traverseMethods;

    	public BundleChecker(final Collection<Rule> rules,
    			final ILanguageNames names, final IViolationsOutput output) {
    		this.names = names;
    		this.output = output;
    		this.bundleRules = new ArrayList<Rule>();
    		this.packageRules = new ArrayList<Rule>();
    		this.classRules = new ArrayList<Rule>();
    		this.sourceFileRules = new ArrayList<Rule>();
    		this.methodRules = new ArrayList<Rule>();
    		for (final Rule rule : rules) {
    			switch (rule.getElement()) {
    			case BUNDLE:
    				bundleRules.add(rule);
    				break;
    			case PACKAGE:
    				packageRules.add(rule);
    				break;
    			case CLASS:
    				classRules.add(rule);
    				break;
    			case SOURCEFILE:
    				sourceFileRules.add(rule);
    				break;
    			case METHOD:
    				methodRules.add(rule);
    				break;
    			}
    		}
    		traverseMethods = !methodRules.isEmpty();
    		traverseClasses = !classRules.isEmpty() || traverseMethods;
    		traverseSourceFiles = !sourceFileRules.isEmpty();
    		traversePackages = !packageRules.isEmpty() || traverseClasses
    				|| traverseSourceFiles;
    	}

    	public void checkBundle(final IBundleCoverage bundleCoverage) {
    		final String name = bundleCoverage.getName();
    		checkRules(bundleCoverage, bundleRules, "bundle", name);
    		if (traversePackages) {
    			for (final IPackageCoverage p : bundleCoverage.getPackages()) {
    				check(p);
    			}
    		}
    	}

    	private void check(final IPackageCoverage packageCoverage) {
    		final String name = names.getPackageName(packageCoverage.getName());
    		checkRules(packageCoverage, packageRules, "package", name);
    		if (traverseClasses) {
    			for (final IClassCoverage c : packageCoverage.getClasses()) {
    				check(c);
    			}
    		}
    		if (traverseSourceFiles) {
    			for (final ISourceFileCoverage s : packageCoverage.getSourceFiles()) {
    				check(s);
    			}
    		}
    	}

    	private void check(final IClassCoverage classCoverage) {
    		final String name = names
    				.getQualifiedClassName(classCoverage.getName());
    		checkRules(classCoverage, classRules, "class", name);
    		if (traverseMethods) {
    			for (final IMethodCoverage m : classCoverage.getMethods()) {
    				check(m, classCoverage.getName());
    			}
    		}
    	}

    	private void check(final ISourceFileCoverage sourceFile) {
    		final String name = sourceFile.getPackageName() + "/"
    				+ sourceFile.getName();
    		checkRules(sourceFile, sourceFileRules, "source file", name);
    	}

    	private void check(final IMethodCoverage method, final String className) {
    		final String name = names.getQualifiedMethodName(className,
    				method.getName(), method.getDesc(), method.getSignature());
    		checkRules(method, methodRules, "method", name);
    	}

    	private void checkRules(final ICoverageNode node,
    			final Collection<Rule> rules, final String typename,
    			final String elementname) {
    		for (final Rule rule : rules) {
    			if (rule.matches(elementname)) {
    				for (final Limit limit : rule.getLimits()) {
    					checkLimit(node, typename, elementname, rule, limit);
    				}
    			}
    		}
    	}

    	private void checkLimit(final ICoverageNode node, final String elementtype,
    			final String typename, final Rule rule, final Limit limit) {
    		final String message = limit.check(node);
    		if (message != null) {
    			output.onViolation(node, rule, limit, String.format(
    					"Rule violated for %s %s: %s", elementtype, typename,
    					message));
    		}
    	}

    }