package org.apache.torque.generator.maven;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.torque.generator.configuration.ConfigurationException;
import org.apache.torque.generator.configuration.UnitDescriptor;
import org.apache.torque.generator.configuration.UnitDescriptor.Packaging;
import org.apache.torque.generator.configuration.controller.Loglevel;
import org.apache.torque.generator.configuration.option.MapOptionsConfiguration;
import org.apache.torque.generator.configuration.option.OptionsConfiguration;
import org.apache.torque.generator.configuration.paths.CustomProjectPaths;
import org.apache.torque.generator.configuration.paths.DefaultTorqueGeneratorPaths;
import org.apache.torque.generator.configuration.paths.Maven2DirectoryProjectPaths;
import org.apache.torque.generator.configuration.paths.Maven2JarProjectPaths;
import org.apache.torque.generator.configuration.paths.Maven2ProjectPaths;
import org.apache.torque.generator.configuration.paths.ProjectPaths;
import org.apache.torque.generator.control.Controller;
import org.apache.torque.generator.file.Fileset;
import org.apache.torque.generator.source.stream.FileSourceProvider;

/**
 * Executes a unit of generation within the torque generator.
 *
 * $Id: TorqueGeneratorMojo.java 1401885 2012-10-24 21:13:09Z tfischer $
 *
 * @goal generate
 */
public class TorqueGeneratorMojo extends AbstractMojo implements Mojo
{
    /** Possible usages for generator output directories. */
    private enum OutputDirUsage
    {
        /**
         * The output dir will be added to the maven project's
         * compileSourceRoot.
         */
        COMPILE("compile"),
        /**
         * The output dir will be added to the maven project's
         * testCompileSourceRoot.
         */
        TEST_COMPILE("test-compile"),
        /**
         * The output dir will be added to the maven project's resources.
         */
        RESOURCE("resource"),
        /**
         * The output dir will be added to the maven project's test resources.
         */
        TEST_RESOURCE("test-resource"),
        /**
         * The target dir will not be used in the maven build.
         */
        NONE("none");

        /** The usage key. */
        private final String key;

        /**
         * Constructor.
         *
         * @param key the key for the enum.
         */
        private OutputDirUsage(String key)
        {
            this.key = key;
        }

        @Override
        public String toString()
        {
            return key;
        }

        /**
         * Returns the key of the Usage.
         *
         * @return the key, not null.
         */
        public String getKey()
        {
            return key;
        }

        public static OutputDirUsage get(String key)
            throws MojoExecutionException
        {
            for (OutputDirUsage candidate : values())
            {
                if (candidate.getKey().equals(key))
                {
                    return candidate;
                }
            }
            StringBuilder errorMessage = new StringBuilder()
                .append("targetDirUsage contains illegal value: ")
                .append(key)
                .append(". Possible values are :");
            for (OutputDirUsage targetDirUsage : values())
            {
                errorMessage.append(" ").append(targetDirUsage.getKey());
            }
            throw new MojoExecutionException(errorMessage.toString());
        }
    }

    /**
     * The packaging type of the generation unit, either "directory" , "jar"
     * or "classpath".
     *
     * @parameter expression="directory"
     * @required
     */
    private String packaging;

    /**
     * The root directory of the project.
     * Has no effect if packaging is "classpath".
     *
     * @parameter expression="${basedir}"
     * @required
     */
    private File projectRootDir;

    /**
     * The configuration directory of the generation unit.
     * Has no effect if packaging is "classpath".
     *
     * @parameter
     */
    private File configDir;

    /**
     * The configuration package of the generation unit.
     * Has only effect if packaging is "classpath".
     *
     * @parameter
     */
    private String configPackage;

    /**
     * The directory where the source files reside.
     *
     * @parameter
     */
    private File sourceDir;

    /**
     * Include patterns for the source files.
     * If set, the include and exclude patterns from the templates
     * are overridden.
     * If not set, then the include patterns from the templates are used.
     * The patterns are case sensitive, wildcards are * and ?.
     *
     * @parameter
     */
    private Set<String> sourceIncludes;

