/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "Ant" and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.tools.ant.taskdefs.optional.scm;

import java.util.StringTokenizer;

import com.starbase.starteam.Folder;
import com.starbase.starteam.Item;
import com.starbase.starteam.Property;
import com.starbase.starteam.Server;
import com.starbase.starteam.StarTeamFinder;
import com.starbase.starteam.Type;
import com.starbase.starteam.View;
import com.starbase.util.Platform;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;

/**
 * Checks out files from a specific StarTeam server, project, view, and
 * folder.
 * <BR><BR>
 * This program logs in to a StarTeam server and opens up the specified
 * project and view.  Then, it searches through that view for the given
 * folder (or, if you prefer, it uses the root folder).  Beginning with
 * that folder and optionally continuing recursivesly, AntStarTeamCheckOut
 * compares each file with your include and exclude filters and checks it
 * out only if appropriate.
 * <BR><BR>
 * Checked out files go to a directory you specify under the subfolder
 * named for the default StarTeam path to the view.  That is, if you
 * entered /home/cpovirk/work as the target folder, your project was named
 * "OurProject," the given view was named "TestView," and that view is
 * stored by default at "C:\projects\Test," your files would be checked
 * out to /home/cpovirk/work/Test."  I avoided using the project name in
 * the path because you may want to keep several versions of the same
 * project on your computer, and I didn't want to use the view name, as
 * there may be many "Test" or "Version 1.0" views, for example.  This
 * system's success, of course, depends on what you set the default path
 * to in StarTeam.
 * <BR><BR>
 * You can set AntStarTeamCheckOut to verbose or quiet mode.  Also, it has
 * a safeguard against overwriting the files on your computer:  If the
 * target directory you specify already exists, the program will throw a
 * BuildException.  To override the exception, set <CODE>force</CODE> to
 * true.
 * <BR><BR>
 * <B>This program makes use of functions from the StarTeam API.  As a result
 * AntStarTeamCheckOut is available only to licensed users of StarTeam and
 * requires the StarTeam SDK to function.  You must have
 * <CODE>starteam-sdk.jar</CODE> in your classpath to run this program.
 * For more information about the StarTeam API and how to license it, see
 * the link below.</B>
 *
 * @author <A HREF="mailto:chris.povirk@paytec.com">Chris Povirk</A>
 * @author <A HREF="mailto:jc.mann@paytec.com">JC Mann</A>
 * @author <A HREF="mailto:jeff.gettle@paytec.com">Jeff Gettle</A>
 * @author <A HREF="mailto:stevec@ignitesports.com">Steve Cohen</A>
 * @version 1.0
 * @see <A HREF="http://www.starbase.com/">StarBase Web Site</A>
 *
 * @ant.task name="starteam" category="scm" ignore="true"
 */
public class AntStarTeamCheckOut extends org.apache.tools.ant.Task {

    /**
     * This constant sets the filter to include all files. This default has
     * the same result as <CODE>setIncludes("*")</CODE>.
     *
     * @see #getIncludes()
     * @see #setIncludes(String includes)
     */
    public static final String DEFAULT_INCLUDESETTING = "*";

    /**
     * This disables the exclude filter by default. In other words, no files
     * are excluded. This setting is equivalent to <CODE>setExcludes(null)</CODE>
     * .
     *
     * @see #getExcludes()
     * @see #setExcludes(String excludes)
     */
    public static final String DEFAULT_EXCLUDESETTING = null;

    /**
     * The default folder to search; the root folder. Since
     * AntStarTeamCheckOut searches subfolders, by default it processes an
     * entire view.
     *
     * @see #getFolderName()
     * @see #setFolderName(String folderName)
     */
    public static final String DEFAULT_FOLDERSETTING = null;

    /**
     * This is used when formatting the output. The directory name is
     * displayed only when it changes.
     */
    private Folder prevFolder = null;

