/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.api.commands;

import java.io.File;
import java.io.IOException;
import java.util.List;

import edu.nyu.cs.javagit.api.JavaGitException;
import edu.nyu.cs.javagit.api.Ref;
import edu.nyu.cs.javagit.client.ClientManager;
import edu.nyu.cs.javagit.client.IClient;
import edu.nyu.cs.javagit.client.IGitReset;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * GitReset provides an API to perform git-reset functionality against a git
 * repository: reset the current HEAD to the specified state.
 */
public class GitReset {

  /*
   * TODO (jhl388): Determine if "repository" is the right name to call the initial File argument to
   * the reset methods. It may be better to call it something like "workingDirectory" or something
   * to indicate that it can be something further down the git repository working tree other than
   * the root directory.
   */

  /**
   * Perform a reset on the repository. The results of this method are what one would get by running
   * &quote;git-reset&quote; against the repository.
   *
   * @param repository
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to perform reset against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @return The results of the reset.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
a directory doesn't exist

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error making the commit.
   */
  public static GitResetResponse gitReset(File repository) throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitReset gitReset = client.getGitResetInstance();
    return gitReset.gitReset(repository);
  }

  /**
   * Perform a reset on the repository.
   *
   * @param repository
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to perform reset against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param options
   *          The options for a git-reset command. If the value is null, a
   *          NullPointerException will be thrown.
   * @return The results of the reset.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
a directory doesn't exist

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error making the commit.
   */
  public static GitResetResponse gitReset(File repository, GitResetOptions options)
      throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkNullArgument(options, "options");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitReset gitReset = client.getGitResetInstance();
    return gitReset.gitReset(repository, options);
  }

  /**
   * Perform a reset on the repository.
   *
   * @param repository
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to perform reset against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param commitName
   *          The name of the commit to reset to. If the value is null, a
   *          NullPointerException will be thrown.
   * @param paths
   *          A list of paths to folders or files to reset. The paths specified in this list must
   *          all be relative to the path specified in the repository parameter as
   *          returned by File.getPath(). A non-null and non-empty list is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results of the reset.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
a directory doesn't exist

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error making the commit.
   */
  public GitResetResponse gitReset(File repository, Ref commitName, List<File> paths)
      throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkNullArgument(commitName, "options");
    CheckUtilities.checkNullListArgument(paths, "paths");
    // TODO (jhl388): Check that commitName is a correct type.

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitReset gitReset = client.getGitResetInstance();
    return gitReset.gitReset(repository, commitName, paths);
  }

  /**
   * Perform a reset on the repository.
   *
   * @param repository
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to perform reset against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param paths
   *          A list of paths to folders or files to reset. The paths specified in this list must
   *          all be relative to the path specified in the repository parameter as
   *          returned by File.getPath(). A non-null and non-empty list is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results of the reset.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
a directory doesn't exist

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error making the commit.
   */
  public static GitResetResponse gitReset(File repository, List<File> paths) throws IOException,
      JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkNullListArgument(paths, "paths");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitReset gitReset = client.getGitResetInstance();
    return gitReset.gitReset(repository, paths);
  }

  /**
   * Perform a hard reset on the repository to the specified CommitName.
   *
   * @param repository
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to perform reset against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param commitName
   *          The name of the commit to reset to. If the value is null, a
   *          NullPointerException will be thrown.
   * @return The results of the reset.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
a directory doesn't exist

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error making the commit.
   */
  public static GitResetResponse gitResetHard(File repository, Ref commitName) throws IOException,
      JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkNullArgument(commitName, "commitName");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitReset gitReset = client.getGitResetInstance();
    return gitReset.gitResetHard(repository, commitName);
  }

  /**
   * Perform a soft reset on the repository to the specified CommitName.
   *
   * @param repository
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to perform reset against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param commitName
   *          The name of the commit to reset to. If the value is null, a
   *          NullPointerException will be thrown.
   * @return The results of the reset.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
a directory doesn't exist

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error making the commit.
   */
  public static GitResetResponse gitResetSoft(File repository, Ref commitName) throws IOException,
      JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkNullArgument(commitName, "commitName");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitReset gitReset = client.getGitResetInstance();
    return gitReset.gitResetSoft(repository, commitName);
  }

}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.client;

import java.io.File;

import edu.nyu.cs.javagit.api.Ref;
import edu.nyu.cs.javagit.api.commands.GitCommitResponse;

/**
 * Implementation of a GitCommitResponse. This class adds functionality to set
 * values in a GitCommitResponse.
 */
public class GitCommitResponseImpl extends GitCommitResponse {

  /**
   * Constructor.
   *
   * @param shortHashName
   *          The short hash name
   * @param shortComment
   */
  public GitCommitResponseImpl(Ref shortHashName, String shortComment) {
    super(shortHashName, shortComment);
  }

  /**
   * Add the information about a newly added file in the repository for a given commit.
   *
   * @param pathToFile
   *          The path to the file from the root of the repository.
   * @param mode
   *          The mode of the file.
   * @return False if the pathToFile is null or length zero. True otherwise.
   */
  public boolean addAddedFile(File pathToFile, String mode) {
    if (null == pathToFile) {
      return false;
    }

    return addedFiles.add(new AddedOrDeletedFile(pathToFile, mode));
  }

  /**
   * Add the information about a newly copied file in the repository for a given commit.
   *
   * @param sourceFilePath
   *          The path to the source file.
   * @param destinationFilePath
   *          The path to the destination file.
   * @param percentage
   *          The percentage.
   * @return False if sourceFilePath or destinationFilePath is null or
   *         length zero. True otherwise.
   */
  public boolean addCopiedFile(File sourceFilePath, File destinationFilePath, int percentage) {
    if (null == sourceFilePath || null == destinationFilePath) {
      return false;
    }
    return copiedFiles.add(new CopiedOrMovedFile(sourceFilePath, destinationFilePath, percentage));
  }

  /**
   * Add the information about a file deleted from the repository for a given commit.
   *
   * @param pathToFile
   *          The path to the file from the root of the repository.
   * @param mode
   *          The mode of the file.
   * @return False if the pathToFile is null or length zero. True otherwise.
   */
  public boolean addDeletedFile(File pathToFile, String mode) {
    if (null == pathToFile) {
      return false;
    }

    return deletedFiles.add(new AddedOrDeletedFile(pathToFile, mode));
  }

  /**
   * Add the information about a moved/renamed file in the repository for a given commit.
   *
   * @param sourceFilePath
   *          The path to the source file.
   * @param destinationFilePath
   *          The path to the destination file.
   * @param percentage
   *          The percentage.
   * @return False if sourceFilePath or destinationFilePath is null or
   *         length zero. True otherwise.
   */
  public boolean addRenamedFile(File sourceFilePath, File destinationFilePath, int percentage) {
    if (null == sourceFilePath || null == destinationFilePath) {
      return false;
    }
    return renamedFiles.add(new CopiedOrMovedFile(sourceFilePath, destinationFilePath, percentage));
  }

  /**
   * Sets the number of files changed in the commit.
   *
   * @param filesChanged
   *          The number of files changed in the commit.
   */
  public void setFilesChanged(int filesChanged) {
    this.filesChanged = filesChanged;
  }

  /**
   * Sets the number of files changed during a commit.
   *
   * @param filesChangedStr
   *          The number of files changed in String format.
   * @return True if the filesChangedStr parameter is a String
   *         representing a number. False if the String does not contain a parsable
   *         integer.
   */
  public boolean setFilesChanged(String filesChangedStr) {
    try {
      this.filesChanged = Integer.parseInt(filesChangedStr);
      return true;
    } catch (NumberFormatException e) {
      return false;
    }
  }

  /**
   * Sets the number of lines deleted in the commit.
   *
   * @param linesDeleted
   *          The number of lines deleted in the commit.
   */
  public void setLinesDeleted(int linesDeleted) {
    this.linesDeleted = linesDeleted;
  }

  /**
   * Sets the number of lines deleted in a commit.
   *
   * @param linesDeletedStr
   *          The number of lines deleted in String format.
   * @return True if the linesDeletedStr parameter is a String
   *         representing a number. False if the String does not contain a parsable
   *         integer.
   */
  public boolean setLinesDeleted(String linesDeletedStr) {
    try {
      this.linesDeleted = Integer.parseInt(linesDeletedStr);
      return true;
    } catch (NumberFormatException e) {
      return false;
    }
  }

  /**
   * Sets the number of lines inserted in the commit.
   *
   * @param linesInserted
   *          The number of lines inserted in the commit.
   */
  public void setLinesInserted(int linesInserted) {
    this.linesInserted = linesInserted;
  }

