/**
 * Copyright (C) 2000
 */

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.Copy;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.PatternSet;

import java.io.File;
import java.util.StringTokenizer;

/**
 * @author	<A HREF="mailto:sebastien.chassande@inrialpes.fr><b>
 *			Sebastien Chassande-Barrioz
 *			</b></A>
 */
public class MultipleCopy extends Copy {

	protected File basedir = null;
	protected String myFile = null;
	protected boolean notReplace = true;

	public void execute() throws BuildException {
		DirectoryScanner ds = getDirectoryScanner(basedir);
		String[] dirs = DirectoryScannerHelper.getSelectedFilesAsString(ds, getProject());
		String fileName = null;
		for (int i = 0; i < dirs.length; i++) {
			if (myFile == null) {
				fileName = basedir + "/" + dirs[i];
				super.setTodir(new File(fileName));
				super.setTofile(null);
			}
			else {
				super.setTodir(null);
				fileName = basedir + "/" + dirs[i] + "/" + myFile;
				super.setTofile(new File(fileName));
			}
			log("File name = " + fileName, Project.MSG_DEBUG);
			copy();
		}
	}

	/**
	 * Performs the copy operation.
	 */
	public void copy() throws BuildException {
          boolean ant16 = false;
          String version = getProject().getProperty("ant.version");
          StringTokenizer st = new StringTokenizer(version, " ");
          while (st.hasMoreTokens()) {
            String s = st.nextToken();
            if (s.length() > 2 && Character.isDigit(s.charAt(0)) && s.charAt(1) == '.') {
              if ((int)(s.charAt(0) - '0') > 1) {
                ant16 = true;
              } else if ((int)(s.charAt(2) - '0') > 5) {
                ant16 = true;
              }
              break;
            }
          }
		
                // make sure we don't have an illegal set of options
		validateAttributes();

		// deal with the single file
		if (file != null) {
			if (file.exists()) {
				if (destFile == null) {
					destFile = new File(destDir, file.getName());
				}
				if (!destFile.exists())
                                  if (ant16)
					fileCopyMap.put(file.getAbsolutePath(), new String[] { destFile.getAbsolutePath() });
                                  else
					fileCopyMap.put(file.getAbsolutePath(), destFile.getAbsolutePath());

				else if (!notReplace && ( forceOverwrite
						|| (file.lastModified() > destFile.lastModified()))
					) {
                                        if (ant16)
					  fileCopyMap.put(file.getAbsolutePath(), new String[] { destFile.getAbsolutePath() });
                                        else 
					  fileCopyMap.put(file.getAbsolutePath(), destFile.getAbsolutePath());
				}
				else {
					log(file + " omitted as " + destFile + " is up to date.",
						Project.MSG_VERBOSE);
				}
			}
			else {
				String message = "Could not find file "
					+ file.getAbsolutePath() + " to copy.";
				log(message);
				throw new BuildException(message);
			}
		}

		// deal with the filesets
		for (int i = 0; i < filesets.size(); i++) {
			FileSet fs = (FileSet) filesets.elementAt(i);
			DirectoryScanner ds = fs.getDirectoryScanner(getProject());
			File fromDir = fs.getDir(getProject());

			String[] srcFiles = ds.getIncludedFiles();
			String[] srcDirs = ds.getIncludedDirectories();

			scan(fromDir, destDir, srcFiles, srcDirs);
		}

		// do all the copy operations now...
		doFileOperations();

		// clean up destDir again - so this instance can be used a second
		// time without throwing an exception
		if (destFile != null) {
			destDir = null;
		}
	}

	public void setNotReplace(boolean nr) {
		notReplace = nr;
	}

	public void setTodir(File bd) {
		basedir = bd;
	}

	/**
	 * Sets the destination file.
	 */
	public void setTofile(String f) {
		myFile = f;
	}

	///////////////////////////////////////////////////////////////
	////////////////////// 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);
	}

}