    /** This field keeps count of the number of files checked out.  */
    private int checkedOut = 0;

    // Change these through their GET and SET methods.

    /** The name of the server you wish to connect to.  */
    private String serverName = null;

    /** The port on the server used for StarTeam.  */
    private int serverPort = -1;

    /** The name of your project.  */
    private String projectName = null;

    /**
     * The name of the folder you want to check out files from. All subfolders
     * will be searched, as well.
     */
    private String folderName = DEFAULT_FOLDERSETTING;

    /** The view that the files you want are in.  */
    private String viewName = null;

    /** Your username on the StarTeam server.  */
    private String username = null;

    /** Your StarTeam password.  */
    private String password = null;

    /**
     * The path to the root folder you want to check out to. This is a local
     * directory.
     */
    private String targetFolder = null;

    /**
     * If force set to true, AntStarTeamCheckOut will overwrite files in the
     * target directory.
     */
    private boolean force = false;

    /**
     * When verbose is true, the program will display all files and
     * directories as they are checked out.
     */
    private boolean verbose = false;

    /**
     * Set recursion to false to check out files in only the given folder and
     * not in its subfolders.
     */
    private boolean recursion = true;

    // These fields deal with includes and excludes

    /** All files that fit this pattern are checked out.  */
    private String includes = DEFAULT_INCLUDESETTING;

    /** All files fitting this pattern are ignored.  */
    private String excludes = DEFAULT_EXCLUDESETTING;

    /** The file delimitor on the user's system.  */
    private String delim = Platform.getFilePathDelim();

    /**
     * whether to use the Starteam "default folder" when calculating the
     * target paths to which files are checked out (false) or if targetFolder
     * represents an absolute mapping to folderName.
     */
    private boolean targetFolderAbsolute = false;


    /** convenient method to check for conditions */
    private static void assertTrue(boolean value, String msg) throws BuildException {
        if (!value) {
            throw new BuildException(msg);
        }
    }


    protected void checkParameters() throws BuildException {
        // Check all of the properties that are required.
        assertTrue(getServerName() != null, "ServerName must be set.");
        assertTrue(getServerPort() != -1, "ServerPort must be set.");
        assertTrue(getProjectName() != null, "ProjectName must be set.");
        assertTrue(getViewName() != null, "ViewName must be set.");
        assertTrue(getUsername() != null, "Username must be set.");
        assertTrue(getPassword() != null, "Password must be set.");
        assertTrue(getTargetFolder() != null, "TargetFolder must be set.");

        // Because of the way I create the full target path, there
        // must be NO slash at the end of targetFolder and folderName
        // However, if the slash or backslash is the only character, leave it alone
        if ((getTargetFolder().endsWith("/") ||
            getTargetFolder().endsWith("\\"))
             && getTargetFolder().length() > 1) {
            setTargetFolder(getTargetFolder().substring(0, getTargetFolder().length() - 1));
        }

        // Check to see if the target directory exists.
        java.io.File dirExist = new java.io.File(getTargetFolder());

        if (dirExist.isDirectory() && !getForce()) {
            throw new BuildException("Target directory exists. Set \"force\" "
                 + "to \"true\" to continue anyway.");
        }
    }


    /**
     * Do the execution.
     *
     * @exception BuildException
     */
    public void execute() throws BuildException {
        log("DEPRECATED - The starteam task is deprecated.  Use stcheckout instead.",
            Project.MSG_WARN);

        // Connect to the StarTeam server, and log on.
        Server s = getServer();

        try {
            // Search the items on this server.
            runServer(s);
        } finally {
            // Disconnect from the server.
            s.disconnect();
        }
        // after you are all of the properties are ok, do your thing
        // with StarTeam.  If there are any kind of exceptions then
        // send the message to the project log.

        // Tell how many files were checked out.
        log(checkedOut + " files checked out.");
    }