  /**
   * Sets the number of lines inserted in a commit.
   *
   * @param linesInsertedStr
   *          The number of lines inserted in String format.
   * @return True if the linesInsertedStr parameter is a String
   *         representing a number. False if the String does not contain a parsable
   *         integer.
   */
  public boolean setLinesInserted(String linesInsertedStr) {
    try {
      this.linesInserted = Integer.parseInt(linesInsertedStr);
      return true;
    } catch (NumberFormatException e) {
      return false;
    }
  }

}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.client.cli;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import edu.nyu.cs.javagit.api.JavaGitConfiguration;
import edu.nyu.cs.javagit.api.JavaGitException;
import edu.nyu.cs.javagit.api.commands.GitMvOptions;
import edu.nyu.cs.javagit.api.commands.GitMvResponse;
import edu.nyu.cs.javagit.client.GitMvResponseImpl;
import edu.nyu.cs.javagit.client.IGitMv;
import edu.nyu.cs.javagit.utilities.CheckUtilities;
import edu.nyu.cs.javagit.utilities.ExceptionMessageMap;

/**
 * Command-line implementation of the IGitMv interface.
 */
public class CliGitMv implements IGitMv {
  // Variable, which if set the fatal messages are not considered for throwing exceptions.
  private boolean dryRun;

  public GitMvResponseImpl mv(File repoPath, File source, File destination) throws IOException,
      JavaGitException {
    List<File> sources = new ArrayList<File>();
    sources.add(source);
    return mvProcess(repoPath, null, sources, destination);
  }

  public GitMvResponseImpl mv(File repoPath, GitMvOptions options, File source, File destination)
      throws IOException, JavaGitException {
    List<File> sources = new ArrayList<File>();
    sources.add(source);
    return mvProcess(repoPath, options, sources, destination);
  }

  public GitMvResponseImpl mv(File repoPath, List<File> sources, File destination) throws IOException,
      JavaGitException {
    return mvProcess(repoPath, null, sources, destination);
  }

  public GitMvResponseImpl mv(File repoPath, GitMvOptions options, List<File> sources, File destination)
      throws IOException, JavaGitException {
    return mvProcess(repoPath, options, sources, destination);
  }

  /**
   * Exec of git-mv command
   *
   * @param repoPath
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to move/rename against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param options
   *          The options to git-mv command.
   * @param source
   *          The List of source file/folder/symlink which are to be moved to a
   *          different location. The paths specified in this list must all be relative to the
   *          path specified in the repository parameter as returned by
   *          File.getPath(). A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param destination
   *          The destination file/folder/symlink which the source is renamed or moved to. It
   *          should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the git-mv.
   *           It is expected that GitMv does not notify when a move was successful. This follows
   *           the response that git-mv itself gives. If the move/rename fails for any reason,
   *           proper exception messages are generated and thrown.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error executing git-mv.
   */
  public GitMvResponseImpl mvProcess(File repoPath, GitMvOptions options, List<File> source,
      File destination) throws IOException, JavaGitException {

    List<String> commandLine = buildCommand(options, source, destination);
    GitMvParser parser = new GitMvParser();

    return (GitMvResponseImpl) ProcessUtilities.runCommand(repoPath, commandLine, parser);
  }

  /**
   * Builds a list of command arguments to pass to ProcessBuilder.
   *
   * @param options
   *          The options to include on the command line.
   * @param source
   *          The source file/directory/symlink to rename/move.
   * @param destination
   *          The destination file/directory/symlink to rename/move to.
   * @return A list of the individual arguments to pass to ProcessBuilder.
   */
  protected List<String> buildCommand(GitMvOptions options, List<File> source, File destination) {
    List<String> cmd = new ArrayList<String>();

    cmd.add(JavaGitConfiguration.getGitCommand());
    cmd.add("mv");

    if (null != options) {
      if (options.isOptF()) {
        cmd.add("-f");
      }
      if (options.isOptK()) {
        cmd.add("-k");
      }
      if (options.isOptN()) {
        cmd.add("-n");
        setDryRun(true);
      }
    }
    for (File file : source) {
      cmd.add(file.getPath());
    }
    cmd.add(destination.getPath());
    return cmd;
  }

  /**
   * Implementation of the IParser interface in GitMvParser class.
   */
  public class GitMvParser implements IParser {

    // The response object for an mv operation.
    private GitMvResponseImpl response = null;

    // While handling the error cases this buffer will have the error messages.
    private StringBuffer errorMessage = null;

    // Track the number of lines parsed.
    private int numLinesParsed = 0;

    /**
     * Parses the line from the git-mv response text.
     *
     * @param line
     *          The line of text to process.
     *
     */
    public void parseLine(String line) {
      ++numLinesParsed;
      if (null != errorMessage) {
        errorMessage.append(", line" + numLinesParsed + "=[" + line + "]");
        return;
      }
      if (line.startsWith("error") || line.startsWith("fatal")) {
        if (null == errorMessage) {
          errorMessage = new StringBuffer();
        }
        errorMessage.append("line1=[" + line + "]");
      } else {
        if (null == response) {
          response = new GitMvResponseImpl();
        }
        // This is to parse the output when -n or -f options were given
        parseLineForSuccess(line);
      }
    }

    /**
     * Parses the line for successful execution.
     *
     * @param line
     *          The line of text to process.
     */
    public void parseLineForSuccess(String line) {
      if (line.contains("Warning:")) {
        response.addComment(line);
      }
      if (line.contains("Adding") || line.contains("Changed")) {
        response.setDestination(new File(line.substring(11)));
      }
      if (line.contains("Deleting")) {
        response.setSource(new File(line.substring(11)));
      }
    }

    public void processExitCode(int code) {
    }

    /**
     * Gets a GitMvResponse object containing the information from the git-mv
     * response text parsed by this IParser instance. It is expected that GitMv does not notify
     * when a move was successful. This follows the response that git-mv itself gives. If the
     * move/rename fails for any reason, proper exception messages are generated and thrown.
     *
     * @return The GitMvResponse object containing the git-mv's response
     *         information. It is expected that GitMv does not notify when a move was successful.
     *         This follows the response that git-mv itself gives. If the move/rename fails for
     *         any reason, proper exception messages are generated and thrown.
     * @throws JavaGitException if there is an error executing git-mv.
     */
    public GitMvResponse getResponse() throws JavaGitException {
      if (null != errorMessage) {
        if (isDryRun()) {
          throw new JavaGitException(424001, ExceptionMessageMap.getMessage("424001")
              + "  The git-mv dry-run error message:  { " + errorMessage.toString() + " }");
        } else {
          throw new JavaGitException(424000, ExceptionMessageMap.getMessage("424000")
              + "  The git-mv error message:  { " + errorMessage.toString() + " }");
        }
      }
      return response;
    }
  }

  /**
   * @return the dryRun
   */
  public boolean isDryRun() {
    return dryRun;
  }

  /**
   * @param dryRun
   *          the dryRun to set
   */
  public void setDryRun(boolean dryRun) {
    this.dryRun = dryRun;
  }
}


package org.ucmtwine.parameter.types;

import intradoc.common.ExecutionContext;
import intradoc.data.DataBinder;
import intradoc.data.Workspace;
import intradoc.server.HttpImplementor;
import intradoc.server.PageMerger;
import intradoc.server.Service;
import intradoc.server.ServiceRequestImplementor;
import intradoc.shared.UserData;

import org.ucmtwine.parameter.Parameter;

/**
 * Place-holder parameter which doesn't retrieve it's value from the binder,
 * rather is injected when enumerating the parameter list before invocation.
 *
 * @author tim
 */
public class InjectedParameter extends Parameter {

  public InjectedParameter(String name, Class<?> type) {
    super(name, type);
  }