    /**
     * Exclude patterns for the source files.
     * If set, the include and exclude patterns from the templates
     * are overridden.
     * If not set, then the include patterns from the templates are used.
     * The patterns are case sensitive, wildcards are * and ?.
     *
     * @parameter
     */
    private Set<String> sourceExcludes;

    /**
     * Whether all source files should be combined into one source tree.
     * If false, each source file will be read in its own source tree
     * and start a new generation run.
     * If true, a single source tree with the following structure will be
     * built from all source files:
     * &lt;source&gt;
     *   &lt;file path="path/to/file1"&gt;
     *      &lt;rootOfFile1&gt;
     *        ...
     *      &lt;/rootOfFile1&gt;
     *   &lt;/file&gt;
     *   &lt;file path="path/to/file2"&gt;
     *      &lt;rootOfFile2&gt;
     *        ...
     *      &lt;/rootOfFile2&gt;
     *   &lt;/file&gt;
     *   ...
     * &lt;/source&gt;
     * If not set, the settings from the templates will be used.
     *
     * @parameter
     */
    private Boolean combineFiles;

    /**
     * The default base output directory for the generated files.
     * Whether the configured templates use this directory or not,
     * is up to the templates; check the template documentation.
     *
     * @parameter expression="${project.build.directory}/generated-sources"
     * @required
     */
    private File defaultOutputDir;

    /**
     * The target directories for the generated files, keyed by the
     * output directory keys.
     * If output directory keys are used by the output
     * (and if yes, which output directory keys),
     * is up to the templates; check the template documentation.
     * Default is to map the key "modifiable" to
     * ${project.build.directory}/src/main/generated-java
     *
     * @parameter
     */
    private Map<String, String> outputDirMap = new HashMap<String, String>();

    /**
     * The work directory for e.g. merge sources.
     *
     * @parameter expression="${basedir}/src/main/torque-gen/work"
     */
    private File workDir;

    /**
     * The filename of the jar file of the generation unit.
     * Has only effect if packaging is "jar".
     *
     * @parameter
     */
    private String jarFile;

    /**
     * What to do with the generated files in the default output directory.
     * Possible values are:
     * <ul>
     *   <li>
     *     compile: The generated files are treated as compileable sources.
     *     In maven-speak, this means the newFileTargetDir will be added as
     *     compileSourceRoot of the maven project.
     *   </li>
     *   <li>
     *     test-compile: The generated files are treated as compileable
     *     test sources.
     *     In maven-speak, this means the newFileTargetDir will be added as
     *     testCompileSourceRoot of the maven project.
     *   </li>
     *   <li>
     *     resource: The generated files are treated as resource.
     *     This means the newFileTargetDir will be added to the
     *     resources of the maven project.
     *   </li>
     *   <li>
     *     test-resource: The generated files are treated as test resource.
     *     This means the newFileTargetDir will be added to the
     *     test resources of the maven project.
     *   </li>
     *   <li>
     *     none: The generated files are not used in the maven build.
     *   </li>
     *
     * @parameter expression="compile"
     * @required
     */
    private String defaultOutputDirUsage;

    /**
     * What to do with the generated files for the output directories
     * defined in outputDirMap. The map uses the same keys as outputDirMap.
     * Possible values are:
     * <ul>
     *   <li>
     *     compile: The generated files are treated as compileable sources.
     *     In maven-speak, this means the modifiedFileTargetDir will be added
     *     as compileSourceRoot of the maven project.
     *   </li>
     *   <li>
     *     test-compile: The generated files are treated as compileable
     *     test sources.
     *     In maven-speak, this means the modifiedFileTargetDir will be added
     *     as testCompileSourceRoot of the maven project.
     *   </li>
     *   <li>
     *     resource: The generated files are treated as resource.
     *     This means the modifiedFileTargetDir will be added to the
     *     resources of the maven project.
     *   </li>
     *   <li>
     *     test-resource: The generated files are treated as test resource.
     *     This means the modifiedFileTargetDir will be added to the
     *     test resources of the maven project.
     *   </li>
     *   <li>
     *     none: The generated files are not used in the maven build.
     *   </li>
     * Default is to map the key "modifiable" to compile
     *
     * @parameter
     */
    private Map<String, String> outputDirUsageMap
            = new HashMap<String, String>();