    /**
     * Creates and logs in to a StarTeam server.
     *
     * @return A StarTeam server.
     */
    protected Server getServer() {
        // Simplest constructor, uses default encryption algorithm and compression level.
        Server s = new Server(getServerName(), getServerPort());

        // Optional; logOn() connects if necessary.
        s.connect();

        // Logon using specified user name and password.
        s.logOn(getUsername(), getPassword());

        return s;
    }


    /**
     * Searches for the specified project on the server.
     *
     * @param s A StarTeam server.
     */
    protected void runServer(Server s) {
        com.starbase.starteam.Project[] projects = s.getProjects();

        for (int i = 0; i < projects.length; i++) {
            com.starbase.starteam.Project p = projects[i];

            if (p.getName().equals(getProjectName())) {
                if (getVerbose()) {
                    log("Found " + getProjectName() + delim);
                }
                runProject(s, p);
                break;
            }
        }
    }


    /**
     * Searches for the given view in the project.
     *
     * @param s A StarTeam server.
     * @param p A valid project on the given server.
     */
    protected void runProject(Server s, com.starbase.starteam.Project p) {
        View[] views = p.getViews();

        for (int i = 0; i < views.length; i++) {
            View v = views[i];

            if (v.getName().equals(getViewName())) {
                if (getVerbose()) {
                    log("Found " + getProjectName() + delim + getViewName() + delim);
                }
                runType(s, p, v, s.typeForName(s.getTypeNames().FILE));
                break;
            }
        }
    }


    /**
     * Searches for folders in the given view.
     *
     * @param s A StarTeam server.
     * @param p A valid project on the server.
     * @param v A view name from the specified project.
     * @param t An item type which is currently always "file".
     */
    protected void runType(Server s, com.starbase.starteam.Project p, View v, Type t) {
        // This is ugly; checking for the root folder.
        Folder f = v.getRootFolder();

        if (getFolderName() != null) {
            if (getFolderName().equals("\\") || getFolderName().equals("/")) {
                setFolderName(null);
            } else {
                f = StarTeamFinder.findFolder(v.getRootFolder(), getFolderName());
                assertTrue(null != f, "ERROR: " + getProjectName() + delim + getViewName() + delim +
                    v.getRootFolder() + delim + getFolderName() + delim +
                    " does not exist.");
            }
        }

        if (getVerbose() && getFolderName() != null) {
            log("Found " + getProjectName() + delim + getViewName() +
                delim + getFolderName() + delim + "\n");
        }

        // For performance reasons, it is important to pre-fetch all the
        // properties we'll need for all the items we'll be searching.

        // We always display the ItemID (OBJECT_ID) and primary descriptor.
        int nProperties = 2;

        // We'll need this item type's primary descriptor.
        Property p1 = getPrimaryDescriptor(t);

        // Does this item type have a secondary descriptor?
        // If so, we'll need it.
        Property p2 = getSecondaryDescriptor(t);

        if (p2 != null) {
            nProperties++;
        }

        // Now, build an array of the property names.
        String[] strNames = new String[nProperties];
        int iProperty = 0;

        strNames[iProperty++] = s.getPropertyNames().OBJECT_ID;
        strNames[iProperty++] = p1.getName();
        if (p2 != null) {
            strNames[iProperty++] = p2.getName();
        }

        // Pre-fetch the item properties and cache them.
        f.populateNow(t.getName(), strNames, -1);

        // Now, search for items in the selected folder.
        runFolder(s, p, v, t, f, calcTargetFolder(v, f));

        // Free up the memory used by the cached items.
        f.discardItems(t.getName(), -1);
    }