  /**
   * Returns null because the type should be injected rather than retrieved.
   * This is a place-holder not a value retrieval.
   *
   * @throws IllegalAccessException
   */
  @Override
  public Object getBinderValue(Service service) throws IllegalAccessException {
    return getInjectedValue(service);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Object getArgumentValue(Object object, Service service) throws ClassCastException {
    return getInjectedValue(service);
  }

  /**
   * Special case for Injectable type. Injects the required parameter from the
   * ExecutionContext (service)
   *
   * @param service
   * @return
   */
  protected Object getInjectedValue(Service service) {

    if (type == UserData.class) {
      return service.getUserData();

    } else if (type == PageMerger.class) {
      return service.getPageMerger();

    } else if (type == DataBinder.class) {
      return service.getBinder();

    } else if (type == HttpImplementor.class) {
      return service.getHttpImplementor();

    } else if (type == ServiceRequestImplementor.class) {
      return service.getRequestImplementor();

    } else if (type == Workspace.class) {
      return service.getWorkspace();

    } else if (ExecutionContext.class.isAssignableFrom(type)) {
      return service;
    }

    throw new IllegalStateException("Injectable type " + type.getName() + " not known.");
  }

  /**
   * {@inheritDoc}
   */
  public int getGrammarElementType() {
    return -1; // ignore element type in idoc functions
  }

  public static boolean isValidType(Class<?> type) {
    return (type == UserData.class || ExecutionContext.class.isAssignableFrom(type) || type == PageMerger.class
        || type == DataBinder.class || type == HttpImplementor.class || type == ServiceRequestImplementor.class || type == Workspace.class);
  }
}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.api.commands;

import java.io.File;
import java.io.IOException;
import java.util.List;

import edu.nyu.cs.javagit.api.JavaGitException;
import edu.nyu.cs.javagit.client.ClientManager;
import edu.nyu.cs.javagit.client.IClient;
import edu.nyu.cs.javagit.client.IGitMv;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * GitMv provides an interface to move files, symlinks or directories to a different
 * location or rename them.
 *
 */
public class GitMv {
  /**
   * Moves the specified source file/symlink/directory to the destination file/symlink/directory. If
   * destination is non-existent then same as rename.
   *
   * @param repositoryPath
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to move/rename against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param source
   *          The source file/folder/symlink which is to be renamed or moved to a different
   *          location. It should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param destination
   *          The destination file/folder/symlink which the source is renamed or moved to. It
   *          should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the git-mv.
   *           It is expected that GitMv does not notify when a move was successful. This follows
   *           the response that git-mv itself gives. If the move/rename fails for any reason,
   *           proper exception messages are generated and thrown.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error executing git-mv.
   */
  public GitMvResponse mv(File repositoryPath, File source, File destination)
      throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repositoryPath, "repository path");
    CheckUtilities.checkNullArgument(source, "source");
    CheckUtilities.checkNullArgument(destination, "destination");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitMv gitMv = client.getGitMvInstance();
    return gitMv.mv(repositoryPath, source, destination);
  }

  /**
   * Moves the specified source file/symlink/directory to the destination file/symlink/directory. If
   * destination is non-existent then same as rename.
   *
   * @param repositoryPath
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to move/rename against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param options
   *          The options to git-mv command.
   * @param source
   *          The source file/folder/symlink which is to be renamed or moved to a different
   *          location. It should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param destination
   *          The destination file/folder/symlink which the source is renamed or moved to. It
   *          should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the git-mv.
   *           It is expected that GitMv does not notify when a move was successful. This follows
   *           the response that git-mv itself gives. If the move/rename fails for any reason,
   *           proper exception messages are generated and thrown.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error executing git-mv.
   */
  public GitMvResponse mv(File repositoryPath, GitMvOptions options, File source,
      File destination) throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repositoryPath, "repository path");
    CheckUtilities.checkNullArgument(source, "source");
    CheckUtilities.checkNullArgument(options, "options");
    CheckUtilities.checkNullArgument(destination, "destination");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitMv gitMv = client.getGitMvInstance();
    return gitMv.mv(repositoryPath, options, source, destination);
  }

  /**
   * Moves the specified source files/symlinks/directories to the destination directory.
   *
   * @param repositoryPath
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to move/rename against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param sources
   *          The List of source file/folder/symlink which are to be moved to a
   *          different location. The paths specified in this list must all be relative to the
   *          path specified in the repository parameter as returned by
   *          File.getPath(). A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param destination
   *          The destination file/folder/symlink which the source is renamed or moved to. It
   *          should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the git-mv.
   *           It is expected that GitMv does not notify when a move was successful. This follows
   *           the response that git-mv itself gives. If the move/rename fails for any reason,
   *           proper exception messages are generated and thrown.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error executing git-mv.
   */
  public GitMvResponse mv(File repositoryPath, List<File> sources, File destination)
      throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repositoryPath, "repository path");
    CheckUtilities.checkNullListArgument(sources, "sources");
    CheckUtilities.checkNullArgument(destination, "destination");
    //CheckUtilities.checkDirectoryArgument(destination, "destination");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitMv gitMv = client.getGitMvInstance();
    return gitMv.mv(repositoryPath, sources, destination);
  }

  /**
   * Moves the specified source files/symlinks/directories to the destination directory.
   *
   * @param repositoryPath
   *          A File instance for the path to the repository root (the parent
   *          directory of the .git directory) or a sub-directory in the working tree of the
   *          repository to move/rename against. This argument must represent the absolute path to
   *          the desired directory as returned by the File.getPath() method. If null
   *          is passed, a NullPointerException will be thrown.
   * @param options
   *          The options to git-mv command.
   * @param sources
   *          The List of source file/folder/symlink which are to be moved to a
   *          different location. The paths specified in this list must all be relative to the
   *          path specified in the repository parameter as returned by
   *          File.getPath(). A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param destination
   *          The destination file/folder/symlink which the source is renamed or moved to. It
   *          should be relative to the path specified in the repository
   *          parameter as returned by File.getPath(). A non-zero length argument is
   *          required for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the git-mv.
   *           It is expected that GitMv does not notify when a move was successful. This follows
   *           the response that git-mv itself gives. If the move/rename fails for any reason,
   *           proper exception messages are generated and thrown.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown.
   *              Examples include:
   *

   *
access to a file is denied

   *
a command is not found on the PATH

   *

   * @exception JavaGitException
   *              Thrown when there is an error executing git-mv.
   */
  public GitMvResponse mv(File repositoryPath, GitMvOptions options, List<File> sources,
      File destination) throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repositoryPath, "repository path");
    CheckUtilities.checkNullArgument(options, "options");
    CheckUtilities.checkNullListArgument(sources, "sources");
    CheckUtilities.checkDirectoryArgument(destination, "destination");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitMv gitMv = client.getGitMvInstance();
    return gitMv.mv(repositoryPath, options, sources, destination);
  }
}


package edu.nyu.cs.javagit.utilities;

/**
 * Description : String utilities
 * Date: 3/31/13
 * Time: 7:01 PM
 */
public final class StringUtilities {
    /**
     * Returns the position for char 'c' in string 'str' starting from position 'pos'
     * and searching towards the string beginning
     * @param str
     * @param from
     * @param c
     * @return char 'c' position or -1 if char is not found
     */
    public static int indexOfLeft(String str, int from, char c) {
        int pos = -1;
        int f = from;

        while(  f >= 0 && pos == -1 )
            if ( str.charAt(f--) == c )
                pos = f+1;

        return pos;
    }
}


package org.ucmtwine.parameter.types;

import intradoc.common.GrammarElement;
import intradoc.provider.Provider;
import intradoc.provider.Providers;
import intradoc.server.Service;

import org.ucmtwine.parameter.Parameter;

public class ProviderParameter extends Parameter {

  public ProviderParameter() {
    super("", Provider.class);
  }

  public ProviderParameter(String name) {
    super(name, Provider.class);
  }

  public ProviderParameter(String name, Class<?> type) {
    super(name, type);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Object getBinderValue(Service service) {
    String providerName = getStringValue(service.getBinder());
    Provider provider = Providers.getProvider(providerName);

    if (this.required && provider == null) {
      throw new IllegalArgumentException("Provider '" + providerName + "' could not be found.");
    }

    // providers that are in error will throw an exception if they are required
    if (provider != null && provider.isInError() && this.required) {
      throw new IllegalArgumentException("The provider '" + providerName + "' is not configured correctly!");
    }

    return provider;
  }

  /**
   * Returns a result set found by the passed in string value.
   */
  @Override
  public Object getArgumentValue(Object object, Service service) throws ClassCastException {

    if (object instanceof String) {
      Provider provider = Providers.getProvider((String) object);

      if (provider != null) {
        return provider;
      }
    }
    return null;
    // throw new
    // ClassCastException("Must supply the name of a provider as a string");
  }

  /**
   * {@inheritDoc}
   */
  public int getGrammarElementType() {
    // string val because the provider name is passed as a string
    return GrammarElement.STRING_VAL;
  }
}


/*
 * Copyright (C) 2014 The droitated DB Authors
 *
 * 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 org.droitateddb;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import org.droitateddb.cursor.CombinedCursorImpl;
import org.droitateddb.entity.Column;
import org.droitateddb.entity.Entity;
import org.droitateddb.entity.PrimaryKey;
import org.droitateddb.schema.EntityInfo;
import org.droitateddb.validation.AccumulatedValidationResult;
import org.droitateddb.validation.InvalidEntityException;
import org.droitateddb.validation.ValidationToggle;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static org.droitateddb.Utilities.getFieldValue;

/**
 * Provides support for executing CRUD operations on {@link org.droitateddb.entity.Entity} classes, such getting them from the database or
 * saving them to the database.

 *

 * Each operation opens a connection to the {@link SQLiteDatabase}. If you want only one db connection use
 * {@link ConnectedEntityService}
 *
 * @param <E> Entity, for which this service will be used
 * @author Falk Appel
 * @author Alexander Frank
 */
public class EntityService<E> {
    private final Context context;
    private final Class<E> entityClass;
    private String tableName;
    private final EntityInfo entityInfo;
    private Field primaryKey;
    protected DbCreator dbCreator;
    private DatabaseValidator<E> databaseValidator;
    private ValidationToggle toggle;

