package de.andrena.tools.nopackagecycles;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import jdepend.framework.JDepend;
import jdepend.framework.JavaPackage;

import org.apache.maven.enforcer.rule.api.EnforcerRule;
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;

public class NoPackageCyclesRule implements EnforcerRule {

	private boolean includeTests = true;

	public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
		try {
			executePackageCycleCheckIfNecessary(helper);
		} catch (ExpressionEvaluationException e) {
			throw new EnforcerRuleException("Unable to lookup an expression " + e.getLocalizedMessage(), e);
		} catch (IOException e) {
			throw new EnforcerRuleException("Unable to access target directory " + e.getLocalizedMessage(), e);
		}
	}

	private void executePackageCycleCheckIfNecessary(EnforcerRuleHelper helper)
			throws ExpressionEvaluationException, IOException, EnforcerRuleException {
		DirectoriesWithClasses directories = new DirectoriesWithClasses(helper, includeTests);
		if (directories.directoriesWithClassesFound()) {
			executePackageCycleCheck(directories);
		} else {
			helper.getLog().info("No directories with classes to check for cycles found.");
		}
	}

	private void executePackageCycleCheck(Iterable<File> directories) throws IOException, EnforcerRuleException {
		JDepend jdepend = createJDepend();
		for (File directory : directories) {
			jdepend.addDirectory(directory.getAbsolutePath());
		}
		jdepend.analyze();
		if (jdepend.containsCycles()) {
			throw new EnforcerRuleException("There are package cycles:" + getPackageCycles(jdepend));
		}
	}

	protected JDepend createJDepend() {
		return new JDepend();
	}

	private String getPackageCycles(JDepend jdepend) {
		Collection<JavaPackage> packages = jdepend.getPackages();
		return new PackageCycleOutput(new ArrayList<JavaPackage>(packages)).getOutput();
	}

	public String getCacheId() {
		return "";
	}

	public boolean isCacheable() {
		return false;
	}

	public boolean isResultValid(EnforcerRule arg0) {
		return false;
	}

	public void setIncludeTests(boolean includeTests) {
		this.includeTests = includeTests;
	}
}
@@ -147,16 +147,40 @@
 ection;%0D
+%0Aimport java.util.List;%0D
 %0A%0D%0Aimpor
@@ -247,16 +247,57 @@
 ackage;%0D
+%0Aimport jdepend.framework.PackageFilter;%0D
 %0A%0D%0Aimpor
@@ -672,16 +672,138 @@
 = true;%0D
+%0A%09private List%3CString%3E includedPackages = new ArrayList%3C%3E();%0D%0A%09private List%3CString%3E excludedPackages = new ArrayList%3C%3E();%0D
 %0A%0D%0A%09publ
@@ -2143,24 +2143,111 @@
 new JDepend(
+PackageFilter.all()%0D%0A%09%09%09%09.including(includedPackages)%0D%0A%09%09%09%09.excluding(excludedPackages)
 );%0D%0A%09%7D%0D%0A%0D%0A%09p
@@ -2721,13 +2721,251 @@
 Tests;%0D%0A
-
 %09%7D%0D%0A
+%0D%0A%09public void setIncludedPackages(List%3CString%3E includedPackages) %7B%0D%0A%09%09this.includedPackages = includedPackages;%0D%0A%09%7D%0D%0A%0D%0A%09public void setExcludedPackages(List%3CString%3E excludedPackages) %7B%0D%0A%09%09this.excludedPackages = excludedPackages;%0D%0A%09%7D%0D%0A%0D%0A
 %7D

Allow to specify packages to include/exclude.