    /**
     * Returns a file object that defines the root of the local checkout tree.
     * Depending on the value of targetFolderAbsolute, this will be either the
     * targetFolder exactly as set by the user or the path formed by appending
     * the default folder onto the specified target folder.
     *
     * @param v view from which the file is checked out, supplies the "default
     *      folder"
     * @param rootSourceFolder root folder of the checkout operation in Star
     *      Team
     * @return an object referencing the local file
     * @see #getTargetFolderAbsolute()
     */
    private java.io.File calcTargetFolder(View v, Folder rootSourceFolder) {
        java.io.File root = new java.io.File(getTargetFolder());

        if (!getTargetFolderAbsolute()) {
            // Create a variable dir that contains the name of
            // the StarTeam folder that is the root folder in this view.
            // Get the default path to the current view.
            String defaultPath = v.getDefaultPath();

            // convert whatever separator char is in starteam to that of the target system.
            defaultPath = defaultPath.replace('/', java.io.File.separatorChar);
            defaultPath = defaultPath.replace('\\', java.io.File.separatorChar);

            java.io.File dir = new java.io.File(defaultPath);
            String dirName = dir.getName();

            // If it ends with separator then strip it off
            if (dirName.endsWith(delim)) {
                dirName = dirName.substring(0, dirName.length() - 1);
            }

            // Replace the projectName in the file's absolute path to the viewName.
            // This makes the root target of a checkout operation equal to:
            // targetFolder + dirName
            StringTokenizer pathTokenizer = new StringTokenizer(rootSourceFolder.getFolderHierarchy(), delim);
            String currentToken = null;
            boolean foundRoot = false;

            while (pathTokenizer.hasMoreTokens()) {
                currentToken = pathTokenizer.nextToken();
                if (currentToken.equals(getProjectName()) && !foundRoot) {
                    currentToken = dirName;
                    foundRoot = true;// only want to do this the first time
                }
                root = new java.io.File(root, currentToken);
            }
        }

        return root;
    }


    /**
     * Searches for files in the given folder. This method is recursive and
     * thus searches all subfolders.
     *
     * @param s A StarTeam server.
     * @param p A valid project on the server.
     * @param v A view name from the specified project.
     * @param t An item type which is currently always "file".
     * @param f The folder to search.
     * @param tgt Target folder on local machine
     */
    protected void runFolder(Server s,
                             com.starbase.starteam.Project p,
                             View v,
                             Type t,
                             Folder f,
                             java.io.File tgt) {
        // Process all items in this folder.
        Item[] items = f.getItems(t.getName());

        for (int i = 0; i < items.length; i++) {
            runItem(s, p, v, t, f, items[i], tgt);
        }

        // Process all subfolders recursively if recursion is on.
        if (getRecursion()) {
            Folder[] subfolders = f.getSubFolders();

            for (int i = 0; i < subfolders.length; i++) {
                runFolder(s, p, v, t, subfolders[i], new java.io.File(tgt, subfolders[i].getName()));
            }
        }
    }