    /**
     * Creates a {@link EntityService} for the given {@link org.droitateddb.entity.Entity}.

     * The validation when saving {@link org.droitateddb.entity.Entity}s is turned on.
     *
     * @param context     Android context
     * @param entityClass Class of the {@link org.droitateddb.entity.Entity}, the service should be used for
     * @throws IllegalArgumentException When the given {@link #entityClass} is no {@link org.droitateddb.entity.Entity}
     */
    public EntityService(final Context context, final Class<E> entityClass) {
        this(context, entityClass, ValidationToggle.ON, DbCreator.getInstance(context));
    }

    /**
     * Creates a {@link EntityService} for the given {@link org.droitateddb.entity.Entity}
     *
     * @param context     Android context
     * @param entityClass Class of the {@link org.droitateddb.entity.Entity}, the service should be used for
     * @param toggle      Controls the use of validation on saving  {@link org.droitateddb.entity.Entity}s
     * @throws IllegalArgumentException When the given {@link #entityClass} is no {@link org.droitateddb.entity.Entity}
     */
    public EntityService(final Context context, final Class<E> entityClass, ValidationToggle toggle) {
        this(context, entityClass, toggle, DbCreator.getInstance(context));
    }

    /*
     * Provides test access to constructor
     */
    EntityService(final Context context, final Class<E> entityClass, ValidationToggle toggle, final DbCreator dbCreator) {
        if (entityClass.getAnnotation(Entity.class) == null) {
            throw new IllegalArgumentException("The EntityService can only be used for @Entity annotated classes");
        }
        this.context = context;
        this.entityClass = entityClass;
        this.entityInfo = SchemaUtil.getEntityInfo(entityClass);
        this.tableName = SchemaUtil.getTableName(entityClass);
        this.toggle = toggle;
        this.dbCreator = dbCreator;
        this.databaseValidator = new DatabaseValidator<E>();
        initColumns();
    }

    private void initColumns() {
        for (Field field : entityClass.getDeclaredFields()) {
            if (field.getAnnotation(Column.class) != null) {
                if (field.getAnnotation(PrimaryKey.class) != null) {
                    primaryKey = field;
                }
            }
        }
    }

    /**
     * Reads all {@link Entity}s of the service specific type from the database
     *
     * @return All {@link Entity}s stored in the database, if non are found a empty list is returned
     */
    public List<E> get() {
        return find(null, null, null);
    }

    /**
     * Gets a specific {@link Entity} according to the given id
     *
     * @param id primary key of the {@link Entity}
     * @return The {@link Entity} to the given id, or null if non was found
     */
    public E get(final long id) {
        SQLiteDatabase database = openDB();
        try {
            Cursor cursor = database.query(tableName, null, primaryKey.getName() + " = ?", new String[]{Long.toString(id)}, null, null, null);
            if (cursor.getCount() == 0) {
                return null;
            }
            return CursorOperation.tryOnCursor(cursor, new CursorOperation<E>() {
                @Override
                public E execute(final Cursor cursor) {
                    return CombinedCursorImpl.create(context, cursor, entityInfo, entityClass).getCurrent();
                }
            });
        } finally {
            closeDB(database);
        }
    }

    protected void closeDB(SQLiteDatabase database) {
        dbCreator.reduceDatabaseConnection();
    }

    protected SQLiteDatabase openDB() {
        return dbCreator.getDatabaseConnection();
    }

    /**
     * Search for {@link Entity}s in the database with basic SQL WHERE statements.
     *
     * @param selection     SQL WHERE statement
     * @param selectionArgs Arguments for the WHERE statement
     * @param order         Sort order of the result
     * @return All found {@link Entity}s or an empty list of non are found
     */
    public List<E> find(final String selection, final String[] selectionArgs, final String order) {
        SQLiteDatabase database = openDB();
        try {
            Cursor cursor = database.query(tableName, null, selection, selectionArgs, null, null, order);
            return CursorOperation.tryOnCursor(cursor, new CursorOperation<List<E>>() {
                @Override
                public List<E> execute(final Cursor cursor) {
                    return new ArrayList<E>(CombinedCursorImpl.create(context, cursor, entityInfo, entityClass).getAll());
                }
            });
        } finally {
            closeDB(database);
        }
    }

    /**
     * Resolves the associations to a given {@link Entity} object and all underlying associations within the object
     * graph.
     *
     * @param data {@link Entity} on which the associations should be resolved
     */
    public void resolveAssociations(final E data) {
        SQLiteDatabase database = openDB();
        try {
            new DatabaseResolver(context, database).resolve(data, 0, Integer.MAX_VALUE);
        } finally {
            closeDB(database);
        }
    }

    /**
     * Resolves the associations to a given {@link Entity} object. The associations will only be resolved to the given
     * depth within the object graph.
     *
     * @param data     {@link Entity} on which the associations should be resolved
     * @param maxDepth The maximum depth to which the associations should be resolved
     */
    public void resolveAssociations(final E data, final int maxDepth) {
        SQLiteDatabase database = openDB();
        try {
            new DatabaseResolver(context, database).resolve(data, 0, maxDepth);
        } finally {
            closeDB(database);
        }
    }

    /**
     * Stores the given {@link Entity} to the database. All attached associations will be stored as well.
     *
     * @param data {@link Entity} which should be stored
     * @return The primary key of the given data.
     * @throws IllegalStateException                             When the {@link PrimaryKey} field and its value of the {@link Entity} could
     *                                                           not be determined
     * @throws org.droitateddb.validation.InvalidEntityException when the given entity is invalid.
     */
    public long save(final E data) {
        return save(data, Integer.MAX_VALUE);
    }

    /**
     * Stores the given {@link Entity} to the database. Associated objects will be saved to the given maxDepth.

     * maxDepth of 0 means that only the given {@link Entity} itself will be saved without associations.
     *
     * @param data     {@link Entity} which should be stored
     * @param maxDepth The maximum depth of the associated objects which should also be saved.
     * @return The primary key of the given data.
     * @throws IllegalStateException                             When the {@link PrimaryKey} field and its value of the {@link Entity} could
     *                                                           not be determined
     * @throws org.droitateddb.validation.InvalidEntityException when the given entity is invalid.
     */
    public long save(final E data, final int maxDepth) {
        if (toggle == ValidationToggle.ON) {
            AccumulatedValidationResult validationResult = databaseValidator.validate(data, maxDepth);
            if (!validationResult.isValid()) {
                throw new InvalidEntityException(validationResult);
            }
        }

        final SQLiteDatabase database = openDB();
        try {
            return transactional(database, new DatabaseOperation<Number>() {
                @Override
                public Number execute() {
                    return new DatabaseSaver(database, maxDepth).save(data);
                }
            }).longValue();
        } finally {
            closeDB(database);
        }
    }

    /**
     * Stores all given {@link Entity}s in the {@link Collection} to the database. All attached associations will be
     * stored as well.
     *
     * @param data {@link Entity}s which should be stored
     * @throws IllegalStateException                             When the {@link PrimaryKey} field and its value of the {@link Entity} could
     *                                                           not be determined
     * @throws org.droitateddb.validation.InvalidEntityException when at least one of the given entities is invalid.
     */
    public void save(final Collection<E> data) {
        save(data, Integer.MAX_VALUE);
    }

    /**
     * Stores all given {@link Entity}s in the {@link Collection} to the database. Associated objects will be saved to
     * the given maxDepth.

     * maxDepth of 0 means that only the given {@link Entity} itself will be saved without associations.
     *
     * @param data     {@link Entity} which should be stored
     * @param maxDepth The maximum depth of the associated objects which should also be saved.
     * @throws IllegalStateException                             When the {@link PrimaryKey} field and its value of the {@link Entity} could
     *                                                           not be determined
     * @throws org.droitateddb.validation.InvalidEntityException when at least one of the given entities is invalid.
     */
    public void save(final Collection<E> data, final int maxDepth) {
        if (toggle == ValidationToggle.ON) {
            AccumulatedValidationResult validationResult = databaseValidator.validate(data, maxDepth);
            if (!validationResult.isValid()) {
                throw new InvalidEntityException(validationResult);
            }
        }

        SQLiteDatabase database = openDB();
        try {
            final DatabaseSaver databaseSaver = new DatabaseSaver(database, maxDepth);
            transactional(database, new DatabaseOperation<Void>() {
                @Override
                public Void execute() {
                    for (E object : data) {
                        databaseSaver.save(object);
                    }
                    return null;
                }
            });
        } finally {
            closeDB(database);
        }
    }

    /**
     * Deletes the given {@link Entity} from the database
     *
     * @param data {@link Entity} that should be deleted
     * @return true if the {@link Entity} could be deleted, false otherwise
     * @throws IllegalStateException    When the {@link PrimaryKey} field and its value of the {@link Entity} could not be determined
     * @throws IllegalArgumentException When the value of the {@link PrimaryKey} field is null
     */
    public boolean delete(final E data) {
        Number id = getFieldValue(data, primaryKey);
        if (id == null) {
            throw new IllegalArgumentException("The @PrimaryKey of the given @Entity can not be null");
        }
        return delete(id.longValue());
    }