    /**
     * The config directory of the project overriding the settings.
     * If set, the settings of this directory are used as "child"
     * and the "normal" settings are used as "parent".
     *
     * @parameter
     */
    private File overrideConfigDir;

    /**
     * The config package of the project overriding the settings.
     * If set, the settings of this directory are used as "child"
     * and the "normal" settings are used as "parent".
     *
     * @parameter
     */
    private String overrideConfigPackage;

    /**
     * The Loglevel to use in the generation process. Must be one of
     * trace, debug, info, warn or error.
     *
     * @parameter
     */
    private String loglevel;

    /**
     * Whether to add debug information to the output.
     *
     * @parameter
     */
    private boolean addDebuggingInfoToOutput = false;

    /**
     * Additional options which can be added to the generation process.
     * This overrides both the options set in the templates
     * and the options in optionsFile.
     *
     * @parameter
     */
    private Map<String, String> options;

    /**
     * Properties file which contains the options which can be added
     * to the generation process.
     * This overrides the options set in the templates, but not the
     * options set by the parameter <code>options</code>.
     *
     * @parameter
     */
    private File optionsFile;

    /**
     * The encoding which should be used for the files which do not have an
     * output encoding set in the templates.
     * If not set, the property project.build.sourceEncoding from the
     * maven pom is used.
     * If that is also not set, the generator default is used
     * (which is the platform default encoding).
     *
     * @parameter
     */
    private String defaultOutputEncoding;