    /**
     * Check out one file if it matches the include filter but not the exclude
     * filter.
     *
     * @param s A StarTeam server.
     * @param p A valid project on the server.
     * @param v A view name from the specified project.
     * @param t An item type which is currently always "file".
     * @param f The folder the file is localed in.
     * @param item The file to check out.
     * @param tgt target folder on local machine
     */
    protected void runItem(Server s,
                           com.starbase.starteam.Project p,
                           View v,
                           Type t,
                           Folder f,
                           Item item,
                           java.io.File tgt) {
        // Get descriptors for this item type.
        Property p1 = getPrimaryDescriptor(t);
        Property p2 = getSecondaryDescriptor(t);

        String pName = (String) item.get(p1.getName());

        if (!shouldCheckout(pName)) {
            return;
        }

        // VERBOSE MODE ONLY
        if (getVerbose()) {
            // Show folder only if changed.
            boolean bShowHeader = (f != prevFolder);

            if (bShowHeader) {
                // We want to display the folder the same way you would
                // enter it on the command line ... so we remove the
                // View name (which is also the name of the root folder,
                // and therefore shows up at the start of the path).
                String strFolder = f.getFolderHierarchy();
                int i = strFolder.indexOf(delim);

                if (i >= 0) {
                    strFolder = strFolder.substring(i + 1);
                }
                log("            Folder: \"" + strFolder + "\"");
                prevFolder = f;

                // If we displayed the project, view, item type, or folder,
                // then show the list of relevant item properties.
                StringBuffer header = new StringBuffer("                Item");

                header.append(",\t").append(p1.getDisplayName());
                if (p2 != null) {
                    header.append(",\t").append(p2.getDisplayName());
                }
                log(header.toString());
            }

            // Finally, show the Item properties ...
            // Always show the ItemID.
            StringBuffer itemLine = new StringBuffer("                ");

            itemLine.append(item.getItemID());

            // Show the primary descriptor.
            // There should always be one.
            itemLine.append(",\t").append(formatForDisplay(p1, item.get(p1.getName())));

            // Show the secondary descriptor, if there is one.
            // Some item types have one, some don't.
            if (p2 != null) {
                itemLine.append(",\t").append(formatForDisplay(p2, item.get(p2.getName())));
            }

            // Show if the file is locked.
            int locker = item.getLocker();

            if (locker > -1) {
                itemLine.append(",\tLocked by ").append(locker);
            } else {
                itemLine.append(",\tNot locked");
            }
            log(itemLine.toString());
        }
        // END VERBOSE ONLY

        // Check it out; also ugly.

        // Change the item to be checked out to a StarTeam File.
        com.starbase.starteam.File remote = (com.starbase.starteam.File) item;

        // The local file name is simply the local target path (tgt) which has
        // been passed recursively down from the top of the tree, with the item's name appended.
        java.io.File local = new java.io.File(tgt, (String) item.get(p1.getName()));

        try {
            remote.checkoutTo(local, Item.LockType.UNCHANGED, false, true, true);
            checkedOut++;
        } catch (Exception e) {
            throw new BuildException("Failed to checkout '" + local + "'", e);
        }
    }


    /**
     * Look if the file should be checked out. Don't check it out if It fits
     * no include filters and It fits an exclude filter.
     *
     * @param pName the item name to look for being included.
     * @return whether the file should be checked out or not.
     */
    protected boolean shouldCheckout(String pName) {
        boolean includeIt = matchPatterns(getIncludes(), pName);
        boolean excludeIt = matchPatterns(getExcludes(), pName);

        return (includeIt && !excludeIt);
    }


    /**
     * Convenient method to see if a string match a one pattern in given set
     * of space-separated patterns.
     *
     * @param patterns the space-separated list of patterns.
     * @param pName the name to look for matching.
     * @return whether the name match at least one pattern.
     */
    protected boolean matchPatterns(String patterns, String pName) {
        if (patterns == null) {
            return false;
        }
        StringTokenizer exStr = new StringTokenizer(patterns, " ");

        while (exStr.hasMoreTokens()) {
            if (DirectoryScanner.match(exStr.nextToken(), pName)) {
                return true;
            }
        }
        return false;
    }


    /**
     * Get the primary descriptor of the given item type. Returns null if
     * there isn't one. In practice, all item types have a primary descriptor.
     *
     * @param t An item type. At this point it will always be "file".
     * @return The specified item's primary descriptor.
     */
    protected Property getPrimaryDescriptor(Type t) {
        Property[] properties = t.getProperties();

        for (int i = 0; i < properties.length; i++) {
            Property p = properties[i];

            if (p.isPrimaryDescriptor()) {
                return p;
            }
        }
        return null;
    }


    /**
     * Get the secondary descriptor of the given item type. Returns null if
     * there isn't one.
     *
     * @param t An item type. At this point it will always be "file".
     * @return The specified item's secondary descriptor. There may not be one
     *      for every file.
     */
    protected Property getSecondaryDescriptor(Type t) {
        Property[] properties = t.getProperties();

        for (int i = 0; i < properties.length; i++) {
            Property p = properties[i];

            if (p.isDescriptor() && !p.isPrimaryDescriptor()) {
                return p;
            }
        }
        return null;
    }