    /**
     * Deletes the data of the {@link Entity} for the given id
     *
     * @param id primary key of the {@link Entity} to be deleted
     * @return true if the {@link Entity} could be deleted, false otherwise
     */
    public boolean delete(final long id) {
        SQLiteDatabase database = openDB();
        try {
            int delete = database.delete(tableName, EntityData.getEntityData(entityClass).primaryKey.getName() + "= ?", new String[]{Long.toString(id)});
            return delete == 1;
        } finally {
            closeDB(database);
        }
    }

    private <T> T transactional(SQLiteDatabase database, final DatabaseOperation<T> operation) {
        database.beginTransaction();
        try {
            T result = operation.execute();
            database.setTransactionSuccessful();
            return result;
        } finally {
            database.endTransaction();
        }
    }

    private static interface DatabaseOperation<E> {
        public E execute();
    }

    /**
     * Will be removed with Version 0.2.0

     * Use {@link ConnectedEntityService} if you need only one db connection.
     */
    // TODO:remove with Version 0.2.0
    @Deprecated
    public void close() {

    }

}


package org.ucmtwine.proxy.injector;

import intradoc.common.AppObjectRepository;
import intradoc.common.ScriptContext;
import intradoc.common.ScriptExtensions;
import intradoc.common.ServiceException;
import intradoc.data.DataException;

import java.net.URL;

import org.ucmtwine.proxy.ScriptProxy;

public class IdocScriptInjector extends BaseInjector implements IClassInjector {

  /**
   * {@inheritDoc}
   */
  @Override
  public void injectClasses(URL propertiesFile) {
    injectClasses(propertiesFile, "ucm.idocscript");
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void inject(Class<?> klass) throws DataException, ServiceException {

    // loads function def table from annotated class
    ScriptExtensions extensions = new ScriptProxy(klass);

    // load func def table and set parent to the default script context
    ScriptContext defaultScriptContext = (ScriptContext) AppObjectRepository.getObject("DefaultScriptContext");
    extensions.load(defaultScriptContext);

    // register these extensions
    defaultScriptContext.registerExtension(extensions);
  }
}


package org.ucmtwine.parameter.types;

import intradoc.common.GrammarElement;
import intradoc.data.DataResultSet;
import intradoc.data.ResultSet;
import intradoc.server.Service;

import org.ucmtwine.parameter.Parameter;

public class ResultSetParameter extends Parameter {

  public ResultSetParameter() {
    super("", DataResultSet.class);
  }

  public ResultSetParameter(String name) {
    super(name, DataResultSet.class);
  }

  public ResultSetParameter(String name, Class<?> type) {
    super(name, type);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Object getBinderValue(Service service) {
    DataResultSet drs = getResultSet(this.name, service);

    if (this.required && drs == null) {
      throw new IllegalArgumentException("ResultSet " + this.name + " is required.");
    }

    return drs;
  }

  /**
   * Returns a result set found by the passed in string value.
   */
  @Override
  public Object getArgumentValue(Object object, Service service) throws ClassCastException {

    if (object instanceof String) {
      DataResultSet drs = getResultSet((String) object, service);

      if (drs != null) {
        return drs;
      }
    }
    return null;
    // throw new ClassCastException("Must supply the name of a result set as a string");
  }

  /**
   * Find a result set in the service binder.
   *
   * @param name
   * @param service
   * @return
   */
  private DataResultSet getResultSet(String name, Service service) {
    ResultSet rs = service.getBinder().getResultSet(name);
    DataResultSet drs = new DataResultSet();

    if (rs != null) {
      drs.copy(rs);

      return drs;
    }

    return null;
  }

  /**
   * {@inheritDoc}
   */
  public int getGrammarElementType() {
    // string val because the RS name is passed as a string
    return GrammarElement.STRING_VAL;
  }
}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.client.cli;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import edu.nyu.cs.javagit.api.JavaGitConfiguration;
import edu.nyu.cs.javagit.api.JavaGitException;
import edu.nyu.cs.javagit.api.commands.CommandResponse;
import edu.nyu.cs.javagit.api.commands.GitLogOptions;
import edu.nyu.cs.javagit.api.commands.GitLogResponse;
import edu.nyu.cs.javagit.api.commands.GitLogResponse.Commit;
import edu.nyu.cs.javagit.client.IGitLog;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * Command-line implementation of the IGitLog interface.
 */
public class CliGitLog implements IGitLog{

	/**
	 * Implementations of <git log> with options and one file to be added to index.
	 */
	public List<Commit> log(File repositoryPath, GitLogOptions options)
	throws JavaGitException, IOException {
		CheckUtilities.checkFileValidity(repositoryPath);
		GitLogParser parser = new GitLogParser();
		List<String> command = buildCommand(repositoryPath, options);
		GitLogResponse response =  (GitLogResponse) ProcessUtilities.runCommand(repositoryPath,
				command, parser);
		if (response.containsError()) {
			int line = response.getError(0).getLineNumber();
			String error = response.getError(0).error();
			throw new JavaGitException(420001, "Line " + line + ", " + error);
		}
		return response.getLog();
	}

	public List<Commit> log(File repositoryPath) throws JavaGitException,
	IOException {
		CheckUtilities.checkFileValidity(repositoryPath);
		GitLogParser parser = new GitLogParser();
		List<String> command = buildCommand(repositoryPath, null);
		GitLogResponse response =  (GitLogResponse) ProcessUtilities.runCommand(repositoryPath,
				command, parser);
		if (response.containsError()) {
			int line = response.getError(0).getLineNumber();
			String error = response.getError(0).error();
			throw new JavaGitException(420001, "Line " + line + ", " + error);
		}
		return response.getLog();
	}

	/**
	 * This function builds the git log commands with necessary options as specified by the user.
	 * @param repositoryPath Root of the repository
	 * @param options	Options supplied to the git log command using GitLogOptions.
	 * @return Returns a List of command argument to be applied to git log.
	 */
	private List<String> buildCommand(File repositoryPath, GitLogOptions options) {
		List<String> command = new ArrayList<String>();
		command.add(JavaGitConfiguration.getGitCommand());
		command.add("log");
		if(options!=null){
			//General Options
			/**
			 * Breaks rewrite changes in to pairs of delete and create.
			 */
			if (options.isOptBreakRewriteChanges()) {
				command.add("-B");
			}
			/**
			 * Detects renames
			 */
			if (options.isOptDetectRenames()) {
				command.add("-M");
			}
			/**
			 * Detects copies and renames, of original files
			 */
			if (options.isOptFindCopies()) {
				command.add("-C");
			}
			/**
			 * 	Detects copies and renames , very expensive operation.
			 */
			if (options.isOptFindCopiesHarder()) {
				command.add("--find-copies-harder");
			}
			/**
			 *  List details about lines modified and files affected in a commit.
			 */
			if (options.isOptFileDetails()) {
				command.add("--numstat");
			}

			/**
			 * 	List all logs on the relative path.
			 */
			if (options.isOptRelative()) {
				command.add("--relative="+options.getOptRelativePath());
			}

			/**
			 * 	List all logs since specified date.
			 */
			if (options.isOptLimitCommitSince()) {
				command.add("--since="+ options.getOptLimitSince());
			}

			/**
			 * 	List all logs after specified date.
			 */
			if (options.isOptLimitCommitAfter()) {
				command.add("--after="+ options.getOptLimitAfter());
			}

			/**
			 * 	List all logs after specified date.
			 */
			if (options.isOptLimitCommitUntil()) {
				command.add("--until="+ options.getOptLimitUntil());
			}

			/**
			 * 	List all logs before specified date.
			 */
			if (options.isOptLimitCommitBefore()) {
				command.add("--before="+ options.getOptLimitBefore());
			}

			/**
			 * 	List all logs by an author
			 */
			if (options.isOptLimitAuthor()) {
				command.add("--author="+ options.getOptAuthor());
			}

			/**
			 * 	List all logs by an author/committer header pattern.
			 */
			if (options.isOptLimitCommitterPattern()) {
				command.add("--committer="+ options.getOptLimitPattern());
			}

			/**
			 * 	List all logs by matching to a grep pattern.
			 */
			if (options.isOptLimitGrep()) {
				command.add("--grep="+ options.getOptLimitGrepPattern().toString());
			}
			/**
			 * 	Match regular expressions with out  regard to letters case.
			 */
			if (options.isOptLimitMatchIgnoreCase()) {
				command.add("-i");
			}

			/**
			 * 	Match extended regular expressions.
			 */
			if (options.isOptLimitEnableExtendedRegex()) {
				command.add("-E");
			}

			/**
			 * 	Match patterns as fixed strings and not regular expressions.
			 */
			if (options.isOptLimitMatchIgnoreCase()) {
				command.add("-F");
			}

			/**
			 * 	Stop when a path dissapears from the tree.
			 */
			if (options.isOptLimitRemoveEmpty()) {
				command.add("--remove-empty");
			}

			/**
			 * 	Match parts of history irrelevant to the current path.
			 */
			if (options.isOptLimitFullHistory()) {
				command.add("--full-history");
			}

			/**
			 * 	Do not print commits with more than one merges.
			 */
			if (options.isOptLimitNoMerges()) {
				command.add("--no-merges");
			}

			/**
			 * 	Follow only first parent on seeing a merge.
			 */
			if (options.isOptLimitFirstParent()) {
				command.add("--first-parent");
			}

			/**
			 * 	Order commits topologically.
			 */
			if (options.isOptOrderingTopological()) {
				command.add("--topo-order");
			}

			/**
			 * 	Order commits in reverse
			 */
			if (options.isOptOrderingReverse()) {
				command.add("--reverse");
			}

			/**
			 * 	Limits the number of commits to retrieve.
			 */
			if (options.isOptLimitCommitMax()) {
				command.add("-n");
				command.add(String.valueOf(options.getOptLimitMax()));
			}

			// Skips the specified number of commit messages
			if (options.isOptLimitCommitSkip()) {
			  command.add("--skip=" + options.getOptLimitSkip());
			}
		}

		return command;

	}