    /**
     * The Maven project this plugin runs in.
     *
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    private MavenProject project;

    /**
     * Configures and runs the Torque generator.
     */
    public void execute() throws MojoExecutionException
    {
        Controller controller = new Controller();
        List<UnitDescriptor> unitDescriptors = new ArrayList<UnitDescriptor>();

        // Do conversion here so illegal values are discovered before generation
        OutputDirUsage defaultOutputDirUsageConverted
                = OutputDirUsage.get(defaultOutputDirUsage);
        Map<String, OutputDirUsage> outputDirUsageConvertedMap
                = new HashMap<String, OutputDirUsage>();
        for (Map.Entry<String, String> outputDirUsageEntry
                : outputDirUsageMap.entrySet())
        {
            outputDirUsageConvertedMap.put(
                    outputDirUsageEntry.getKey(),
                    OutputDirUsage.get(outputDirUsageEntry.getValue()));
        }

        UnitDescriptor.Packaging packaging;
        if ("jar".equals(this.packaging))
        {
            packaging = UnitDescriptor.Packaging.JAR;
        }
        else if ("directory".equals(this.packaging))
        {
            packaging = UnitDescriptor.Packaging.DIRECTORY;
        }
        else if ("classpath".equals(this.packaging))
        {
            packaging = UnitDescriptor.Packaging.CLASSPATH;
        }
        else
        {
            throw new IllegalArgumentException(
                    "Unknown packaging " + this.packaging
                        + ", must be jar, directory or classpath");
        }
        getLog().debug("Packaging is " + packaging);

        ProjectPaths defaultProjectPaths;
        if (UnitDescriptor.Packaging.JAR == packaging)
        {
            defaultProjectPaths
                    = new Maven2JarProjectPaths(projectRootDir, jarFile);
        }
        else if (UnitDescriptor.Packaging.DIRECTORY == packaging)
        {
            defaultProjectPaths
                    = new Maven2DirectoryProjectPaths(projectRootDir);
        }
        else if (UnitDescriptor.Packaging.CLASSPATH == packaging)
        {
            defaultProjectPaths
                    = new Maven2DirectoryProjectPaths(projectRootDir);
        }
        else
        {
             throw new IllegalStateException("Unknown packaging" + packaging);
        }

        CustomProjectPaths projectPaths
                = new CustomProjectPaths(defaultProjectPaths);

        if (UnitDescriptor.Packaging.CLASSPATH == packaging)
        {
            if (configPackage == null)
            {
                throw new MojoExecutionException(
                    "configPackage must be set for packaging =\"classpath\"");
            }
            projectPaths.setConfigurationPackage(configPackage);
            projectPaths.setConfigurationDir(null);
        }
        else
        {
            if (configDir != null)
            {
                projectPaths.setConfigurationDir(configDir);
                getLog().debug("Setting config dir to " + configDir.toString());
            }
        }

        if (sourceDir != null)
        {
            projectPaths.setSourceDir(sourceDir);
            getLog().debug("Setting source dir to " + sourceDir.toString());
        }

        FileSourceProvider fileSourceProvider = null;
        if (sourceIncludes != null || sourceExcludes != null)
        {
            Fileset sourceFileset
                    = new Fileset(
                            projectPaths.getDefaultSourcePath(),
                            sourceIncludes,
                            sourceExcludes);
            getLog().debug("Setting source includes to "
                    + sourceIncludes);
            getLog().debug("Setting source excludes to "
                    + sourceExcludes);
            try
            {
                fileSourceProvider = new FileSourceProvider(
                        null,
                        sourceFileset,
                        combineFiles);
            }
            catch (ConfigurationException e)
            {
                throw new MojoExecutionException(
                        "The source provider cannot be instantiated", e);
            }
        }

        projectPaths.setOutputDirectory(null, defaultOutputDir);
        getLog().debug("Setting defaultOutputDir to "
                + defaultOutputDir.toString());
        if (outputDirMap != null)
        {
            if (outputDirMap.get(Maven2ProjectPaths.MODIFIABLE_OUTPUT_DIR_KEY)
                    == null)
            {
                outputDirMap.put(
                        Maven2ProjectPaths.MODIFIABLE_OUTPUT_DIR_KEY,
                        project.getBasedir()
                                + "/"
                                + Maven2ProjectPaths.MODIFIABLE_OUTPUT_DIR);
            }
            for (Map.Entry<String, String> outputDirMapEntry
                    : outputDirMap.entrySet())
            {
                projectPaths.setOutputDirectory(
                        outputDirMapEntry.getKey(),
                        new File(outputDirMapEntry.getValue()));
                getLog().debug("Setting output directory with key "
                        + outputDirMapEntry.getKey()
                        + " to "
                        + outputDirMapEntry.getValue());
            }
        }
        if (workDir != null)
        {
            projectPaths.setWorkDir(workDir);
            getLog().debug("Setting workDir to "
                    + workDir.toString());
        }
        getLog().debug("ProjectPaths = " + projectPaths);

        OptionsConfiguration optionConfiguration = null;
        if (options != null || optionsFile != null)
        {
            if (options == null)
            {
                options = new HashMap<String, String>();
            }
            if (optionsFile != null)
            {
                Properties optionProperties = new Properties();
                FileInputStream optionsFileInputStream = null;
                try
                {
                    optionsFileInputStream = new FileInputStream(optionsFile);
                    optionProperties.load(optionsFileInputStream);
                }
                catch (FileNotFoundException e)
                {
                    getLog().error(e);
                    throw new MojoExecutionException(e.getMessage());
                }
                catch (IOException e)
                {
                    getLog().error(e);
                    throw new MojoExecutionException(e.getMessage());
                }
                finally
                {
                    if (optionsFileInputStream != null)
                    {
                        try
                        {
                            optionsFileInputStream.close();
                        }
                        catch (IOException e)
                        {
                            getLog().error(e);
                        }
                    }
                }
                getLog().debug("loaded options file from "
                        + optionsFile.getAbsolutePath() + ", contents: "
                        + optionProperties);
                for (Map.Entry<Object, Object> propertiesEntry
                        : optionProperties.entrySet())
                {
                    if (!options.containsKey(propertiesEntry.getKey()))
                    {
                        options.put(
                                (String) propertiesEntry.getKey(),
                                (String) propertiesEntry.getValue());
                    }
                }
            }
            getLog().debug("options = " + options);
            optionConfiguration = new MapOptionsConfiguration(options);
        }
        Loglevel convertedLoglevel = null;
        if (this.loglevel != null)
        {
            convertedLoglevel = Loglevel.getByKey(loglevel);
        }
        String encoding = defaultOutputEncoding;
        if (encoding == null)
        {
            encoding = project.getProperties().getProperty(
                    "project.build.sourceEncoding");
        }
        UnitDescriptor unitDescriptor = new UnitDescriptor(
                packaging,
                projectPaths,
                new DefaultTorqueGeneratorPaths());
        unitDescriptor.setOverrideSourceProvider(fileSourceProvider);
        unitDescriptor.setOverrideOptions(optionConfiguration);
        unitDescriptor.setLoglevel(convertedLoglevel);
        unitDescriptor.setDefaultOutputEncoding(encoding);
        unitDescriptor.setAddDebuggingInfoToOutput(addDebuggingInfoToOutput);
        getLog().debug("unit descriptor created");
        if (overrideConfigDir != null)
        {
            CustomProjectPaths childProjectPaths
                = new CustomProjectPaths(projectPaths);
            childProjectPaths.setConfigurationDir(overrideConfigDir);

            UnitDescriptor parentUnitDescriptor = new UnitDescriptor(
                    Packaging.DIRECTORY,
                    childProjectPaths,
                    new DefaultTorqueGeneratorPaths());
            parentUnitDescriptor.setInheritsFrom(unitDescriptor);
            parentUnitDescriptor.setOverrideSourceProvider(fileSourceProvider);
            parentUnitDescriptor.setOverrideOptions(optionConfiguration);
            parentUnitDescriptor.setLoglevel(convertedLoglevel);
            parentUnitDescriptor.setDefaultOutputEncoding(encoding);
            getLog().debug("child unit descriptor created from directory");
            unitDescriptor = parentUnitDescriptor;
        }
        else if (overrideConfigPackage != null)
        {
            CustomProjectPaths childProjectPaths
                = new CustomProjectPaths(projectPaths);
            childProjectPaths.setConfigurationPackage(overrideConfigPackage);

            UnitDescriptor parentUnitDescriptor = new UnitDescriptor(
                    Packaging.CLASSPATH,
                    childProjectPaths,
                    new DefaultTorqueGeneratorPaths());
            parentUnitDescriptor.setInheritsFrom(unitDescriptor);
            parentUnitDescriptor.setOverrideSourceProvider(fileSourceProvider);
            parentUnitDescriptor.setOverrideOptions(optionConfiguration);
            parentUnitDescriptor.setLoglevel(convertedLoglevel);
            parentUnitDescriptor.setDefaultOutputEncoding(encoding);
            getLog().debug("child unit descriptor created from package");
            unitDescriptor = parentUnitDescriptor;
        }
        unitDescriptors.add(unitDescriptor);
        try
        {
            getLog().debug("Generation started");
            controller.run(unitDescriptors);
            getLog().info("Generation successful");
        }
        catch (Exception e)
        {
            getLog().error(e);
            throw new MojoExecutionException(e.getMessage());
        }

        File defaultOutputDirPath = projectPaths.getOutputDirectory(null);
        if (defaultOutputDirPath.exists())
        {
            switch (defaultOutputDirUsageConverted)
            {
            case COMPILE:
                project.addCompileSourceRoot(
                        defaultOutputDirPath.toString());
                getLog().debug("Added "
                        + defaultOutputDirPath.toString()
                        + " as compile source root");
                break;
            case TEST_COMPILE:
                project.addTestCompileSourceRoot(
                        defaultOutputDirPath.toString());
                getLog().debug("Added "
                        + defaultOutputDirPath.toString()
                        + " as test compile source root");
                break;
            case RESOURCE:
                Resource resource = new Resource();
                resource.setDirectory(defaultOutputDirPath.toString());
                project.addResource(resource);
                getLog().debug("Added "
                        + defaultOutputDirPath.toString()
                        + " to the project resources");
                break;
            case TEST_RESOURCE:
                resource = new Resource();
                resource.setDirectory(defaultOutputDirPath.toString());
                project.addTestResource(resource);
                getLog().debug("Added "
                        + defaultOutputDirPath.toString()
                        + " to the project test resources");
                break;
            case NONE:
            default:
            }
        }
        else
        {
            getLog().info("defaultOutputDirPath "
                + defaultOutputDirPath.getAbsolutePath()
                + " does not exist, not applying defaultOutputDirUsage");
        }

        if (outputDirUsageConvertedMap.get(
                Maven2ProjectPaths.MODIFIABLE_OUTPUT_DIR_KEY)
                  == null
            && outputDirMap.get(
                Maven2ProjectPaths.MODIFIABLE_OUTPUT_DIR_KEY)
                    != null)
        {
            outputDirUsageConvertedMap.put(
                    Maven2ProjectPaths.MODIFIABLE_OUTPUT_DIR_KEY,
                    OutputDirUsage.COMPILE);
        }
        for (Map.Entry<String, OutputDirUsage> usageEntry
                : outputDirUsageConvertedMap.entrySet())
        {
            String outputDirPath = outputDirMap.get(usageEntry.getKey());
            if (outputDirPath == null)
            {
                getLog().info("outputDirPath set for key "
                        + usageEntry.getKey()
                        + " ignoring this outputDirUsageMap entry");
                continue;
            }

            File outputDirFile = new File(outputDirPath);
            if (!outputDirFile.exists())
            {
                getLog().info("outputDirPath "
                        + outputDirFile.getAbsolutePath()
                        + " for outputDirUsageMap with key "
                        + usageEntry.getKey()
                        + " does not exist,"
                        + " ignoring this outputDirUsageMap entry");
                continue;
            }
            switch (usageEntry.getValue())
            {
            case COMPILE:
                project.addCompileSourceRoot(outputDirPath.toString());
                getLog().debug("Added "
                        + outputDirPath.toString()
                        + " as compile source root");
                break;
            case TEST_COMPILE:
                project.addTestCompileSourceRoot(
                        outputDirPath.toString());
                getLog().debug("Added "
                        + outputDirPath.toString()
                        + " as test compile source root");
                break;
            case RESOURCE:
                Resource resource = new Resource();
                resource.setDirectory(outputDirPath.toString());
                project.addResource(resource);
                getLog().debug("Added "
                        + outputDirPath.toString()
                        + " to the project resources");
                break;
            case TEST_RESOURCE:
                resource = new Resource();
                resource.setDirectory(outputDirPath.toString());
                project.addTestResource(resource);
                getLog().debug("Added "
                        + outputDirPath.toString()
                        + " to the project test resources");
                break;
            case NONE:
            default:
            }
        }
    }