    /**
     * Formats a property value for display to the user.
     *
     * @param p An item property to format.
     * @param value
     * @return A string containing the property, which is truncated to 35
     *      characters for display.
     */
    protected String formatForDisplay(Property p, Object value) {
        if (p.getTypeCode() == Property.Types.TEXT) {
            String str = value.toString();

            if (str.length() > 35) {
                str = str.substring(0, 32) + "...";
            }
            return "\"" + str + "\"";
        } else {
            if (p.getTypeCode() == Property.Types.ENUMERATED) {
                return "\"" + p.getEnumDisplayName(((Integer) value).intValue()) + "\"";
            } else {
                return value.toString();
            }
        }
    }

    // Begin SET and GET methods

    /**
     * Sets the <CODE>serverName</CODE> attribute to the given value.
     *
     * @param serverName The name of the server you wish to connect to.
     * @see #getServerName()
     */
    public void setServerName(String serverName) {
        this.serverName = serverName;
    }


    /**
     * Gets the <CODE>serverName</CODE> attribute.
     *
     * @return The StarTeam server to log in to.
     * @see #setServerName(String serverName)
     */
    public String getServerName() {
        return serverName;
    }


    /**
     * Sets the <CODE>serverPort</CODE> attribute to the given value. The
     * given value must be a valid integer, but it must be a string object.
     *
     * @param serverPort A string containing the port on the StarTeam server
     *      to use.
     * @see #getServerPort()
     */
    public void setServerPort(int serverPort) {
        this.serverPort = serverPort;
    }


    /**
     * Gets the <CODE>serverPort</CODE> attribute.
     *
     * @return A string containing the port on the StarTeam server to use.
     * @see #setServerPort(int)
     */
    public int getServerPort() {
        return serverPort;
    }