	/**
	 * Parser class to parse the output generated by git log; and return a
	 * GitLogResponse object.
	 */
	public class GitLogParser implements IParser {

		private int linesAdded = 0;
		private int linesDeleted = 0;
		private boolean canCommit = false;
		private String filename = null;
		private String []tmp ;
		private GitLogResponse response = new GitLogResponse();

		/**
		 * Add the final parsed commit. and returns the response of git log execution.
		 */
		public CommandResponse getResponse() throws JavaGitException {
			response.addCommit();
			return this.response;
		}

    /**
		 *  Parses a line at a time from the commandline execution output of git log
		 */
		public void parseLine(String line) {
			if(line.length() == 0){
				return;
			}

			//commit
			if (line.startsWith("commit")){
				if(canCommit){
					response.addCommit();

				}
				canCommit = true;
				tmp = line.split(" ");
				response.setSha(line.substring(tmp[0].length()).trim());
			}
			//merge (optional)
			else if (line.startsWith("Merge")){
				List<String> mergeDetails = new ArrayList<String>();
				tmp = line.split(" ");
				StringTokenizer st = new StringTokenizer(line.substring(tmp[0].length()));
				while(st.hasMoreTokens()){
					mergeDetails.add(st.nextToken().trim());
				}

				response.setMergeDetails(mergeDetails);
				mergeDetails = null;
			}
			//Author
			else if (line.startsWith("Author")){
				tmp = line.split(" ");
				response.setAuthor(line.substring(tmp[0].length()).trim());
			}
			//Date
			else if (line.startsWith("Date")){
				tmp = line.split(" ");
				response.setDate(line.substring(tmp[0].length()).trim());
			}
			//message or fileDetails (always starts with an int)
			else{
				StringTokenizer st = new StringTokenizer(line);
				try{
					linesAdded = Integer.parseInt(st.nextToken());
					linesDeleted = Integer.parseInt(st.nextToken());
					filename = st.nextToken().toString();
					response.addFile(filename,linesAdded,linesDeleted);
				}
				catch(NumberFormatException nfe){
					try{
						if (st.nextToken().equals("-")){
							linesAdded = 0;
							linesDeleted = 0;
							filename = st.nextToken().toString();
							response.addFile(filename,linesAdded,linesDeleted);
						}
						else{
							response.setMessage(line);
						}
					}
					catch(NoSuchElementException nsee){
						response.setMessage(line);
					}
				}
				catch(NoSuchElementException nsee){
					response.setMessage(line);
				}
				catch(Exception e){
					response.setMessage(line);
				}
			}
		}

	public void processExitCode(int code) {
		// TODO Auto-generated method stub

	}
	}
}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.api.commands;

import java.util.ArrayList;
import java.util.List;

import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * 	A response data object for the git log command.
 */
public class GitLogResponse implements CommandResponse {

	private List<Commit> commitList = new ArrayList<Commit>();
	protected List<ResponseString> errors = new ArrayList<ResponseString>();

	//local variables used to store parsed data until it is pushed into the object
	private String sha = null;
	private List<String> mergeDetails = null;
	private String dateString = null;
	private String message = null;
	private List<CommitFile> files = null;
	private String author = null;

	/**
	 *
	 * @return true is the response object contain an error
	 */
	public boolean containsError() {
		return ( errors.size() > 0 );
	}

	/**
	 *
	 * @param sha This sets the sha extracted from each commit entry.
	 */
	public void setSha(String sha){
		this.sha = sha;
	}

	/**
	 *
	 * @param mergeDetails This stored the merge details of a commit. eg. Merge: f859e80... 55a5e32...
	 */
	public void setMergeDetails(List<String> mergeDetails){
		this.mergeDetails = mergeDetails;
	}

	/**
	 *
	 * @param string This returns the Date object for a particular commit.
	 */
	public void setDate(String string){
		this.dateString = string;
	}
	/**
	 *
	 * @param author This sets the author for a commit.
	 */
	public void setAuthor(String author){
		this.author = author;
	}
	/**
	 *
	 * @param message This set the message for a commmit.
	 */
	public void setMessage(String message){
		if (this.message == null){
			this.message = message;
		}
		else{
			this.message += message;
		}

	}
	/**
	 *
	 * @param file This adds a file entry to the list of files modified for a single commit.
	 */
	public void addFile(CommitFile file){
		if (files==null){
			files = new ArrayList<CommitFile>();
		}
		this.files.add(file);
	}

	/**
	 * This add a newly created commit object to the list of commits for a log.
	 */
	public void addCommit(){
		if(this.sha!=null){
			Commit commit = new Commit(this.sha, this.mergeDetails, this.author, this.dateString,
					this.message, this.files);
			if (commitList == null){
				commitList = new ArrayList<Commit>();
			}

			this.commitList.add(commit);
			//reset variables for future commits.
			this.files = null;
			this.mergeDetails = null;
			this.message = null;
		}
	}
	/**
	 * This adds a file to the list of files affected by a particular commit.
	 * @param filename The filename affected by the commit.
	 * @param linesAdded	Number of lines added in the above file in that particular commit.
	 * @param linesDeleted	Number of lines deleted in the above file in that particular commit.
	 */
	public void addFile(String filename,int linesAdded, int linesDeleted){
		CommitFile commitFile = new CommitFile(filename, linesAdded, linesDeleted);
		if (files == null){
			files = new ArrayList<CommitFile>();
		}
		this.files.add(commitFile);
	}
	/**
	 * @param index
	 *          Returns the index of error.
	 * @return The index of error.
	 */
	public ResponseString getError(int index) {
		CheckUtilities.checkIntInRange(index, 0, errors.size());
		return ( errors.get(index) );
	}

	/**
	 *
	 * @return	This returns the commit list of the particular log instance.
	 */
	public List<Commit> getLog() {

		return this.commitList;
	}

	/**
	 *
	 * A data structure which  holds information about each commit.
	 *
	 */
	public static class Commit{

		String sha = null;
		List<String> mergeDetails = null;
		String author = null;
		String date = null;

		String message = null;

		//Additional Commit details
		List<CommitFile> files = null;

		int filesChanged = 0;
		int linesInserted = 0;
		int linesDeleted = 0;

		/**
		 * Constructor for creating a commit data structure.
		 * @param sha	The SHA hash for a particular commit instance.
		 * @param mergeDetails	The Merge details for a particular commit instance. Pass null is commit is not a merge
		 * @param author	The Author for a particular commit instance.
		 * @param date	The Date of a particular commit instance.
		 * @param message	The Message for a particular commit instance.
		 * @param files	The list of files affected by a particular commit instance.
		 */
		public Commit(String sha, List<String> mergeDetails, String author, String date,
				String message, List<CommitFile> files) {
			super();
			this.sha = sha;
			this.mergeDetails = mergeDetails;
			this.author = author;
			this.date = date;
			this.message = message;
			this.files = files;
			setLinesInsertionsDeletions();
			setFilesChanged();
		}

		/**
		 *
		 * @return This returns the SHA for each commit.
		 */
		public String getSha() {
			return sha;
		}

		/**
		 *
		 * @return This returns the merge details for each commit. If the commit was not a merge it returns null.
		 */
		public List<String> getMergeDetails() {
			return mergeDetails;
		}
		/**
		 *
		 * @return This return the name of the author of the commit.
		 */
		public String getAuthor() {
			return author;
		}

		/**
		 *
		 * @return This return the Date object for a particular commmit.
		 */
		public String getDateString() {
			return date;
		}
		/**
		 *
		 * @return	This returns the message of a commit.
		 */
		public String getMessage() {
			return message;
		}
		/**
		 *  This returns the list of files affected by a particular commit.
		 */
		public List<CommitFile> getFiles() {
			return files;
		}