    /**
     * Sets the packaging.
     *
     * @param packaging the packaging, either "jar" or "directory"
     */
    public void setPackaging(String packaging)
    {
        this.packaging = packaging;
    }

    /**
     * Sets the root directory of the project.
     *
     * @param projectRootDir the project root Directory.
     */
    public void setProjectRootDir(File projectRootDir)
    {
        this.projectRootDir = projectRootDir;
    }

    public void setConfigDir(File configDir)
    {
        this.configDir = configDir;
    }

    public void setConfigPackage(String configPackage)
    {
        this.configPackage = configPackage;
    }

    /**
     * Sets the default output directory for generated files.
     *
     * @param outputDir the default output directory, not null.
     */
    public void setDefaultOutputDir(File outputDir)
    {
        this.defaultOutputDir = outputDir;
    }

    /**
     * Sets the target directory for files which are not generated
     * each time anew.
     *
     * @param targetDir the target directory, or null to use the default.
     */
    public void setOutputDir(String outputDirKey, String outputDir)
    {
        this.outputDirMap.put(outputDirKey, outputDir);
    }

    /**
     * The path to the jar file to use.
     *
     * @param jarFile the jar file, or null.
     */
    public void setJarFile(String jarFile)
    {
        this.jarFile = jarFile;
    }

