/**
 * @Contributors:<A HREF="mailto:sebastien.chassande@inrialpes.fr>
 * <b>S. Chassande-Barrioz</b></A>
 */

package org.objectweb.util.ant;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Ant;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.PatternSet;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collection;

/**
 * This task calls all xml files into the specified Dir
 */
public class MultipleAnt extends Ant implements FilenameFilter {

    protected File directory = null;

    protected String antFile = null;

    protected String target = null;

    private String[] getSelectedFiles() {
        Collection result = Arrays.asList(getDirectoryScanner(directory)
                .getIncludedFiles());
        Collection toDeselct = Arrays.asList(getDirectoryScanner(directory)
                .getExcludedFiles());
        log(toDeselct.toString(), Project.MSG_DEBUG);
        result.removeAll(toDeselct);
        return (String[]) result.toArray(new String[result.size()]);
    }

    /**
     * Search all files in the directory. Foreach set the antfile on the ant
     * task and execute the ant task.
     */
    public void execute() throws BuildException {
        String fileName = null;
        if (directory == null)
            throw new BuildException("The Dir parameter is required !");
        String[] dirs = getSelectedFiles();
        if (dirs == null || dirs.length == 0) {
            log("No directory found", Project.MSG_DEBUG);
            return;
        }
        int nbOK = 0;
        for (int j = 0; j < dirs.length; j++) {
            fileName = null;
            File dir = new File(directory, dirs[j]);
            if (dir.isFile()) {
                log("file=" + dir.getAbsolutePath(), Project.MSG_DEBUG);
                fileName = dir.getAbsolutePath();
            } else if (antFile != null) {
                // A file name has been specified by the user
                // then call the file
                fileName = dir.getAbsolutePath() + File.separator + antFile;
                log("Directory + antFile=" + fileName, Project.MSG_DEBUG);
            }
            if (fileName != null) {
                if ((new File(fileName)).exists() && fileName.endsWith(".xml")) {
                    if (execute(fileName)) {
                        nbOK++;
                    }
                }
            } else {
                log("Directory=" + dir.getAbsolutePath(), Project.MSG_DEBUG);
                // No file name has been specified by the user
                // then try with all
                String[] xmls = dir.list(this);
                if (xmls == null) {
                    log("No xml file found", Project.MSG_DEBUG);
                    continue;
                }
                for (int i = 0; i < xmls.length; i++) {
                    fileName = directory.getAbsolutePath() + File.separator
                            + xmls[i];
                    if (execute(fileName)) {
                        nbOK++;
                    }
                }
            }
        }
        if (nbOK == 0) {
            log("No task executed ...", Project.MSG_WARN);
        } else {
            log(nbOK + " task(s) executed.", Project.MSG_DEBUG);
        }
    }

    private boolean execute(String fileName) {
        log("execute=" + fileName, Project.MSG_VERBOSE);
        super.setAntfile(fileName);
        if (target != null) {
            super.setTarget(target);
        }
        try {
            super.execute();
            return true;
        } catch (Exception e) {
            log("Error in " + fileName + " file:\n\t" + e.getMessage(),
                    Project.MSG_VERBOSE);
            return false;
        }
    }

    /**
     * Set the directory where find xml file(s). The field "dir" is required to
     * use this task.
     */
    public void setDir(File d) {
        directory = d;
    }

    public void setAntFile(String f) {
        antFile = f;
    }

    public void setTarget(String t) {
        target = t;
    }

    /**
     * This method is used to chack if a file is a xml file.
     */
    public boolean accept(File dir, String name) {
        return name != null && dir != null && dir.equals(directory)
                && name.endsWith(".xml");
    }

    // /////////////////////////////////////////////////////////////
    // //////////////////// MATCHING TASK //////////////////////////
    // /////////////////////////////////////////////////////////////

    protected boolean useDefaultExcludes = true;

    protected FileSet fileset = new FileSet();

    /**
     * add a name entry on the include list
     */
    public PatternSet.NameEntry createInclude() {
        return fileset.createInclude();
    }

    /**
     * add a name entry on the include files list
     */
    public PatternSet.NameEntry createIncludesFile() {
        return fileset.createIncludesFile();
    }

    /**
     * add a name entry on the exclude list
     */
    public PatternSet.NameEntry createExclude() {
        return fileset.createExclude();
    }

    /**
     * add a name entry on the include files list
     */
    public PatternSet.NameEntry createExcludesFile() {
        return fileset.createExcludesFile();
    }

    /**
     * add a set of patterns
     */
    public PatternSet createPatternSet() {
        return fileset.createPatternSet();
    }

    /**
     * Sets the set of include patterns. Patterns may be separated by a comma or
     * a space.
     * 
     * @param includes
     *            the string containing the include patterns
     */
    public void setIncludes(String includes) {
        fileset.setIncludes(includes);
    }

    /**
     * Sets the set of exclude patterns. Patterns may be separated by a comma or
     * a space.
     * 
     * @param excludes
     *            the string containing the exclude patterns
     */
    public void setExcludes(String excludes) {
        fileset.setExcludes(excludes);
    }

    /**
     * Sets whether default exclusions should be used or not.
     * 
     * @param useDefaultExcludes
     *            "true"|"on"|"yes" when default exclusions should be used,
     *            "false"|"off"|"no" when they shouldn't be used.
     */
    public void setDefaultexcludes(boolean useDefaultExcludes) {
        this.useDefaultExcludes = useDefaultExcludes;
    }

    /**
     * Returns the directory scanner needed to access the files to process.
     */
    protected DirectoryScanner getDirectoryScanner(File baseDir) {
        fileset.setDir(baseDir);
        fileset.setDefaultexcludes(useDefaultExcludes);
        return fileset.getDirectoryScanner(getProject());
    }

    /**
     * Sets the name of the file containing the includes patterns.
     * 
     * @param includesfile
     *            A string containing the filename to fetch the include patterns
     *            from.
     */
    public void setIncludesfile(File includesfile) {
        fileset.setIncludesfile(includesfile);
    }

    /**
     * Sets the name of the file containing the includes patterns.
     * 
     * @param excludesfile
     *            A string containing the filename to fetch the include patterns
     *            from.
     */
    public void setExcludesfile(File excludesfile) {
        fileset.setExcludesfile(excludesfile);
    }

}