		/**
		 *
		 * @param sha sets the SHA for a commit.
		 */
		public void setSha(String sha) {
			this.sha = sha;
		}
		/**
		 *
		 * @param mergeDetails This set the merge details for a particular commit.
		 */
		public void setMergeDetails(List<String> mergeDetails) {
			this.mergeDetails = mergeDetails;
		}
		/**
		 *
		 * @param author This sets the Author of a particular commit.
		 */
		public void setAuthor(String author) {
			this.author = author;
		}
		/**
		 *
		 * @param date	This sets the Date object for a particular commit.
		 */
		public void setDateString(String date) {
			this.date = date;
		}
		/**
		 *
		 * @param message This sets the Message for a particular commit.
		 */
		public void setMessage(String message) {
			this.message = message;
		}
		/**
		 *
		 * @param files This sets the list of files affected by a particular commit.
		 */
		public void setFiles(List<CommitFile> files) {
			this.files = files;
		}

		/**
		 * This methods calculated the total number of files affected by a particular commit.
		 */
		void setFilesChanged() {
			if(this.files != null){
				this.filesChanged = this.files.size();
			}
			else{
				this.filesChanged = 0;
			}

		}
		/**
		 * This calculated the Total number of lines Added and Deleted for a particular commit.
		 */
		void setLinesInsertionsDeletions(){
			if(this.files != null){
				for(int i = 0; i< this.files.size();i++){
					this.linesInserted += files.get(i).linesAdded;
					this.linesDeleted += files.get(i).linesDeleted;
				}

			}
			else{
				this.linesInserted = 0;
				this.linesDeleted = 0;
			}
		}

		/**
		 *
		 * @return The number of lines deleted for a paticular commit.
		 */
		public int getLinesDeleted() {
			return this.linesDeleted;
		}

		/**
		 *
		 * @return @return The number of lines inserted for a particular commit.
		 */
		public int getLinesInserted() {
			return this.linesInserted;
		}

		/**
		 *
		 * @return The number of files changed in a particular commit.
		 */
		public int getFilesChanged() {
			return this.filesChanged;
		}
	}

	/**
	 *
	 * This class hold information about a file affected by a commit
	 *
	 */
	public static  class CommitFile{

		String filename = null;
		int linesAdded = 0;
		int linesDeleted = 0;
		public CommitFile(String name, int linesAdded, int linesDeleted) {
			super();
			this.filename = name;
			this.linesAdded = linesAdded;
			this.linesDeleted = linesDeleted;
		}
		public String getName() {
			return filename;
		}

		public int getLinesAdded() {
			return linesAdded;
		}

		public int getLinesDeleted() {
			return linesDeleted;
		}
	}

  public static class ResponseString {
    final String error;
         final int lineNumber;

    public ResponseString(int lineNumber, String error) {
      this.lineNumber = lineNumber;
      this.error = error;
    }

     public int getLineNumber() {
       return lineNumber;
     }

    public String error() {
      return error;
    }
  }
}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.client.cli;

import edu.nyu.cs.javagit.api.JavaGitConfiguration;
import edu.nyu.cs.javagit.api.JavaGitException;
import edu.nyu.cs.javagit.api.Ref;
import edu.nyu.cs.javagit.api.Ref.RefType;
import edu.nyu.cs.javagit.api.commands.GitCheckoutOptions;
import edu.nyu.cs.javagit.api.commands.GitCheckoutResponse;
import edu.nyu.cs.javagit.client.GitCheckoutResponseImpl;
import edu.nyu.cs.javagit.client.IGitCheckout;
import edu.nyu.cs.javagit.utilities.CheckUtilities;
import edu.nyu.cs.javagit.utilities.ExceptionMessageMap;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Command-line implementation of the IGitCheckout interface.
 */
public class CliGitCheckout implements IGitCheckout {

    /**
     * String pattern for matching files with modified, deleted, added words in the output.
     */
    private enum Pattern {
        MODIFIED("^M\\s+\\w+"), DELETED("^D\\s+\\w+"), ADDED("^A\\s+\\w+");

        String pattern;

        private Pattern(String pattern) {
            this.pattern = pattern;
        }

        public boolean matches(String line) {
            return line.matches(pattern);
        }
    }

    /**
     * Git checkout with options and base branch information provided to <git-checkout> command.
     */
    public GitCheckoutResponse checkout(File repositoryPath, GitCheckoutOptions options, Ref ref)
            throws JavaGitException, IOException {
        CheckUtilities.checkFileValidity(repositoryPath);
        checkRefAgainstRefType(ref, RefType.HEAD);
        List<String> command = buildCommand(options, ref);
        GitCheckoutParser parser = new GitCheckoutParser();
        GitCheckoutResponse response = (GitCheckoutResponse) ProcessUtilities.runCommand(repositoryPath,
                command, parser);
        return response;
    }

    /**
     * Git checkout without any options and branch information provided. Just a basic checkout
     * command.
     */
    public GitCheckoutResponse checkout(File repositoryPath) throws JavaGitException, IOException {
        GitCheckoutOptions options = null;
        return checkout(repositoryPath, options, null);
    }

    /**
     * Checks out a branch from the git repository with a given branch name.
     */
    public GitCheckoutResponse checkout(File repositoryPath, Ref branch) throws JavaGitException,
            IOException {
        return checkout(repositoryPath, null, branch);
    }

    /**
     * Checks out a list of files from repository, no checkout options provided.
     */
    public GitCheckoutResponse checkout(File repositoryPath, List<File> paths)
            throws JavaGitException, IOException {
        CheckUtilities.checkFileValidity(repositoryPath);
        CheckUtilities.checkNullListArgument(paths, "list of file paths");
        GitCheckoutParser parser = new GitCheckoutParser();
        List<String> command = buildCommand(null, null, paths);
        GitCheckoutResponse response = (GitCheckoutResponse) ProcessUtilities.runCommand(repositoryPath,
                command, parser);
        return response;
    }

    /**
     * Checks out a list of file from repository, with <tree-ish> options provided.
     */
    public GitCheckoutResponse checkout(File repositoryPath, GitCheckoutOptions options, Ref ref,
                                        List<File> paths) throws JavaGitException, IOException {
        CheckUtilities.checkFileValidity(repositoryPath);
        if (ref != null && ref.getRefType() == RefType.HEAD) {
            throw new IllegalArgumentException("Invalid ref type passed as argument to checkout");
        }
        GitCheckoutParser parser = new GitCheckoutParser();
        List<String> command = buildCommand(options, ref, paths);
        return (GitCheckoutResponse) ProcessUtilities.runCommand(repositoryPath, command, parser);
    }

    /**
     * Checks out a file from repository from a particular branch
     */
    public GitCheckoutResponse checkout(File repositoryPath, GitCheckoutOptions options, Ref branch,
                                        File path) throws JavaGitException, IOException {
        CheckUtilities.checkFileValidity(repositoryPath);
        GitCheckoutParser parser = new GitCheckoutParser();
        List<File> paths = new ArrayList<File>();
        paths.add(path);
        List<String> command = buildCommand(options, branch, paths);
        GitCheckoutResponse response = (GitCheckoutResponse) ProcessUtilities.runCommand(repositoryPath,
                command, parser);
        return response;
    }

    /**
     * Checks out a list of files from a given branch
     */
    public GitCheckoutResponse checkout(File repositoryPath, Ref branch, List<File> paths)
            throws JavaGitException, IOException {
        CheckUtilities.checkFileValidity(repositoryPath);
        GitCheckoutParser parser = new GitCheckoutParser();
        List<String> command = buildCommand(null, branch, paths);
        GitCheckoutResponse response = (GitCheckoutResponse) ProcessUtilities.runCommand(repositoryPath,
                command, parser);
        return response;
    }

    /**
     * This is just a test method for verifying that a given ref is not of refType provided as one of the parameters.
     *
     * @param ref     This could be branch, sha1 etc.
     * @param refType This is the RefType which the ref should not match.
     */
    private void checkRefAgainstRefType(Ref ref, RefType refType) {
        if (ref != null && ref.getRefType() == refType) {
            throw new IllegalArgumentException("Invalid ref type passed as argument to checkout");
        }
    }

    /**
     * builds a <git-checkout> command in sth List<String> format.
     *
     * @param options GitCheckoutOptions options passed to the <git-checkout> command.
     * @param treeIsh either a branch type or sha1 type object
     * @param paths   List of files that are to be checked out
     * @return Command to be executed as a list of String
     * @throws JavaGitException
     */
    private List<String> buildCommand(GitCheckoutOptions options, Ref treeIsh, List<File> paths)
            throws JavaGitException {
        List<String> command = new ArrayList<String>();
        command.add(JavaGitConfiguration.getGitCommand());
        command.add("checkout");
        // Process options
        if (options != null) {
            processOptions(command, options);
        }
        // Process tree-ish
        if (treeIsh != null) {
            command.add(treeIsh.getName());
        }
        // return if no file-paths are provided
        if (paths == null) {
            return command;
        }
        command.add("--");
        for (File file : paths) {
            command.add(file.getName());
        }
        return command;
    }