    /**
     * Sets the maven project this mojo runs in.
     *
     * @param project the maven project this mojo runs in.
     */
    public void setProject(MavenProject project)
    {
        this.project = project;
    }

    /**
     * Sets the usage for the default output dir.
     *
     * @param defaultOutputDirUsage the new usage, not null.
     */
    public void setDefaultOutputDirUsage(String defaultOutputDirUsage)
    {
        if (defaultOutputDirUsage == null)
        {
            throw new NullPointerException(
                    "defaultOutputDirUsage must not be null");
        }
        this.defaultOutputDirUsage = defaultOutputDirUsage;
    }

    /**
     * Sets the usage for an output directory.
     *
     * @param outputDirKey key for the output directory, not null.
     * @param outputDirUsage the new usage, not null.
     */
    public void setOutputDirUsage(
            String outputDirKey,
            String outputDirUsage)
    {
        if (outputDirKey == null)
        {
            throw new NullPointerException(
                    "outputDirKey must not be null");
        }
        if (outputDirUsage == null)
        {
            throw new NullPointerException(
                    "modifiedFileTargetDirUsage must not be null");
        }
        this.outputDirUsageMap.put(outputDirKey, outputDirUsage);
    }

    /**
     * Sets the directory in which the source files are located.
     *
     * @param sourceDir the directory in which the source files are located.
     */
    public void setSourceDir(File sourceDir)
    {
        this.sourceDir = sourceDir;
    }

