/*
 * Copyright (c) 2012 by The Author(s)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.ferstl.maven.pomenforcers;

import java.util.Collection;

import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.logging.Log;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import com.github.ferstl.maven.pomenforcers.reader.DeclaredPluginsReader;
import com.github.ferstl.maven.pomenforcers.reader.XPathExpressions;
import com.github.ferstl.maven.pomenforcers.util.XmlUtils;

public class PedanticPluginConfigurationEnforcer extends AbstractPedanticEnforcer {

  private boolean manageVersions = true;
  private boolean manageConfigurations = true;
  private boolean manageDependencies = true;

  /**
   * Enforces plugin versions to be defined in `<pluginManagement>`.
   * @configParam
   * @default `true`
   * @param manageVersions
   */
  public void setManageVersions(boolean manageVersions) {
    this.manageVersions = manageVersions;
  }

  public void setManageConfigurations(boolean manageConfigurations) {
    this.manageConfigurations = manageConfigurations;
  }

  public void setManageDependencies(boolean manageDependencies) {
    this.manageDependencies = manageDependencies;
  }

  @Override
  protected void doEnforce(EnforcerRuleHelper helper, Document pom) throws EnforcerRuleException {
    Log log = helper.getLog();
    if (this.manageVersions) {
      log.info("Enforcing managed plugin versions.");
      enforceManagedVersions(pom);
    }

    if (this.manageConfigurations) {
      log.info("Enforcing managed plugin configurations.");
      enforceManagedConfiguration(pom);
    }

    if (this.manageDependencies) {
      log.info("Enforcing managed plugin dependencies.");
      enforceManagedDependencies(pom);
    }
  }

  private void enforceManagedVersions(Document pom) throws EnforcerRuleException {
    Collection<Plugin> versionedPlugins = searchForPlugins(pom, XPathExpressions.POM_VERSIONED_PLUGINS);
    if (versionedPlugins.size() > 0) {
      throw new EnforcerRuleException("One does not simply set versions on plugins. Plugin versions have to " +
      		"be declared in <pluginManagement>: " + versionedPlugins);
    }

  }

  private void enforceManagedConfiguration(Document pom) throws EnforcerRuleException {
    Collection<Plugin> configuredPlugins = searchForPlugins(pom, XPathExpressions.POM_CONFIGURED_PLUGINS);
    if (configuredPlugins.size() > 0) {
      throw new EnforcerRuleException("One does not simply configure plugins. Use <pluginManagement> to configure "
          +	"these plugins or configure them for a specific <execution>: " + configuredPlugins);
    }
  }

  private void enforceManagedDependencies(Document pom) throws EnforcerRuleException {
    Collection<Plugin> configuredPluginDependencies =
        searchForPlugins(pom, XPathExpressions.POM_CONFIGURED_PLUGIN_DEPENDENCIES);
    if (configuredPluginDependencies.size() > 0) {
      throw new EnforcerRuleException("One does not simply configure plugin dependencies. Use <pluginManagement> "
      	+ "to configure plugin dependencies: " + configuredPluginDependencies);
    }
  }

  private Collection<Plugin> searchForPlugins(Document pom, String xpath) {
    NodeList plugins = XmlUtils.evaluateXPathAsNodeList(xpath, pom);
    Document pluginsDoc = XmlUtils.createDocument("plugins", plugins);
    return new DeclaredPluginsReader(pluginsDoc).read(XPathExpressions.STANDALONE_PLUGINS);
  }

  @Override
  protected void accept(PedanticEnforcerVisitor visitor) {
    visitor.visit(this);
  }

}

@@ -1145,16 +1145,204 @@
 Utils;%0A%0A
+/**%0A * Enforces that plugins are configured in the %3Ccode%3EpluginManagement%3C/code%3E section.%0A * %3Cpre%3E%0A * ### Example%0A *%0A * %3C/pre%3E%0A * @id %7B@link PedanticEnforcerRule#PLUGIN_CONFIGURATION%7D%0A */%0A
 public c
@@ -1637,307 +1637,884 @@
  * @
-configParam%0A   * @default %60true%60%0A   * @param manageVersions%0A   */%0A  public void setManageVersions(boolean manageVersions) %7B%0A    this.manageVersions = manageVersions;%0A  %7D%0A%0A  public void setManageConfigurations(boolean manageConfigurations) %7B%0A    this.manageConfigurations = manageConfigurations;%0A  %7D%0A
+param manageVersions Enforces plugin versions to be defined in %60%3CpluginManagement%3E%60.%0A   * @configParam%0A   * @default %3Ccode%3Etrue%3C/code%3E%0A   */%0A  public void setManageVersions(boolean manageVersions) %7B%0A    this.manageVersions = manageVersions;%0A  %7D%0A%0A  /**%0A   * Enforces plugin %3Ccode%3Econfiguration%3C/code%3E to be defined in %60%3CpluginManagement%3E%60.%0A   * @param manageVersions Enforces plugin %3Ccode%3Econfiguration%3C/code%3E to be defined in %60%3CpluginManagement%3E%60.%0A   * @configParam%0A   * @default %3Ccode%3Etrue%3C/code%3E%0A   */%0A  public void setManageConfigurations(boolean manageConfigurations) %7B%0A    this.manageConfigurations = manageConfigurations;%0A  %7D%0A%0A  /**%0A   * Enforces plugin dependencies to be defined in %60%3CpluginManagement%3E%60.%0A   * @param manageVersions Enforces plugin %3Ccode%3Econfiguration%3C/code%3E to be defined in %60%3CpluginManagement%3E%60.%0A   * @configParam%0A   * @default %3Ccode%3Etrue%3C/code%3E%0A   */
 %0A  p

add documentation