    /**
     * Sets the <CODE>projectName</CODE> attribute to the given value.
     *
     * @param projectName The StarTeam project to search.
     * @see #getProjectName()
     */
    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }


    /**
     * Gets the <CODE>projectName</CODE> attribute.
     *
     * @return The StarTeam project to search.
     * @see #setProjectName(String projectName)
     */
    public String getProjectName() {
        return projectName;
    }


    /**
     * Sets the <CODE>viewName</CODE> attribute to the given value.
     *
     * @param viewName The view to find the specified folder in.
     * @see #getViewName()
     */
    public void setViewName(String viewName) {
        this.viewName = viewName;
    }


    /**
     * Gets the <CODE>viewName</CODE> attribute.
     *
     * @return The view to find the specified folder in.
     * @see #setViewName(String viewName)
     */
    public String getViewName() {
        return viewName;
    }


    /**
     * Sets the <CODE>folderName</CODE> attribute to the given value. To
     * search the root folder, use a slash or backslash, or simply don't set a
     * folder at all.
     *
     * @param folderName The subfolder from which to check out files.
     * @see #getFolderName()
     */
    public void setFolderName(String folderName) {
        this.folderName = folderName;
    }


    /**
     * Gets the <CODE>folderName</CODE> attribute.
     *
     * @return The subfolder from which to check out files. All subfolders
     *      will be searched, as well.
     * @see #setFolderName(String folderName)
     */
    public String getFolderName() {
        return folderName;
    }


    /**
     * Sets the <CODE>username</CODE> attribute to the given value.
     *
     * @param username Your username for the specified StarTeam server.
     * @see #getUsername()
     */
    public void setUsername(String username) {
        this.username = username;
    }


    /**
     * Gets the <CODE>username</CODE> attribute.
     *
     * @return The username given by the user.
     * @see #setUsername(String username)
     */
    public String getUsername() {
        return username;
    }


    /**
     * Sets the <CODE>password</CODE> attribute to the given value.
     *
     * @param password Your password for the specified StarTeam server.
     * @see #getPassword()
     */
    public void setPassword(String password) {
        this.password = password;
    }


    /**
     * Gets the <CODE>password</CODE> attribute.
     *
     * @return The password given by the user.
     * @see #setPassword(String password)
     */
    public String getPassword() {
        return password;
    }


    /**
     * Sets the <CODE>targetFolder</CODE> attribute to the given value.
     *
     * @param target The target path on the local machine to check out to.
     * @see #getTargetFolder()
     */
    public void setTargetFolder(String targetFolder) {
        this.targetFolder = targetFolder;
    }


    /**
     * Gets the <CODE>targetFolder</CODE> attribute.
     *
     * @return The target path on the local machine to check out to.
     * @see #setTargetFolder(String targetFolder)
     */
    public String getTargetFolder() {
        return targetFolder;
    }


    /**
     * Sets the <CODE>force</CODE> attribute to the given value.
     *
     * @param force if true, it overwrites files in the target directory. By
     *      default it set to false as a safeguard. Note that if the target
     *      directory does not exist, this setting has no effect.
     * @see #getForce()
     */
    public void setForce(boolean force) {
        this.force = force;
    }


    /**
     * Gets the <CODE>force</CODE> attribute.
     *
     * @return whether to continue if the target directory exists.
     * @see #setForce(boolean)
     */
    public boolean getForce() {
        return force;
    }


    /**
     * Turns recursion on or off.
     *
     * @param recursion if it is true, the default, subfolders are searched
     *      recursively for files to check out. Otherwise, only files
     *      specified by <CODE>folderName</CODE> are scanned.
     * @see #getRecursion()
     */
    public void setRecursion(boolean recursion) {
        this.recursion = recursion;
    }


    /**
     * Gets the <CODE>recursion</CODE> attribute, which tells
     * AntStarTeamCheckOut whether to search subfolders when checking out
     * files.
     *
     * @return whether to search subfolders when checking out files.
     * @see #setRecursion(boolean)
     */
    public boolean getRecursion() {
        return recursion;
    }


    /**
     * Sets the <CODE>verbose</CODE> attribute to the given value.
     *
     * @param verbose whether to display all files as it checks them out. By
     *      default it is false, so the program only displays the total number
     *      of files unless you override this default.
     * @see #getVerbose()
     */
    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }


    /**
     * Gets the <CODE>verbose</CODE> attribute.
     *
     * @return whether to display all files as it checks them out.
     * @see #setVerbose(boolean verbose)
     */
    public boolean getVerbose() {
        return verbose;
    }

    // Begin filter getters and setters

    /**
     * Sets the include filter. When filtering files, AntStarTeamCheckOut uses
     * an unmodified version of <CODE>DirectoryScanner</CODE>'s <CODE>match</CODE>
     * method, so here are the patterns straight from the Ant source code:
     * <BR>
     * <BR>
     * Matches a string against a pattern. The pattern contains two special
     * characters: <BR>
     * '*' which means zero or more characters, <BR>
     * '?' which means one and only one character. <BR>
     * <BR>
     * Separate multiple inlcude filters by <I>spaces</I> , not commas as Ant
     * uses. For example, if you want to check out all .java and .class\
     * files, you would put the following line in your program: <CODE>setIncludes("*.java *.class");</CODE>
     * Finally, note that filters have no effect on the <B>directories</B>
     * that are scanned; you could not check out files from directories with
     * names beginning only with "build," for instance. Of course, you could
     * limit AntStarTeamCheckOut to a particular folder and its subfolders
     * with the <CODE>setFolderName(String folderName)</CODE> command. <BR>
     * <BR>
     * Treatment of overlapping inlcudes and excludes: To give a simplistic
     * example suppose that you set your include filter to "*.htm *.html" and
     * your exclude filter to "index.*". What happens to index.html?
     * AntStarTeamCheckOut will not check out index.html, as it matches an
     * exclude filter ("index.*"), even though it matches the include filter,
     * as well. <BR>
     * <BR>
     * Please also read the following sections before using filters:
     *
     * @param includes A string of filter patterns to include. Separate the
     *      patterns by spaces.
     * @see #getIncludes()
     * @see #setExcludes(String excludes)
     * @see #getExcludes()
     */
    public void setIncludes(String includes) {
        this.includes = includes;
    }


    /**
     * Gets the patterns from the include filter. Rather that duplicate the
     * details of AntStarTeanCheckOut's filtering here, refer to these links:
     *
     * @return A string of filter patterns separated by spaces.
     * @see #setIncludes(String includes)
     * @see #setExcludes(String excludes)
     * @see #getExcludes()
     */
    public String getIncludes() {
        return includes;
    }


    /**
     * Sets the exclude filter. When filtering files, AntStarTeamCheckOut uses
     * an unmodified version of <CODE>DirectoryScanner</CODE>'s <CODE>match</CODE>
     * method, so here are the patterns straight from the Ant source code:
     * <BR>
     * <BR>
     * Matches a string against a pattern. The pattern contains two special
     * characters: <BR>
     * '*' which means zero or more characters, <BR>
     * '?' which means one and only one character. <BR>
     * <BR>
     * Separate multiple exlcude filters by <I>spaces</I> , not commas as Ant
     * uses. For example, if you want to check out all files except .XML and
     * .HTML files, you would put the following line in your program: <CODE>setExcludes("*.XML *.HTML");</CODE>
     * Finally, note that filters have no effect on the <B>directories</B>
     * that are scanned; you could not skip over all files in directories
     * whose names begin with "project," for instance. <BR>
     * <BR>
     * Treatment of overlapping inlcudes and excludes: To give a simplistic
     * example suppose that you set your include filter to "*.htm *.html" and
     * your exclude filter to "index.*". What happens to index.html?
     * AntStarTeamCheckOut will not check out index.html, as it matches an
     * exclude filter ("index.*"), even though it matches the include filter,
     * as well. <BR>
     * <BR>
     * Please also read the following sections before using filters:
     *
     * @param excludes A string of filter patterns to exclude. Separate the
     *      patterns by spaces.
     * @see #setIncludes(String includes)
     * @see #getIncludes()
     * @see #getExcludes()
     */
    public void setExcludes(String excludes) {
        this.excludes = excludes;
    }


    /**
     * Gets the patterns from the exclude filter. Rather that duplicate the
     * details of AntStarTeanCheckOut's filtering here, refer to these links:
     *
     * @return A string of filter patterns separated by spaces.
     * @see #setExcludes(String excludes)
     * @see #setIncludes(String includes)
     * @see #getIncludes()
     */
    public String getExcludes() {
        return excludes;
    }


    /**
     * returns whether the StarTeam default path is factored into calculated
     * target path locations (false) or whether targetFolder is an absolute
     * mapping to the root folder named by folderName
     *
     * @return returns true if absolute mapping is used, false if it is not
     *      used.
     * @see #setTargetFolderAbsolute(boolean)
     */
    public boolean getTargetFolderAbsolute() {
        return this.targetFolderAbsolute;
    }


    /**
     * sets the property that indicates whether or not the Star Team "default
     * folder" is to be used when calculation paths for items on the target
     * (false) or if targetFolder is an absolute mapping to the root folder
     * named by foldername.
     *
     * @param targetFolderAbsolute <tt>true</tt> if the absolute mapping is to
     *      be used. <tt>false</tt> (the default) if the "default folder" is
     *      to be factored in.
     * @see #getTargetFolderAbsolute()
     */
    public void setTargetFolderAbsolute(boolean targetFolderAbsolute) {
        this.targetFolderAbsolute = targetFolderAbsolute;
    }
}