    /**
     * Sets the pattern which files are included in the generation process.
     *
     * @param sourceIncludes a list containing the include patterns, or null
     *        if no include pattern should be used.
     */
    public void setSourceIncludes(Set<String> sourceIncludes)
    {
        this.sourceIncludes = sourceIncludes;
    }

    /**
     * Sets the pattern which files are excluded in the generation process.
     *
     * @param sourceExcludes a list containing the exclude patterns, or null
     *        if no exclude pattern should be used.
     */
    public void setSourceExcludes(Set<String> sourceExcludes)
    {
        this.sourceExcludes = sourceExcludes;
    }

    /**
     * Sets the config directory overriding the template settings.
     * If set, the settings of this directory are used as "child"
     * and the "normal" settings are used as "parent".
     *
     * @parameter the config directory overriding the template settings,
     *            or null if the template settings will not be overridden.
     */
    public void setOverrideConfigDir(File overrideConfigDir)
    {
        this.overrideConfigDir = overrideConfigDir;
    }

    /**
     * Sets the config package of the project overriding the settings.
     * If set, the settings of this directory are used as "child"
     * and the "normal" settings are used as "parent".
     *
     * @parameter the config package of the project overriding the settings,
     *            or null if the template settings will not be overridden.
     */
    public void setOverrideConfigPackage(String overrideConfigPackage)
    {
        this.overrideConfigPackage = overrideConfigPackage;
    }

    /**
     * Sets the Loglevel to use in the generation process.
     *
     * @param loglevel the loglevel, must be one of trace, debug, info, warn
     *        or error, or null if the loglevel defined in the templates
     *        should be used.
     */
    public void setLoglevel(String loglevel)
    {
        this.loglevel = loglevel;
    }

    /**
     * Sets the encoding which should be used for the files which do not have
     * an output encoding set in the templates.
     *
     * @param defaultOutputEncoding the default output encoding,
     *        or null to use the generator default
     *        (the platform default encoding).
     */
    public void setDefaultOutputEncoding(String defaultOutputEncoding)
    {
        this.defaultOutputEncoding = defaultOutputEncoding;
    }

    /**
     * Sets additional options which can be added to the generation process.
     * These options overrides existing options in the templates.
     *
     * @param options the overriding options, or null if no options
     *        should be overridden.
     */
    public void setOptions(Map<String, String> options)
    {
        this.options = options;
    }

    /**
     * Sets whether all source files should be combined into one single graph-
     *
     * @param combineFiles whether the source file should be combined.
     */
    public void setCombineFiles(Boolean combineFiles)
    {
        this.combineFiles = combineFiles;
    }

    /**
     * Sets the work dir for e.g. merging sources.
     *
     * @param workDir the new workdir.
     */
    public void setWorkDir(File workDir)
    {
        this.workDir = workDir;
    }

    /**
     * Sets a options file by which generation parameters can be set.
     *
     * @param optionsFile the path to the file containing the generation
     *        options.
     */
    public void setOptionsFile(File optionsFile)
    {
        this.optionsFile = optionsFile;
    }

    /**
     * Sets whether debugging information should be added to the output.
     *
     * @param addDebuggingInfoToOutput true if debugging information
     *        should be added to the output, false otherwise.
     */
    public void setAddDebuggingInfoToOutput(boolean addDebuggingInfoToOutput)
    {
        this.addDebuggingInfoToOutput = addDebuggingInfoToOutput;
    }
}