    private List<String> buildCommand(GitCheckoutOptions options, Ref branch) throws JavaGitException {
        List<String> command = new ArrayList<String>();
        command.add(JavaGitConfiguration.getGitCommand());
        command.add("checkout");
        if (options != null) {
            processOptions(command, options);
        }
        if (branch != null && branch.getName().length() > 0) {
            command.add(branch.getName());
        }
        return command;
    }

    private void processOptions(List<String> command, GitCheckoutOptions options)
            throws JavaGitException {
        if (options.optQ()) {
            command.add("-q");
        }
        if (options.optF()) {
            command.add("-f");
        }
        // --track and --no-track options are valid only with -b option
        Ref newBranch;
        if ((newBranch = options.getOptB()) != null) {
            if (options.optNoTrack() && options.optTrack()) {
                throw new JavaGitException(120, "Both --notrack and --track options are set");
            }
            if (options.optTrack()) {
                command.add("--track");
            }
            if (options.optNoTrack()) {
                command.add("--no-track");
            }
            command.add("-b");
            command.add(newBranch.getName());
        }
        if (options.optL()) {
            command.add("-l");
        }
        if (options.optM()) {
            command.add("-m");
        }
    }

    /**
     * Parser class to parse the output generated by <git-checkout> and return a
     * GitCheckoutResponse object.
     */
    public static class GitCheckoutParser implements IParser {

        private static final char QUOTE_CHAR = '"';
        private static final char SINGLE_QUOTE_CHAR = '\'';

        private int lineNum;
        private GitCheckoutResponseImpl response;
        private List<ErrorDetails> errors;

        public GitCheckoutParser() {
            lineNum = 0;
            response = new GitCheckoutResponseImpl();
            errors = new ArrayList<ErrorDetails>();
        }

        public void parseLine(String line) {
            if (line == null || line.length() == 0) {
                return;
            }
            ++lineNum;
            if (!isErrorLine(line)) {
                parseSwitchedToBranchLine(line);
                parseFilesInfo(line);
            }
        }

        private boolean isErrorLine(String line) {
            if (line.startsWith("error") || line.startsWith("fatal")) {
                setError(lineNum, line);
                return true;
            }
            return false;
        }

        public void parseSwitchedToBranchLine(String line) {
            if (line.startsWith("Switched to branch")) {
                getSwitchedToBranch(line);
            } else if (line.startsWith("Switched to a new branch")) {
                getSwitchedToNewBranch(line);
            }
        }

        private void getSwitchedToBranch(String line) {
            String branchName = extractBranchName(line);
            Ref branch = Ref.createBranchRef(branchName);
            response.setBranch(branch);
        }

        private void getSwitchedToNewBranch(String line) {
            String newBranchName = extractBranchName(line);
            Ref newBranch = Ref.createBranchRef(newBranchName);
            response.setNewBranch(newBranch);
        }

        private String extractBranchName(String line) {
            int startIndex = line.indexOf(QUOTE_CHAR);
            int endIndex = line.indexOf(QUOTE_CHAR, startIndex + 1);
            return (startIndex == -1 || endIndex == -1) ? extractBranchName(line, SINGLE_QUOTE_CHAR) : extractBranchName(line, QUOTE_CHAR);
        }

        private String extractBranchName(String line, char delim) {
            int startIndex = line.indexOf(delim);
            int endIndex = line.indexOf(delim, startIndex + 1);
            return line.substring(startIndex, endIndex + 1);
        }

        private void parseFilesInfo(String line) {
            if (Pattern.MODIFIED.matches(line)) {
                File file = new File(extractFileName(line));
                response.addModifiedFile(file);
                return;
            }
            if (Pattern.DELETED.matches(line)) {
                File file = new File(extractFileName(line));
                response.addDeletedFile(file);
                return;
            }
            if (Pattern.ADDED.matches(line)) {
                File file = new File(extractFileName(line));
                response.addAddedFile(file);
            }
        }

        private String extractFileName(String line) {
            String filename = null;
            Scanner scanner = new Scanner(line);
            while (scanner.hasNext()) {
                filename = scanner.next();
            }
            return filename;
        }

        public void processExitCode(int code) {
        }

        public GitCheckoutResponse getResponse() throws JavaGitException {
            if (errors.size() > 0) {
                throw new JavaGitException(406000, ExceptionMessageMap.getMessage("406000") +
                        " - git checkout error message: { " + getError() + " }");
            }
            return response;
        }

        private String getError() {
            StringBuilder buffer = new StringBuilder();
            for (int i = 0; i < errors.size(); i++) {
                buffer.append(errors.get(i) + " ");
            }
            return buffer.toString();
        }

        private void setError(int lineNumber, String error) {
            ErrorDetails errorDetails = new ErrorDetails(lineNumber, error);
            errors.add(errorDetails);
        }

        private static class ErrorDetails {
            final int lineNumber;
            final String error;

            public ErrorDetails(int lineNumber, String error) {
                this.lineNumber = lineNumber;
                this.error = error;
            }
        }
    }

}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.api;

import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;

import edu.nyu.cs.javagit.api.commands.GitLog;
import edu.nyu.cs.javagit.api.commands.GitLogOptions;
import edu.nyu.cs.javagit.api.commands.GitLogResponse.Commit;

/**
 * GitDirectory represents a directory object in a git working tree.
 */
public class GitDirectory extends GitFileSystemObject {
  /**
   * The constructor.  Both arguments are required (i.e. cannot be null).
   *
   * @param dir
   *          The underlying {@link java.io.File} object that we want to augment with git
   *          functionality.
   * @param workingTree
   *          The WorkingTree that this directory falls under.
   *
   */
  protected GitDirectory(File dir, WorkingTree workingTree) throws JavaGitException {
    super(dir, workingTree);
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof GitDirectory)) {
      return false;
    }

    GitFileSystemObject gitObj = (GitFileSystemObject) obj;
    return super.equals(gitObj);
  }

  /**
   * Gets the children of this directory.
   *
   * @return The children of this directory.
   */
  public List<GitFileSystemObject> getChildren() throws IOException, JavaGitException {
    List<GitFileSystemObject> children = new ArrayList<GitFileSystemObject>();

    // get all of the file system objects currently located under this directory
    for (File memberFile : file.listFiles()) {
      // check if this file is hidden also some times the .git and
      //other unix hidden directories are not hidden in Windows
      if (memberFile.isHidden()||memberFile.getName().startsWith(".")) {
        // ignore (could be .git directory)
        continue;
      }

      // now, just check for the type of the filesystem object
      if (memberFile.isDirectory()) {
        children.add(new GitDirectory(memberFile, workingTree));
      } else {
        children.add(new GitFile(memberFile, workingTree));
      }
    }

    return children;
  }

	/**
	 * Show commit logs
	 *
	 * @return List of commits for the working directory
	 * @throws IOException
	 * @throws JavaGitException
	 */
	public List<Commit> getLog() throws JavaGitException, IOException {
		GitLog gitLog = new GitLog();
		return gitLog.log(this.file);
	}

	/**
	 *
	 * @param options	Options to the git log command
	 * @return	List of commits for the working directory
	 * @throws JavaGitException
	 * @throws IOException
	 */
	public List<Commit> getLog(GitLogOptions options) throws JavaGitException, IOException {
		GitLog gitLog = new GitLog();
		return gitLog.log(this.file,options);
	}
}


/*
 * ====================================================================
 * Copyright (c) 2008 JavaGit Project.  All rights reserved.
 *
 * This software is licensed using the GNU LGPL v2.1 license.  A copy
 * of the license is included with the distribution of this source
 * code in the LICENSE.txt file.  The text of the license can also
 * be obtained at:
 *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *
 * For more information on the JavaGit project, see:
 *
 *   http://www.javagit.com
 * ====================================================================
 */
package edu.nyu.cs.javagit.api.commands;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * GitRmResponse holds the response information returned by the GitRm
 * class.
 */
public abstract class GitRmResponse implements CommandResponse {

  // The list of removed files.
  protected List<File> removedFiles = new ArrayList<File>();

  /**
   * Gets the file at the specified index from the removed file list.
   *
   * @param index
   *          The index of the file to get. It must fall in the range:
   *          0 <= index < getRemovedFilesSize().
   * @return The file at the specified index.
   */
  public File getRemovedFile(int index) {
    CheckUtilities.checkIntIndexInListRange(removedFiles, index);
    return removedFiles.get(index);
  }

  /**
   * Gets an Iterator over the list of removed files.
   *
   * @return An Iterator over the list of removed files.
   */
  public Iterator<File> getRemovedFilesIterator() {
    return (new ArrayList<File>(removedFiles)).iterator();
  }

  /**
   * Gets the number of removed files (provided that the quiet option was not used).
   *
   * @return The number of removed files. If the quiet option was used, zero (0) will be returned.
   */
  public int getRemovedFilesSize() {
    return removedFiles.size();
  }

}