/*
 * ====================================================================
 * 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.commands.GitBranch;
import edu.nyu.cs.javagit.api.commands.GitCommitOptions;
import edu.nyu.cs.javagit.client.GitCommitResponseImpl;
import edu.nyu.cs.javagit.client.IGitCommit;
import edu.nyu.cs.javagit.utilities.CheckUtilities;
import edu.nyu.cs.javagit.utilities.ExceptionMessageMap;
import edu.nyu.cs.javagit.utilities.StringUtilities;

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

/**
 * Command-line implementation of the IGitCommit interface.
 */
public class CliGitCommit implements IGitCommit {

    public GitCommitResponseImpl commitAll(File repository, String message) throws IOException,
            JavaGitException {
        GitCommitOptions options = new GitCommitOptions();
        options.setOptAll(true);
        return commitProcessor(repository, options, message, null);
    }

    public GitCommitResponseImpl commit(File repository, GitCommitOptions options, String message)
            throws IOException, JavaGitException {
        return commitProcessor(repository, options, message, null);
    }

    public GitCommitResponseImpl commit(File repository, GitCommitOptions options, String message,
                                        List<File> paths) throws IOException, JavaGitException {
        return commitProcessor(repository, options, message, paths);
    }

    public GitCommitResponseImpl commit(File repository, String message) throws IOException,
            JavaGitException {
        return commitProcessor(repository, null, message, null);
    }

    public GitCommitResponseImpl commitOnly(File repository, String message, List<File> paths)
            throws IOException, JavaGitException {
        GitCommitOptions options = new GitCommitOptions();
        options.setOptOnly(true);
        return commitProcessor(repository, options, message, paths);
    }

    /**
     * Processes the commit.
     *
     * @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 commit 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 commit with.
     * @param message    The message to attach to the commit. A non-zero length argument is required for this
     *                   parameter, otherwise a NullPointerException or
     *                   IllegalArgumentException will be thrown.
     * @param paths      A list of folders and/or files to commit. The paths specified in this list must all be
     *                   relative to the path specified in the repository parameter as returned
     *                   by File.getPath().
     * @return The results from the commit.
     * @throws 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

     *

     * @throws JavaGitException Thrown when there is an error making the commit.
     */
    protected GitCommitResponseImpl commitProcessor(File repository, GitCommitOptions options,
                                                    String message, List<File> paths) throws IOException, JavaGitException {
        CheckUtilities.checkNullArgument(repository, "repository");
        CheckUtilities.checkStringArgument(message, "message");

        List<String> commandLine = buildCommand(options, message, paths);
        GitCommitParser parser = new GitCommitParser(repository.getAbsolutePath());

        return (GitCommitResponseImpl) ProcessUtilities.runCommand(repository, commandLine, parser);
    }

    /**
     * Builds a list of command arguments to pass to ProcessBuilder.
     *
     * @param options The options to include on the command line.
     * @param message The message for the commit.
     * @return A list of the individual arguments to pass to ProcessBuilder.
     */
    protected List<String> buildCommand(GitCommitOptions options, String message, List<File> paths) {

        // TODO (jhl388): Add a unit test for this method (CliGitCommit.buildCommand()).

        List<String> cmd = new ArrayList<String>();
        cmd.add(JavaGitConfiguration.getGitCommand());
        cmd.add("commit");

        if (null != options) {
            if (options.isOptAll()) {
                cmd.add("-a");
            }
            if (options.isOptInclude()) {
                cmd.add("-i");
            }
            if (options.isOptNoVerify()) {
                cmd.add("--no-verify");
            }
            if (options.isOptOnly()) {
                cmd.add("-o");
            }
            if (options.isOptSignoff()) {
                cmd.add("-s");
            }
            String author = options.getAuthor();
            if (null != author && author.length() > 0) {
                cmd.add("--author");
                cmd.add(options.getAuthor());
            }
        }

        cmd.add("-m");
        cmd.add(message);

        if (null != paths) {
            cmd.add("--");
            for (File f : paths) {
                cmd.add(f.getPath());
            }
        }

        return cmd;
    }

    public class GitCommitParser implements IParser {

        public static final String ERROR_OBTAINING_BRACH_NAME = "Error obtaining brach name : ";
        // Holding onto the error message to make part of an exception
        private StringBuffer errorMsg = null;

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

        // The response object for a commit.
        private GitCommitResponseImpl response;

        // Repository path
        private String repositoryPath;

        // Branch name
        private String branchName;

        public GitCommitParser(String repositoryPath) {
            this(repositoryPath, null);
        }

        public GitCommitParser(String repositoryPath, String branchName) {
            this.repositoryPath = repositoryPath;
            this.branchName = branchName;
        }

        public void parseLine(String line) {

            // TODO (jhl388): handle error messages in a better manner.

            if (null != errorMsg) {
                ++numLinesParsed;
                errorMsg.append(", line" + numLinesParsed + "=[" + line + "]");
                return;
            }

            switch (numLinesParsed) {
                case 0:
                    parseLineOne(line);
                    break;
                case 1:
                    parseLineTwo(line);
                    break;
                default:
                    parseAllOtherLines(line);
            }
            ++numLinesParsed;
        }

        /**
         * Parses the first line of the commit response text.
         *
         * @param line The line of text to process.
         */
        private void parseLineOne(String line) {

            if (line.startsWith("Created initial commit ") || line.startsWith("Created commit ")) {
                int locColon = line.indexOf(':');
                int locShortHash = line.lastIndexOf(' ', locColon);
                String shortHash = line.substring(locShortHash + 1, locColon);
                String shortComment = line.substring(locColon + 2);
                response = new GitCommitResponseImpl(Ref.createSha1Ref(shortHash), shortComment);

            } else if (line.startsWith("[")) {

                if (obtainBranchName()) return;

                if (line.matches("^\\[" + branchName + " .*].*")) {
                    // [master (root-commit) 6bee5e9] commit message
                    int closingSqBracket = line.indexOf(']');
                    int hashEnd = closingSqBracket - 1;
                    int hashBegin = StringUtilities.indexOfLeft(line, hashEnd, ' ') + 1;
                    String shortHash = line.substring(hashBegin, hashEnd + 1);

                    String shortComment = line.substring(closingSqBracket + 2);

                    response = new GitCommitResponseImpl(Ref.createSha1Ref(shortHash), shortComment);
                } else {
                    append2ErrorMsg("line1=[" + line + "]");
                }
            } else {
                append2ErrorMsg("line1=[" + line + "]");
            }
        }

        private boolean obtainBranchName() {
            if (branchName == null) {
                GitBranch gitBranch = new GitBranch();
                try {
                    branchName = gitBranch.branch(new File(repositoryPath)).getCurrentBranch().getName();
                } catch (IOException e) {
                    append2ErrorMsg(ERROR_OBTAINING_BRACH_NAME + e.getMessage());
                    return true;
                } catch (JavaGitException e) {
                    append2ErrorMsg(ERROR_OBTAINING_BRACH_NAME + e.getMessage());
                    return true;
                }
            }
            return false;
        }

        private void append2ErrorMsg(String line) {
            if (errorMsg == null)
                errorMsg = new StringBuffer();

            errorMsg.append(line);
        }

        /**
         * Parse the second line of the commit response text.
         *
         * @param line The line of text to process.
         */
        private void parseLineTwo(String line) {
            // Some output samples for line 2 :
            // 2 files changed, 1 insertion(+), 1 deletion(-)
            //      or
            // 1 file changed, 1 insertion(+)
            //      or
            // 0 files changed

            int spaceOffset = line.indexOf(' ', 1);
            response.setFilesChanged(line.substring(1, spaceOffset));

            int commaOffset = line.indexOf(',', spaceOffset);
            spaceOffset = line.indexOf(' ', commaOffset + 2);

            if (commaOffset == -1) {
                response.setLinesInserted(0);
                response.setLinesDeleted(0);
                return;
            }

            response.setLinesInserted(line.substring(commaOffset + 2, spaceOffset));

            commaOffset = line.indexOf(',', spaceOffset);
            spaceOffset = line.indexOf(' ', commaOffset + 2);

            if (commaOffset == -1) {
                response.setLinesDeleted(0);
                return;
            }

            response.setLinesDeleted(line.substring(commaOffset + 2, spaceOffset));

        }

        /**
         * Parses the rest of the lines in the response from a successful commit.
         *
         * @param line The line to parse.
         */
        private void parseAllOtherLines(String line) {
            if (line.startsWith(" create")) {
                parseAddDeleteLine(line, true);
            } else if (line.startsWith(" copy")) {
                parseCopyRenameLine(line, true);
            } else if (line.startsWith(" delete")) {
                parseAddDeleteLine(line, false);
            } else if (line.startsWith(" rename")) {
                parseCopyRenameLine(line, false);
            }
        }

        /**
         * Parses an add or delete line. The formats of the lines it parses are (without quotes):
         *

         *

         *

         *

         * " create mode 100644 a/file/name.txt"
         *

         *

         *

         *

         *

         *

         * " delete mode 100644 a/file/name.txt"
         *

         *

         *

         *

         *
         * @param line  The line of text to parse.
         * @param isAdd True if parsing an add (create) line, false if parsing a delete line.
         */
        private void parseAddDeleteLine(String line, boolean isAdd) {
            final int modeOffset = 13;
            final int endModeOffset = 19;
            final int startPathOffset = 20;
            String mode = line.substring(modeOffset, endModeOffset);
            String pathStr = line.substring(startPathOffset);
            File path = new File(repositoryPath + pathStr);
            if (isAdd) {
                response.addAddedFile(path, mode);
            } else {
                response.addDeletedFile(path, mode);
            }
        }

        /**
         * Parses a copy or rename line. The formats of the lines it parses are (without quotes):
         *

         *

         *

         *

         * " copy path/to/{file.txt => newName.txt} (100%)"
         *

         *

         *

         *

         *

         *

         * " copy path/to/file.txt => different/path/newName.txt (5%)"
         *

         *

         *

         *

         *
         * @param line   The line of text to parse.
         * @param isCopy True if parsing a copy line, false if parsing a rename line.
         */
        private void parseCopyRenameLine(String line, boolean isCopy) {
            final int PATH_START_COPY = 6;
            final int PATH_START_RENAME = 8;
            int pathStart = (isCopy ? PATH_START_COPY : PATH_START_RENAME);
            int openCurlyOffset = line.indexOf('{', pathStart);
            int openParenOffset = line.lastIndexOf('(');

            String fromPathStr = null;
            String toPathStr = null;

            if (-1 == openCurlyOffset) {
                int arrowOffset = line.indexOf("=>");
                fromPathStr = line.substring(pathStart, arrowOffset - 1);
                toPathStr = line.substring(arrowOffset + 3, openParenOffset - 1);
            } else {
                String base = line.substring(pathStart, openCurlyOffset);
                int arrowOffset = line.indexOf("=>", openCurlyOffset);
                fromPathStr = base + line.substring(openCurlyOffset + 1, arrowOffset - 1);
                int closeCurlyOffset = line.indexOf('}', arrowOffset + 3);
                toPathStr = base + line.substring(arrowOffset + 3, closeCurlyOffset);
            }

            File fromPath = new File(repositoryPath + fromPathStr);
            File toPath = new File(repositoryPath + toPathStr);

            int percentOffset = line.lastIndexOf('%');
            int percentage = 0;
            try {
                percentage = Integer.parseInt(line.substring(openParenOffset + 1, percentOffset));
            } catch (NumberFormatException e) {
                // TODO (jhl388): log this error somehow! Or, at least, deal with it in a better manner.
            }

            if (isCopy) {
                response.addCopiedFile(fromPath, toPath, percentage);
            } else {
                response.addRenamedFile(fromPath, toPath, percentage);
            }
        }

        public void processExitCode(int code) {
        }

        /**
         * Gets a GitCommitResponse object containing the information from the commit
         * response text parsed by this IParser instance.
         *
         * @return The GitCommitResponse object containing the commit's response
         *         information.
         */
        public GitCommitResponseImpl getResponse() throws JavaGitException {
            if (null != errorMsg) {
                throw new JavaGitException(410000, ExceptionMessageMap.getMessage("410000")
                        + "  The git-commit error message:  { " + errorMsg.toString() + " }");
            }
            return response;
        }

        /**
         * Gets the number of lines of response text parsed by this IParser.
         *
         * @return The number of lines of response text parsed by this IParser.
         */
        public int getNumLinesParsed() {
            return numLinesParsed;
        }
    }

}


package edu.nyu.cs.javagit.api;

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

import edu.nyu.cs.javagit.api.commands.CommandResponse;
import edu.nyu.cs.javagit.client.cli.IParser;
import edu.nyu.cs.javagit.client.cli.ProcessUtilities;
import edu.nyu.cs.javagit.utilities.ExceptionMessageMap;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * This class encapsulates our global API options that client code may want to get or set.
 *
 * TODO (rs2705): Create a more generalized/modularized setup where variables and methods related to
 * specific implementation types are self-contained in their own separate classes, instead of
 * floating around in here.
 */
public final class JavaGitConfiguration {

  /*
   * The path to our git binaries. Default to null, which means that the git command is available
   * via the system PATH environment variable.
   */
  private static File gitPath = null;

  /*
   * The version string fpr the locally-installed git binaries.
   */
  private static GitVersion gitVersion = null;

  /**
   * Constructor - private because this is an all-static class.
   */
  private JavaGitConfiguration() {

  }

  /**
   * Sets the {@link #gitVersion} field.
   *

   * This function gets called in one of two ways:
   *

   * 1) When client code sets the path to the git binaries explicitly by calling {@link #setGitPath(java.io.File)},
   * this function is used to determine if the path is usable or not. In this case, the
   * File path argument will be the new path to the git binaries.
   *

   * 2) When client code calls {@link #getGitVersion()} and the path has not been set explicitly, we
   * call this function to figure out the version. In this case, the File path
   * argument will be null.
   *
   *
   * @param path
   *          File object representing the directory containing the git binaries. If
   *          null, the previously-set path is used (if any). It must contain either an absolute
   *          path, or a valid path relative to the current working directory.
   * @throws JavaGitException
   *           Thrown if git is not found at the provided path.
   */
  private static void determineGitVersion(File path) throws JavaGitException {

    /*
     * If they already set the path explicitly, or are in the process of doing so (via the path
     * argument), make sure to prefix the git call with it. If they didn't, assume it's blank.
     */
    String gitPrefix = "";
    if (path != null) {
      // We got a path passed in as an argument.
      gitPrefix = path.getAbsolutePath() + File.separator;
    } else if (gitPath != null) {
      // They didn't pass in a path, but previously set it explicitly via setGitPath.
      gitPrefix = getGitCommandPrefix();
    }

    String gitCommand = gitPrefix + "git";
    if (!(gitPrefix.equals(""))) {
      // If we've got a full path to the git binary here, ensure it actually exists.
      if (!(new File(gitCommand).exists())) {
        throw new JavaGitException(100002, ExceptionMessageMap.getMessage("100002"));
      }
    }

    List<String> commandLine = new ArrayList<String>();
    commandLine.add(gitCommand);
    commandLine.add("--version");

    // Now run the actual git version command.
    try {
      // We're passing in a working directory of null, which is "don't care" to runCommand
      gitVersion = (GitVersion) ProcessUtilities.runCommand(null, commandLine,
          new GitVersionParser());
    } catch (Exception e) {
      throw new JavaGitException(100001, ExceptionMessageMap.getMessage("100001"));
    }

    String version = gitVersion.toString();
    if (!(isValidVersionString(version))) {
      throw new JavaGitException(100001, ExceptionMessageMap.getMessage("100001"));
    }

  }

  /**
   * Return the complete string necessary to invoke git on the command line. Could be an absolute
   * path to git, or if the path was never set explicitly, just "git".
   *
   * @return String containing the path to git, ending with the git executable's name
   *         itself.
   */
  public static String getGitCommand() {
    return getGitCommandPrefix() + "git";
  }

  /**
   * Return an absolute path capable of being dropped in front of the command-line git invocation.
   * If the path hasn't been set explicitly, just return the empty string and assume git is in this
   * process' PATH environment variable.
   *
   * @return The String that points to the git executable.
   */
  public static String getGitCommandPrefix() {
    return ((gitPath == null) ? "" : (gitPath.getAbsolutePath() + File.separator));
  }

  /**
   * Accessor method for the File object representing the path to git. If the git
   * path is never set explicitly, this will return null.
   *
   * @return File object pointing at the directory containing git.
   */
  public static File getGitPath() {
    return gitPath;
  }

  /**
   * Returns the version number of the underlying git binaries. If this method is called and we
   * don't know the version yet, it tries to figure it out. (The version gets set if
   * {@link #setGitPath(File) setGitPath} was previously called.)
   *
   * @return The git version String.
   */
  public static String getGitVersion() throws JavaGitException {
      return getGitVersionObject().toString();
  }

    public static GitVersion getGitVersionObject() throws JavaGitException {
        // If the version hasn't been found yet, let's do some lazy initialization here.
        if (gitVersion == null) {
            determineGitVersion(gitPath);
        }

        return gitVersion;
    }

  /**
   * Judge the validity of a given git version string. This can be difficult to do, as there seems
   * to be no deliberately-defined git version format. So, here we do a minimal sanity check for two
   * things: 1. The first character in the version is a number. 2. There's at least one period in
   * the version string.
   *
   * @param version
   * @return true if the version passed as argument is valid
   */
  private static boolean isValidVersionString(String version) {
    /*
     * Git version strings can vary, so let's do a minimal sanity check for two things: 1. The first
     * character in the version is a number. 2. There's at least one period in the version string.
     *
     * TODO (rs2705): Make this more sophisticated by parsing out a major/minor version number, and
     * ensuring it's >= some minimally-required version.
     */
    try {
      Integer.parseInt(version.substring(0, 1));
    } catch (NumberFormatException e) {
      // First character in the version string was not a valid number!
      return false;
    }

    if (version.indexOf(".") == -1) {
      // The version string doesn't contain a period!
      return false;
    }

    return true;
  }

  /**
   * Called when client code wants to explicitly tell us where to find git on their filesystem. If
   * never called, we assume that git is in a directory in the PATH environment variable for this
   * process. Passing null as the path argument will unset an explicitly-set path and revert to
   * looking for git in the PATH.
   *
   * @param path
   *          File object representing the directory containing the git binaries. It
   *          must contain either an absolute path, or a valid path relative to the current working
   *          directory.
   * @throws IOException
   *           Thrown if the provided path does not exist.
   * @throws JavaGitException
   *           Thrown if git does not exist at the provided path, or the provided path is not a
   *           directory.
   */
  public static void setGitPath(File path) throws IOException, JavaGitException {
    if (path != null) {
      CheckUtilities.checkFileValidity(path);

      if (!(path.isDirectory())) {
        throw new JavaGitException(020002, ExceptionMessageMap.getMessage("020002") + " { path=["
            + path.getPath() + "] }");
      }
    }

    try {
       determineGitVersion(path);
    } catch (Exception e) {
      // The path that was passed in doesn't work. Catch any errors and throw this one instead.
      throw new JavaGitException(100002, ExceptionMessageMap.getMessage("100002") + " { path=["
          + path.getPath() + "] }", e);
    }

    // Make sure we're hanging onto an absolute path.
    gitPath = (path != null) ? path.getAbsoluteFile() : null;
  }

  /**
   * Convenience method for setting the path with a String instead of a
   * File.
   *
   * TODO (rs2705): Enforce the requirement below that the path be absolute. Is there a simple way
   * to do this in an OS-independent fashion?
   *
   * @param path
   *          Absolute path to git binaries installed on the system. The path must be absolute since
   *          it needs to persist for the life of the client code, even if the working directory
   *          changes. Throws a NullPointerException if path is null, or an IllegalArgumentException
   *          if it's the empty string.
   * @throws IOException
   *           Thrown if the provided path does not exist.
   * @throws JavaGitException
   *           Thrown if we cannot find git at the path provided.
   */
  public static void setGitPath(String path) throws IOException, JavaGitException {
    CheckUtilities.checkStringArgument(path, "path");
    setGitPath(new File(path));
  }

  /*
   * GitVersionParser parses the output of the git --version command.
   * It is also used to determine if the git binaries are accessible via the command line.
   *
   * TODO (rs2705): Write unit tests for this class.
   */
  private static class GitVersionParser implements IParser {
    // The version of git that we parse out.
    private String version = "";

    // Whether or not we saw a valid version string.
    private boolean parsedCorrectly = true;

    // We only care about parsing the first line of our input - watch that here.
    private boolean sawLine = false;

    /**
     * Returns the GitVersion object that's essentially just a wrapper around
     * the git version number.
     *
     * @return The response object containing the version number.
     */
    public CommandResponse getResponse() throws JavaGitException {
      if (!(parsedCorrectly)) {
        throw new JavaGitException(100001, ExceptionMessageMap.getMessage("100001"));
      }
      return new GitVersion(version);
    }

    /**
     * Parses the output of git --version. Expects to see: "git version XYZ".
     *
     * @param line
     *          String containing the line to be parsed.
     */
    public void parseLine(String line) {
      if (!(sawLine)) {
        sawLine = true;
        parsedCorrectly = (line.trim().indexOf("git version ") == 0);
        if (parsedCorrectly) {
          version = line.replaceAll("git version ", "");
        }
      }
    }

    public void processExitCode(int code) {
    }

  }

}


package org.ucmtwine.parameter;

import intradoc.common.ExecutionContext;
import intradoc.common.SystemUtils;
import intradoc.data.DataBinder;
import intradoc.data.Workspace;
import intradoc.server.Service;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.ucmtwine.annotation.Binder;
import org.ucmtwine.annotation.Environment;
import org.ucmtwine.parameter.types.InjectedParameter;

/**
 * Handles the binder parameters and type coercion for service and idoc methods
 * including parameter injection of context and user data when needed.
 *
 * @author tim
 */
public class ParameterMarshaller {

  /**
   * The function def table stores each param type plus the function index, the
   * param count and return type
   */
  public static final int EXTRA_FUNC_DEF_VALUES = 3;

  private List<IParameter> parameters;

  public ParameterMarshaller() {
    this.parameters = new ArrayList<IParameter>();
  }

  public ParameterMarshaller(Method method) throws IllegalArgumentException {
    this.parameters = createList(method);
  }

  public List<IParameter> getParameters() {
    return parameters;
  }

  public void setParameters(List<IParameter> parameters) {
    this.parameters = parameters;
  }

  /**
   * Creates the list of BinderVariables given a method obtained through
   * reflection.
   *
   * @param method
   *          The method
   * @return The list of BinderVariables
   */
  private static List<IParameter> createList(Method method) {

    List<IParameter> parameters = new ArrayList<IParameter>();

    Class<?> paramTypes[] = method.getParameterTypes();

    Annotation[][] methodAnnotations = method.getParameterAnnotations();

    for (int i = 0; i < methodAnnotations.length; i++) {

      // defaults
      boolean paramRequired = true;
      String paramName = "";
      Class<?> paramClass = paramTypes[i];

      for (Annotation a : methodAnnotations[i]) {
        if (a instanceof Binder) {
          paramName = ((Binder) a).name();
          paramRequired = ((Binder) a).required();
          break;
        }
//        else if (a instanceof Environment) {
//          paramName = ((Environment) a).name();
//          paramRequired = ((Environment) a).required();
//          break;
//        }
      }

      parameters.add(Parameter.create(paramName, paramClass, paramRequired));
    }

    return parameters;
  }

  /**
   * Returns an array of types for use with reflection method.invoke().
   *
   * @return
   */
  public Class<?>[] getTypeArray() {

    Class<?>[] typeArray = new Class[this.parameters.size()];

    for (int i = 0; i < this.parameters.size(); i++) {
      typeArray[i] = this.parameters.get(i).getType();
    }

    return typeArray;
  }

  /**
   *
   * @param includeInjected
   * @return
   */
  public int getParameterCount(boolean includeInjected) {
    int count = 0;

    for (int i = 0; i < this.parameters.size(); i++) {
      if (this.parameters.get(i) instanceof InjectedParameter) {
        if (includeInjected) {
          count++;
        }

      } else {
        count++;
      }
    }

    return count;
  }

  /**
   * Return the m_functionDefinition compatible array.
   *
   * @param maxParams
   * @return
   */
  public int[] getFunctionDefinitionArray(int functionOffset, int maxParams, int returnType) {
    int[] definition = new int[maxParams + EXTRA_FUNC_DEF_VALUES];

    int paramCount = getParameterCount(false);
    int fullParamCount = getParameterCount(true);

    definition[0] = functionOffset;

    if (paramCount > maxParams) {
      throw new IllegalStateException("Attempted to get function definition table when supplied "
          + "max parameter count " + maxParams + " is smaller than real param count " + paramCount);
    }

    definition[1] = paramCount;

    int j = 2;

    for (int i = 0; i < fullParamCount; i++) {
      // add grammar element if it is NOT an injected type
      if ((this.parameters.get(i) instanceof InjectedParameter) == false) {
        definition[j] = this.parameters.get(i).getGrammarElementType();
        j++;
      }
    }

    // pad out unspecified param types
    for (; j < definition.length - 1; j++) {
      definition[j] = Parameter.GRAMMAR_ELEMENT_UNSPECIFIED;
    }

    // return type as last value
    definition[definition.length - 1] = returnType;

    return definition;
  }

  /**
   * Returns an array of values given an array of script arguments for use with
   * the reflection method.invoke(), injecting known service/user/context data.
   *
   * @return
   * @throws IllegalAccessException
   */
  public Object[] getValueArray(Object[] arguments, Service service) {
    Object[] paramArray = new Object[this.parameters.size()];

    int argumentIndex = 0;

    for (int i = 0; i < this.parameters.size(); i++) {

      // inject params if needed
      IParameter p = this.parameters.get(i);

      try {

        if (p instanceof InjectedParameter) {
          paramArray[i] = p.getArgumentValue(null, service);
        } else {
          paramArray[i] = p.getArgumentValue(arguments[argumentIndex], service);
          argumentIndex++;
        }

      } catch (ClassCastException e) {
        SystemUtils.trace("twine", "getArgumentValue failed on parameter " + (i + 1) + ": " + e.getMessage());
      }

    }

    return paramArray;
  }

  /**
   * Returns an array of values given a filter execution context
   *
   * @param ws
   *          The system workspace
   * @param binder
   *          The current binder
   * @param ctx
   *          The current execution context
   * @return
   */
  public Object[] getValueArray(Workspace ws, DataBinder binder, ExecutionContext ctx) {
    Object[] paramArray = new Object[this.parameters.size()];

    for (int i = 0; i < this.parameters.size(); i++) {

      // inject params if needed
      IParameter p = this.parameters.get(i);

      try {

        if (p.getType() == Workspace.class) {
          paramArray[i] = ws;

        } else if (p.getType() == DataBinder.class) {
          paramArray[i] = binder;

        } else if (p.getType().isAssignableFrom(ExecutionContext.class)) {
          paramArray[i] = ctx;

        } else {
          paramArray[i] = null;
        }

      } catch (ClassCastException e) {
        SystemUtils.trace("twine", "getArgumentValue failed on parameter " + (i + 1) + ": " + e.getMessage());
      }

    }

    return paramArray;
  }

  /**
   * Returns an array of values for use with the reflection method.invoke(),
   * injecting known service/user/context data.
   *
   * @return
   * @throws IllegalAccessException
   */
  public Object[] getValueArray(Service service) {
    Object[] paramArray = new Object[this.parameters.size()];

    for (int i = 0; i < this.parameters.size(); i++) {

      IParameter p = this.parameters.get(i);

      try {
        paramArray[i] = p.getBinderValue(service);

      } catch (IllegalAccessException e) {
        SystemUtils.trace("twine", "getValue failed on parameter " + (i + 1) + ": " + e.getMessage());
      }

    }

    return paramArray;
  }
}


/*
 * ====================================================================
 * 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.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.io.File;
import java.io.IOException;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

import edu.nyu.cs.javagit.api.commands.GitBranch;
import edu.nyu.cs.javagit.api.commands.GitBranchOptions;
import edu.nyu.cs.javagit.api.commands.GitBranchResponse;
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;

/**
 * The DotGit represents the .git directory.
 */
public final class DotGit {
  // This guy's a per-repository singleton, so we need a static place to store our instances.
  private static final Map<String, DotGit> INSTANCES = new HashMap<String, DotGit>();

  // The directory that contains the .git in question.
  private final File path;

  /*
   * The canonical pathname from this file. Store this here so that we don't need to continually hit
   * the filesystem to resolve it.
   */
  private final String canonicalPath;

  /**
   * The constructor. Private because this singleton-ish (per each repository) class is only
   * available via the getInstance method.
   *
   * @param path
   *          The path to the directory containing the .git file in question.
   */
  private DotGit(File path, String canonicalPath) {
    // TODO (rs2705): Ensure that these arguments are valid (not null, not empty)
    this.path = path;
    this.canonicalPath = canonicalPath;
  }

  /**
   * Checks if there is a DotGit instance for a given path
   *
   * @param path
   *          File object representing the path to the repository.
   * @return
   *          true if exits, false otherwise;
   */
  public static synchronized boolean existsInstance(File path) {
    String canonicalPath = "";

    try {
      canonicalPath = path.getCanonicalPath();
    } catch (IOException e) {
      //obviously, the answer is NO
      return false;
    }

    return INSTANCES.containsKey(canonicalPath);
  }

  /**
   * Static factory method for retrieving an instance of this class.
   *
   * @param path
   *          File object representing the path to the repository.
   * @return The DotGit instance for this path
   */
  public static synchronized DotGit getInstance(File path) {
    DotGit dotGit;

    // TODO (rs2705): make sure that path is valid

    /*
     * We want to make sure we're dealing with the canonical path here, since there are multiple
     * ways to refer to the same dir with different strings.
     */
    String canonicalPath = "";

    try {
      canonicalPath = path.getCanonicalPath();
    } catch (Exception e) {
      /*
       * TODO (rs2705): Figure out which exception to throw here, and throw it - or should we simply
       * let it propogate up as-is?
       */

      // Temporary placeholder
      return null;
    }

    if (!(INSTANCES.containsKey(canonicalPath))) {
      dotGit = new DotGit(path, canonicalPath);
      INSTANCES.put(canonicalPath, dotGit);
    } else {
      dotGit = INSTANCES.get(canonicalPath);
    }

    return dotGit;
  }

  /**
   * Convenience method for retrieving an instance of the class using a String
   * instead of a File.
   *
   * @param path
   *          String object representing the path to the repository.
   * @return The DotGit instance for this path
   */
  public static DotGit getInstance(String path) {
    // TODO (rs2705): make sure that path is valid
    return getInstance(new File(path));
  }

  /**
   * Since instances of this class are singletons, don't allow cloning.
   *
   * @return None - always throws exception
   */
  @Override
  protected Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
  }

  /**
   * Clones the repository into new location
   *
   * @param gitFrom
   *          The .git being cloned
   */
  public void gitClone(DotGit gitFrom) {
  }

  /**
   * Creates a new branch
   *
   * @param name
   *          The name of the branch to create
   *
   * @return The new branch
   */
  public Ref createBranch(String name) throws IOException, JavaGitException {
    Ref newBranch = Ref.createBranchRef(name);
    GitBranch gitBranch = new GitBranch();
    gitBranch.createBranch(path, newBranch);
    return newBranch;
  }

  /**
   * Deletes a branch
   *
   * @param branch
   *          The branch to delete
   * @param forceDelete
   *          True if force delete option -D should be used,
   *          false if -d should be used.
   * @throws IOException
   *          Thrown in case of I/O operation failure
   * @throws JavaGitException
   *          Thrown when there is an error executing git-branch.
   */
  public void deleteBranch(Ref branch, boolean forceDelete)
    throws IOException, JavaGitException {
    GitBranch gitBranch = new GitBranch();
    gitBranch.deleteBranch(path, forceDelete, false, branch);
    branch = null;
  }

  /**
   * Renames a branch
   *
   * @param branchFrom
   *          The branch to rename
   * @param nameTo
   *          New branch name
   * @param forceRename
   *          True if force rename option -M should be used.
   *          False if -m should be used.
   * @return new Ref instance
   * @throws IOException
   *          Thrown in case of I/O operation failure
   * @throws JavaGitException
   *          Thrown when there is an error executing git-branch.
   */
  public Ref renameBranch(Ref branchFrom, String nameTo, boolean forceRename)
    throws IOException, JavaGitException {
    Ref newBranch = Ref.createBranchRef(nameTo);
    GitBranch gitBranch = new GitBranch();
    gitBranch.renameBranch(path, forceRename, branchFrom, newBranch);
    return newBranch;
  }

  /**
   * Gets a list of the branches in the repository.
   *
   * @return The branches in the repository.
   */
  public Iterator<Ref> getBranches() throws IOException, JavaGitException {
    GitBranch gitBranch = new GitBranch();
    GitBranchOptions options = new GitBranchOptions();
    GitBranchResponse response = gitBranch.branch(path, options);
    return response.getBranchListIterator();
  }

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

    DotGit dotGit = (DotGit) obj;
    return CheckUtilities.checkObjectsEqual(canonicalPath, dotGit.canonicalPath);
  }

  /**
   * Gets the repository path represented by this repository object.
   *
   * @return The path to the repository
   */
  public File getPath() {
    return path;
  }

  /**
   * Gets the working tree for this git repository
   *
   * @return The working tree
   */
  public WorkingTree getWorkingTree() {
    return WorkingTree.getInstance(path);
  }

  @Override
  public int hashCode() {
    return canonicalPath.hashCode();
  }

  /**
   * Initializes Git repository
   */
  public void init() {
    // TODO (ma1683): Implement this method
    // GitInit.init();
  }

  /**
   * Merges development histories together
   *
   * @param otherGit
   *          The other .git to merge with
   * @param m
   *          The merge options (strategy, message, etc)
   */
  public void merge(DotGit otherGit, MergeOptions m) {
  }

  /**
   * Merges development histories together
   *
   * @param gitList
   *          The list of .git to merge with; implies octopus
   * @param m
   *          The merge options (strategy, message, etc)
   */
  public void merge(List<DotGit> gitList, MergeOptions m) {
  }

  /**
   * Fetch from git repository and merge with the current one
   *
   * @param gitFrom
   *          The git repository being fetched from
   */
  public void pull(DotGit gitFrom) {
  }

  /**
   * Updates the remote git repository with the content of the current one
   *
   * @param gitTo
   *          The .git being updated
   */
  public void push(DotGit gitTo) {
  }

	/**
	 * 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.getPath());
	}

	/**
	 *
	 * @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.getPath(),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.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.GitCommitResponseImpl;
import edu.nyu.cs.javagit.client.IClient;
import edu.nyu.cs.javagit.client.IGitCommit;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * GitCommit provides an API to commit changes to a git repository.
 */
public class GitCommit {

  /**
   * Automatically stage all tracked files that have been changed and then commit all files staged
   * in the git repository's index.
   *
   * @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 commit 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 message
   *          The message to attach to the commit. A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the commit.
   * @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 GitCommitResponseImpl commitAll(File repository, String message) throws IOException,
      JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkStringArgument(message, "message");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitCommit gitCommit = client.getGitCommitInstance();
    return gitCommit.commitAll(repository, message);
  }

  /**
   * Commits staged changes into the specified repository. The specific files that are committed
   * depends on the options specified.
   *
   * @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 commit 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 commit with. If null is passed, a NullPointerException
   *          will be thrown.
   * @param message
   *          The message to attach to the commit. A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the commit.
   * @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 GitCommitResponse commit(File repository, GitCommitOptions options, String message)
      throws IOException, JavaGitException {

    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkStringArgument(message, "message");
    CheckUtilities.checkNullArgument(options, "options");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitCommit gitCommit = client.getGitCommitInstance();
    return gitCommit.commit(repository, options, message);
  }

  /**
   * Commits staged changes into the specified repository. The specific files that are committed
   * depends on the options and paths specified.
   *
   * @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 commit 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 commit with. If null is passed, a NullPointerException
   *          will be thrown.
   * @param message
   *          The message to attach to the commit. A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param paths
   *          A list of folders and/or files to commit. 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 from the commit.
   * @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 GitCommitResponse commit(File repository, GitCommitOptions options, String message,
      List<File> paths) throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkStringArgument(message, "message");
    CheckUtilities.checkNullArgument(options, "options");
    CheckUtilities.checkNullListArgument(paths, "paths");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitCommit gitCommit = client.getGitCommitInstance();
    return gitCommit.commit(repository, options, message, paths);
  }

  /**
   * Commits all staged changes (changes already defined in the index) into the specified
   * 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 commit 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 message
   *          The message to attach to the commit. A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @return The results from the commit.
   * @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 GitCommitResponse commit(File repository, String message) throws IOException,
      JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkStringArgument(message, "message");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitCommit gitCommit = client.getGitCommitInstance();
    return gitCommit.commit(repository, message);
  }

  /**
   * Commits only the changes in the specified paths into the specified repository. Any staged
   * changes (changes already defined in the index) are ignored.
   *
   * @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 commit 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 message
   *          The message to attach to the commit. A non-zero length argument is required for this
   *          parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param paths
   *          A list of folders and/or files to commit. 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 from the commit.
   * @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 GitCommitResponse commitOnly(File repository, String message, List<File> paths)
      throws IOException, JavaGitException {
    CheckUtilities.checkNullArgument(repository, "repository");
    CheckUtilities.checkStringArgument(message, "message");
    CheckUtilities.checkNullListArgument(paths, "paths");

    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitCommit gitCommit = client.getGitCommitInstance();
    return gitCommit.commitOnly(repository, message, paths);
  }

}


package org.ucmtwine.parameter.types;

import intradoc.common.GrammarElement;
import intradoc.server.Service;

import org.ucmtwine.parameter.Parameter;

public class BooleanParameter extends Parameter {

  public BooleanParameter() {
    super(Boolean.class);
  }

  public BooleanParameter(Class<?> type) {
    super(type);
  }

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

  /**
   * {@inheritDoc}
   */
  @Override
  public Object getBinderValue(Service service) {
    String binderValue = getStringValue(service.getBinder());

    return parseStringValue(binderValue);
  }

  private Boolean parseStringValue(String binderValue) {
    Boolean val = null;

    if (binderValue != null) {

      if (binderValue.equals("1")) {
        val = new Boolean(true);
      } else {
        val = new Boolean(binderValue);
      }
    }

    return val;
  }

  /**
   * {@inheritDoc}
   */
  public Object getArgumentValue(Object object, Service service) throws ClassCastException {
    if (object == null) {
      return null;
    }

    if (object.getClass() == Long.class) {
      return (Long) object == 1L;
    }

    if (object.getClass() == String.class) {
      return parseStringValue((String) object);
    }

    return super.getArgumentValue(object, service);
  }

  /**
   * {@inheritDoc}
   */
  public int getGrammarElementType() {
    return GrammarElement.INTEGER_VAL;
  }
}


/*
 * net/balusc/util/ObjectConverter.java
 *
 * Copyright (C) 2007 BalusC
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this library.
 * If not, see <http://www.gnu.org/licenses/>.
 */

package net.balusc.util;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Generic object converter.
 *

 *
Use examples

 *
 *

 * Object o1 = Boolean.TRUE;
 * Integer i = ObjectConverter.convert(o1, Integer.class);
 * System.out.println(i); // 1
 *
 * Object o2 = "false";
 * Boolean b = ObjectConverter.convert(o2, Boolean.class);
 * System.out.println(b); // false
 *
 * Object o3 = new Integer(123);
 * String s = ObjectConverter.convert(o3, String.class);
 * System.out.println(s); // 123
 *

 *
 * Not all possible conversions are implemented. You can extend the
 * <tt>ObjectConverter</tt> easily by just adding a new method to it, with the
 * appropriate logic. For example:
 *
 *

 * public static ToObject fromObjectToObject(FromObject fromObject) {
 *   // Implement.
 * }
 *

 *
 * The method name doesn't matter. It's all about the parameter type and the
 * return type.
 *
 * @author BalusC
 * @link http://balusc.blogspot.com/2007/08/generic-object-converter.html
 */
public final class ObjectConverter {

  // Init
  // ---------------------------------------------------------------------------------------

  private static final Map<String, Method> CONVERTERS = new HashMap<String, Method>();

  static {
    // Preload converters.
    Method[] methods = ObjectConverter.class.getDeclaredMethods();
    for (Method method : methods) {
      if (method.getParameterTypes().length == 1) {
        // Converter should accept 1 argument. This skips the convert() method.
        CONVERTERS.put(method.getParameterTypes()[0].getName() + "_" + method.getReturnType().getName(), method);
      }
    }
  }

  private ObjectConverter() {
    // Utility class, hide the constructor.
  }

  // Action
  // -------------------------------------------------------------------------------------

  /**
   * Convert the given object value to the given class.
   *
   * @param from
   *          The object value to be converted.
   * @param to
   *          The type class which the given object should be converted to.
   * @return The converted object value.
   * @throws NullPointerException
   *           If 'to' is null.
   * @throws UnsupportedOperationException
   *           If no suitable converter can be found.
   * @throws RuntimeException
   *           If conversion failed somehow. This can be caused by at least an
   *           ExceptionInInitializerError, IllegalAccessException or
   *           InvocationTargetException.
   */
  @SuppressWarnings("unchecked")
  public static <T> T convert(Object from, Class<T> to) {

    // Null is just null.
    if (from == null) {
      return null;
    }

    // Can we cast? Then just do it.
    if (to.isAssignableFrom(from.getClass())) {
      return to.cast(from);
    }

    // Lookup the suitable converter.
    String converterId = from.getClass().getName() + "_" + to.getName();
    Method converter = CONVERTERS.get(converterId);
    if (converter == null) {
      throw new UnsupportedOperationException("Cannot convert from " + from.getClass().getName() + " to "
          + to.getName() + ". Requested converter does not exist.");
    }

    // Convert the value.
    try {
      // primitives don't appear to have a .cast() method, which causes a null
      // pointer exception
      if (to.isPrimitive()) {
        return (T) converter.invoke(to, from);
      }
      return to.cast(converter.invoke(to, from));
    } catch (Exception e) {
      throw new RuntimeException("Cannot convert from " + from.getClass().getName() + " to " + to.getName()
          + ". Conversion failed with " + e.getMessage(), e);
    }
  }

  // Converters
  // ---------------------------------------------------------------------------------

  /**
   * Converts Integer to Boolean. If integer value is 0, then return FALSE, else
   * return TRUE.
   *
   * @param value
   *          The Integer to be converted.
   * @return The converted Boolean value.
   */
  public static Boolean integerToBoolean(Integer value) {
    return value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE;
  }

  /**
   * Converts Boolean to Integer. If boolean value is TRUE, then return 1, else
   * return 0.
   *
   * @param value
   *          The Boolean to be converted.
   * @return The converted Integer value.
   */
  public static Integer booleanToInteger(Boolean value) {
    return value.booleanValue() ? Integer.valueOf(1) : Integer.valueOf(0);
  }

  /**
   * Converts Double to BigDecimal.
   *
   * @param value
   *          The Double to be converted.
   * @return The converted BigDecimal value.
   */
  public static BigDecimal doubleToBigDecimal(Double value) {
    return new BigDecimal(value.doubleValue());
  }

  /**
   * Converts BigDecimal to Double.
   *
   * @param value
   *          The BigDecimal to be converted.
   * @return The converted Double value.
   */
  public static Double bigDecimalToDouble(BigDecimal value) {
    return new Double(value.doubleValue());
  }

  /**
   * Converts Integer to String.
   *
   * @param value
   *          The Integer to be converted.
   * @return The converted String value.
   */
  public static String integerToString(Integer value) {
    return value.toString();
  }

  /**
   * Converts String to Integer.
   *
   * @param value
   *          The String to be converted.
   * @return The converted Integer value.
   */
  public static Integer stringToInteger(String value) {
    return Integer.valueOf(value);
  }

  /**
   * Converts String to Long.
   *
   * @param value
   *          The String to be converted.
   * @return The converted Long value.
   */
  public static Long stringToLong(String value) {
    return Long.valueOf(value);
  }

  /**
   * Converts String to long.
   *
   * @param value
   *          The String to be converted.
   * @return The converted long value.
   */
  public static long stringToLongPrimitive(String value) {
    return stringToLong(value).longValue();
  }

  /**
   * Converts Boolean to String.
   *
   * @param value
   *          The Boolean to be converted.
   * @return The converted String value.
   */
  public static String booleanToString(Boolean value) {
    return value.toString();
  }

  /**
   * Converts String to Boolean.
   *
   * @param value
   *          The String to be converted.
   * @return The converted Boolean value.
   */
  public static Boolean stringToBoolean(String value) {
    return Boolean.valueOf(value);
  }

  /**
   * Converts Long to Integer.
   *
   * @param value
   *          The Long value to be convered.
   * @return Converted Integer value.
   */
  public static Integer longToInteger(Long value) {
    return value.intValue();
  }

  /**
   * Converts Double to Float.
   *
   * @param value
   *          The Double value to be convered.
   * @return Converted Float value.
   */
  public static Float doubleToFloat(Double value) {
    return value.floatValue();
  }

  /**
   * Converts String to Float.
   *
   * @param value
   *          The Float value to be convered.
   * @return Converted String value.
   */
  public static Float stringToFloat(String value) {
    return Float.parseFloat(value);

  }

  /**
   * Converts String to Float.
   *
   * @param value
   *          The Float value to be convered.
   * @return Converted String value.
   */
  public static Double stringToDouble(String value) {
    return Double.parseDouble(value);

  }

  /**
   * Converts Long to primitive.
   *
   * @param value
   *          The Long value to be convered.
   * @return Converted primitive value.
   */
  public static long longToPrimitive(Long value) {
    if (value == null) {
      return 0L;
    }
    return value.longValue();

  }

  /**
   * Converts Long to String.
   *
   * @param value
   *          The Long value to be converted.
   * @return Converted String value.
   */
  public static String longToString(Long value) {
    if (value == null) {
      return null;
    }
    return value.toString();
  }

  /**
   * Converts Double to String.
   *
   * @param value
   *          The Double value to be converted.
   * @return Converted String value.
   */
  public static String longToString(Double value) {
    if (value == null) {
      return null;
    }
    return value.toString();
  }

  /**
   * Converts Date to String.
   *
   * @param value
   *          The value to be converted.
   * @return Converted value.
   */
  public static String longToString(Date value) {
    if (value == null) {
      return null;
    }

    SimpleDateFormat sdf = new SimpleDateFormat();
    return sdf.format(value);
  }

  /**
   * Converts Integer to primitive.
   *
   * @param value
   *          The Integer value to be convered.
   * @return Converted primitive value.
   */
  public static int integerToPrimitive(Integer value) {
    if (value == null) {
      return 0;
    }
    return value.intValue();

  }

  /**
   * Converts Long to primitive.
   *
   * @param value
   *          The Long value to be convered.
   * @return Converted primitive value.
   */
  public static double doubleToPrimitive(Double value) {
    if (value == null) {
      return 0.0;
    }
    return value.doubleValue();

  }

  /**
   * Converts Float to primitive.
   *
   * @param value
   *          The Float value to be convered.
   * @return Converted primitive value.
   */
  public static double floatToPrimitive(Float value) {
    if (value == null) {
      return 0.0f;
    }
    return value.floatValue();

  }
}


/*
 * 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.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

import org.droitateddb.cursor.CombinedCursor;
import org.droitateddb.cursor.CombinedCursorImpl;
import org.droitateddb.entity.Entity;
import org.droitateddb.schema.AbstractAttribute;
import org.droitateddb.schema.EntityInfo;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * The {@link BaseContentProvider} is the base class of all generated {@link ContentProvider} for {@link Entity} classes.

 *

 * For each {@link Entity} which allows {@link ContentProvider} generation a separate {@link ContentProvider} will be generated. The generated
 * {@link ContentProvider} is also referenced in the AndroidManifest.xml to use an own Implementation remove the attribute
 * droitateddb:generated="true" in the provider element of the AndroidManifest.xml

 * The authority of the {@link ContentProvider} is therefore defined within the {@link Entity} annotation.

 *

 * The base {@link Uri} for calling the {@link ContentProvider} is build following this schema: content://[authority]/[
 * {@link BaseContentProvider#getEntityURIPart}].

 * If not overridden {@link BaseContentProvider#getEntityURIPart} returns entity

 *

 * For easier use the {@link BaseContentProvider} provides the methods {@link BaseContentProvider#uri(String)} and
 * {@link BaseContentProvider#uriForItem(String, long)}. These methods allow getting the {@link Uri} referencing the Provider with the table name of the
 * {@link Entity} and the primary key.

 *

 * {@link BaseContentProvider#uri(String)}: Returns a {@link Uri} for accessing multiple {@link Entity} elements.

 *

 * {@link BaseContentProvider#uriForItem(String, long)}: Returns a {@link Uri} for accessing a specific {@link Entity} element

 *
 * @author Falk Appel
 * @author Alexander Frank
 */

public abstract class BaseContentProvider extends ContentProvider {

	private static final int         MATCH_DIR  = 0;
	private static final int         MATCH_ITEM = 1;
	private static final String      PROTOCOL   = "content://";
	private static final UriRegistry REGISTRY   = new UriRegistry();

	private final String    contentUri;
	private final String    dirContentType;
	private final String    itemContentType;
	private       DbCreator dbCreator;

	private final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

	protected BaseContentProvider() {
		String authority = getAuthority();
		String base = getEntityURIPart();
		String typeDescription = "/vnd." + authority + "." + base;

		contentUri = PROTOCOL + authority + "/" + base;
		dirContentType = ContentResolver.CURSOR_DIR_BASE_TYPE + typeDescription;
		itemContentType = ContentResolver.CURSOR_ITEM_BASE_TYPE + typeDescription;

		uriMatcher.addURI(authority, base, MATCH_DIR);
		uriMatcher.addURI(authority, base + "/#", MATCH_ITEM);

		REGISTRY.add(getTableName(), contentUri);
	}

	/**
	 * Returns a {@link Uri} for the using it with a {@link ContentResolver} to access this {@link ContentProvider}. The {@link Uri} allows CRUD operations on
	 * multiple {@link Entity} elements.
	 *
	 * @param tableName Name of the Table (simple {@link Entity} name) the data should be retrieved from.
	 * @return Uri to access the tables data
	 */
	public static Uri uri(final String tableName) {
		return REGISTRY.getDictionaryUri(tableName);
	}

	/**
	 * Returns a {@link Uri} for the using it with a {@link ContentResolver} to access this {@link ContentProvider}. The {@link Uri} allows CRUD operations
	 * on a
	 * single {@link Entity} element, qualified by its primary key.
	 *
	 * @param tableName Name of the Table (simple {@link Entity} name) the data should be retrieved from.
	 * @param id        Primary key of the {@link Entity} to be accessed
	 * @return Uri to access the specific item in the table
	 */
	public static Uri uriForItem(final String tableName, final long id) {
		return REGISTRY.getItemUri(tableName, Long.toString(id));
	}

	/**
	 * Has to return the authority to be used for this {@link ContentProvider}.

	 * If generated this is the authority defined in the {@link Entity} class
	 *
	 * @return The authority used for the ContentProvider
	 */
	protected abstract String getAuthority();

	/**
	 * Has to return the attribute describing the primary key of the {@link Entity}.

	 * Id generated this is the {@link org.droitateddb.entity.PrimaryKey} annotated {@link org.droitateddb.entity.Column}.
	 *
	 * @return The description of the primary key of the table access by this ContentProvider
	 */
	protected abstract AbstractAttribute getIdAttribute();

	/**
	 * Has to return metadata of the {@link Entity} this {@link ContentProvider} is for.
	 *
	 * @return Metadata to the {@link Entity} being accessed
	 */
	protected abstract EntityInfo getEntityInfo();

	protected String getEntityURIPart() {
		return "entity";
	}

	private String getTableName() {
		return getEntityInfo().table();
	}

	private String getIdName() {
		return getIdAttribute().fieldName();
	}

	@Override
	public boolean onCreate() {
		dbCreator = DbCreator.getInstance(getContext());
		return true;
	}

	@Override
	public String getType(final Uri uri) {
		switch (uriMatcher.match(uri)) {
			case MATCH_DIR:
				return dirContentType;
			case MATCH_ITEM:
				return itemContentType;
			default:
				throw new UnsupportedOperationException("No type for Uri " + uri + " present");
		}
	}

	@Override
	public Uri insert(final Uri uri, final ContentValues values) {
		return dbCreator.functionOnDatabase(new DbFunction<Uri>() {
			@Override
			public Uri apply(SQLiteDatabase db) {
				switch (uriMatcher.match(uri)) {
					case MATCH_DIR:
						long id = db.insertWithOnConflict(getTableName(), null, values, SQLiteDatabase.CONFLICT_REPLACE);
						getContext().getContentResolver().notifyChange(uri, null);
						return Uri.parse(contentUri + "/" + id);
					default:
						throw new UnsupportedOperationException("Insert not allowed with specific note uri");
				}
			}
		});
	}

	@Override
	public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
		SQLiteDatabase db = dbCreator.getDatabaseConnection();
		SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
		builder.setTables(getTableName());
		switch (uriMatcher.match(uri)) {
			case MATCH_DIR:
				return wrap(builder.query(db, projection, selection, selectionArgs, null, null, sortOrder), uri);
			case MATCH_ITEM:
				int id = Integer.parseInt(uri.getLastPathSegment());
				builder.appendWhere(getIdName() + " = " + id);
				return wrap(builder.query(db, projection, selection, selectionArgs, null, null, sortOrder), uri);
			default:
				throw new UnsupportedOperationException("Unsupported query Uri " + uri);
		}
	}

	@Override
	public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
		return dbCreator.functionOnDatabase(new DbFunction<Integer>() {
			@Override
			public Integer apply(SQLiteDatabase db) {
				switch (uriMatcher.match(uri)) {
					case MATCH_DIR:
						return db.update(getTableName(), values, selection, selectionArgs);
					case MATCH_ITEM:
						String selectId = getIdName() + " = " + Integer.parseInt(uri.getLastPathSegment());
						return db.update(getTableName(), values, getEffectivSelection(selection, selectId), selectionArgs);
					default:
						throw new UnsupportedOperationException(
								"Update not supported for the given Uri + " + uri + ". Only single item updates are allowed right " +
										"now");
				}
			}
		});
	}

	@Override
	public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
		return dbCreator.functionOnDatabase(new DbFunction<Integer>() {
			@Override
			public Integer apply(SQLiteDatabase db) {
				switch (uriMatcher.match(uri)) {
					case MATCH_DIR:
						return db.delete(getTableName(), selection, selectionArgs);
					case MATCH_ITEM:
						String selectId = getIdName() + " = " + Integer.parseInt(uri.getLastPathSegment());
						return db.delete(getTableName(), getEffectivSelection(selection, selectId), selectionArgs);
					default:
						throw new UnsupportedOperationException(
								"Delete not supported for the given Uri + " + uri + ". Only single item deletes are allowed right now");
				}
			}
		});
	}

	private Cursor wrap(final Cursor cursor, final Uri uri) {
		try {
			EntityInfo entityInfo = getEntityInfo();
			CombinedCursor<?> magicCursor = CombinedCursorImpl.create(getContext(), cursor, entityInfo, Class.forName(entityInfo.className()));
			magicCursor.setNotificationUri(getContext().getContentResolver(), uri);
			return magicCursor;
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	private String getEffectivSelection(final String submitedSelection, final String idSelection) {
		String effectivSelection;
		if (submitedSelection == null || submitedSelection.equals("")) {
			effectivSelection = idSelection;
		} else {
			effectivSelection = submitedSelection + " AND " + idSelection;
		}
		return effectivSelection;
	}

	private static class UriRegistry {
		private final Map<String, String> registry = new ConcurrentHashMap<String, String>();

		public void add(final String tableName, final String uri) {
			registry.put(tableName, uri);
		}

		public Uri getDictionaryUri(final String tableName) {
			return Uri.parse(getRegisteredUri(tableName));
		}

		public Uri getItemUri(final String tableName, final String id) {
			return Uri.parse(getRegisteredUri(tableName) + "/" + id);
		}

		private String getRegisteredUri(final String tableName) {
			String uri = registry.get(tableName);
			if (uri == null) {
				throw new IllegalStateException("No ContentProvider Uri was registered for table " + tableName +
						". Did you forget to set \"contentProvider=true\" on the corresponding @Entity annotation?");
			}
			return uri;
		}
	}

}


/*
 * ====================================================================
 * 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.utilities;

import java.util.HashMap;
import java.util.Map;

/**
 * Maps exception error codes to exception messages.

 *

 *
 * The code structure is as follows:
 *
 *

 *
The error code is a six digit number

 *
The first two digits represent the error type

 *
The last four digits represent the specific error in that error type

 *

 *
 * Note: the last four digits may be divided into subtypes. In such case, the explanation of the
 * format will be included in the error type class descriptions below.

 *

 *
 * The error types are:
 *
 *

 *
00 -- Standard Java exceptions caused by malformed or invalid method parameters

 *
02 -- All other standard Java exceptions

 *
10 -- General JavaGit exceptions

 *
40-60 -- Command Specific JavaGit exceptions
 *

 *
400-401 -- git-add specific JavaGit exceptions

 *
402-403 -- git-bisect specific JavaGit exceptions

 *
404-405 -- git-branch specific JavaGit exceptions

 *
406-407 -- git-checkout specific JavaGit exceptions

 *
408-409 -- git-clone specific JavaGit exceptions

 *
410-411 -- git-commit specific JavaGit exceptions

 *
412-413 -- git-diff specific JavaGit exceptions

 *
414-415 -- git-fetch specific JavaGit exceptions

 *
416-417 -- git-grep specific JavaGit exceptions

 *
418-419 -- git-init specific JavaGit exceptions

 *
420-421 -- git-log specific JavaGit exceptions

 *
422-423 -- git-merge specific JavaGit exceptions

 *
424-425 -- git-mv specific JavaGit exceptions

 *
426-427 -- git-pull specific JavaGit exceptions

 *
428-429 -- git-push specific JavaGit exceptions

 *
430-431 -- git-rebase specific JavaGit exceptions

 *
432-433 -- git-reset specific JavaGit exceptions

 *
434-435 -- git-rm specific JavaGit exceptions

 *
436-437 -- git-show specific JavaGit exceptions

 *
438-439 -- git-status specific JavaGit exceptions

 *
440-441 -- git-tag specific JavaGit exceptions

 *
442-443 -- git-version specific JavaGit exceptions

 *

 *

 *

 *
 * How to use the codes and messages:
 *
 *

 *
All exceptions thrown from within javagit should contain a code and a message, even
 * exceptions thrown using standard Java exceptions.

 *
When creating a new exception code and message, start the message with the code like so:
 * "000001: "

 *
When throwing a JavaGitException, the code and the message must be supplied
 * to the constructor.

 *
When throwing a standard Java exception (ex. NullPointerException), just
 * supply the message since the code is already included in the message.

 *
The message retrieved from the ExceptionMessageMap can be treated like a base
 * message. If additional information is required in the message, append that information to the
 * base message.

 *
If the value of a variable must be included in the message, list the variable names and
 * their values at the end of the message in the following format: "{ varName1=[varVal1],
 * varName2=[varVal2], ... }"

 *

 *
 * TODO (jhl388): Load the exception message mapping from a properties bundle.
 */
public class ExceptionMessageMap {

  private static Map<String, String> MESSAGE_MAP;

  static {
    MESSAGE_MAP = new HashMap<String, String>();

    MESSAGE_MAP.put("000001", "000001: A String argument was not specified but is required.");
    MESSAGE_MAP.put("000002", "000002: A List<String> argument was not specified but is required.");
    MESSAGE_MAP.put("000003", "000003: An Object argument was not specified but is required.");
    MESSAGE_MAP.put("000004",
        "000004: The int argument is not greater than the lower bound (lowerBound < toCheck).");
    MESSAGE_MAP.put("000005",
        "000005: An List<?> argument was not specified or is empty but is required.");
    MESSAGE_MAP.put("000006",
        "000006: The int argument is outside the allowable range (start <= index < end).");
    MESSAGE_MAP.put("000007","000007: The argument should be a directory.");

    MESSAGE_MAP.put("000100", "000100: Invalid option combination for git-commit command.");
    MESSAGE_MAP.put("000110", "000110: Invalid option combination for git-add command.");
    MESSAGE_MAP.put("000120", "000120: Invalid option combination for git-branch command.");
    MESSAGE_MAP.put("000130", "000130: Invalid option combination for git-checkout command.");

    MESSAGE_MAP.put("020001", "020001: File or path does not exist.");
    MESSAGE_MAP.put("020002", "020002: File or path is not a directory.");

    MESSAGE_MAP.put("020100", "020100: Unable to start sub-process.");
    MESSAGE_MAP.put("020101", "020101: Error reading input from the sub-process.");

    MESSAGE_MAP.put("100000", "100000: Incorrect refType type.");
    MESSAGE_MAP.put("100001", "100001: Error retrieving git version.");
    MESSAGE_MAP.put("100002", "100002: Invalid path to git specified.");

    MESSAGE_MAP.put("401000", "401000: Error calling git-add.");
    MESSAGE_MAP.put("401001", "401001: Error fatal pathspec error while executing git-add.");

    MESSAGE_MAP.put("410000", "410000: Error calling git-commit.");

    MESSAGE_MAP.put("404000", "404000: Error calling git-branch. ");

    MESSAGE_MAP.put("424000", "424000: Error calling git-mv. ");

    MESSAGE_MAP.put("424001", "424001: Error calling git-mv for dry-run. ");

    MESSAGE_MAP.put("420001", "420001: Error calling git log");

    MESSAGE_MAP.put("432000", "432000: Error calling git-reset.");

    MESSAGE_MAP.put("418000", "418000: Error calling git init.");

    MESSAGE_MAP.put("434000", "434000: Error calling git-rm.");

    MESSAGE_MAP.put("406000", "406000: Error calling git-checkout");
    MESSAGE_MAP.put("406001", "406001: Error not a treeIsh RefType");

    MESSAGE_MAP.put("438000", "438000: Error calling git-status");

    MESSAGE_MAP.put("442001", "442001: No git, or wrong, major version number.");
    MESSAGE_MAP.put("442002", "442002: No git, or wrong, minor version number.");
    MESSAGE_MAP.put("442003", "442003: No git, or wrong, major release version number.");
    MESSAGE_MAP.put("442004", "442004: Wrong minor release version number.");
  }

  /**
   * Gets the error message for the specified code.
   *
   * @param code
   *          The error code for which to get the associated error message.
   * @return The error message for the specified code.
   */
  public static String getMessage(String code) {
    String str = MESSAGE_MAP.get(code);
    if (null == str) {
      return "NO MESSAGE FOR ERROR CODE. { code=[" + code + "] }";
    }
    return str;
  }

}


/*
 * ====================================================================
 * 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.api.Ref;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * A response data object for the git-reset command.
 */
public abstract class GitResetResponse implements CommandResponse {

  /*
   * The list of files left in a dirty state (different than what is in the new HEAD commit) in the
   * working tree.
   */
  protected List<File> filesNeedingUpdate = new ArrayList<File>();

  // If the --hard option was given, this is the SHA1 of the new head.
  protected Ref newHeadSha1 = null;

  // If the --hard option was given, this is the short message for the commit at the new head.
  protected String newHeadShortMessage = null;

  /**
   * Default constructor.
   */
  protected GitResetResponse() {
  }

  /**
   * Constructor that sets the SHA1 and short message of the new head commit.
   *
   * @param newHeadSha1
   *          The SHA1 of the new head commit.
   * @param newHeadShortMessage
   *          The short message of the new head commit.
   */
  protected GitResetResponse(Ref newHeadSha1, String newHeadShortMessage) {
    this.newHeadSha1 = newHeadSha1;
    this.newHeadShortMessage = newHeadShortMessage;
  }

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

    GitResetResponse grr = (GitResetResponse) o;

    if (!CheckUtilities.checkObjectsEqual(newHeadSha1, grr.getNewHeadSha1())) {
      return false;
    }

    if (!CheckUtilities.checkObjectsEqual(newHeadShortMessage, grr.getNewHeadShortMessage())) {
      return false;
    }

    if (!CheckUtilities.checkListsEqual(filesNeedingUpdate, grr.filesNeedingUpdate)) {
      return false;
    }

    return true;
  }

  /**
   * Gets the file at the specified index from the list of files needing update.
   *
   * @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 getFileNeedingUpdate(int index) {
    CheckUtilities.checkIntIndexInListRange(filesNeedingUpdate, index);
    return filesNeedingUpdate.get(index);
  }

  /**
   * Gets an Iterator over the list of files needing update.
   *
   * @return An Iterator over the list of files needing update.
   */
  public Iterator<File> getFilesNeedingUpdateIterator() {
    return (new ArrayList<File>(filesNeedingUpdate)).iterator();
  }

  /**
   * Gets the SHA1 of the new head commit. Only returned when the --hard option is
   * used.
   *
   * @return The SHA1 of the new head commit.
   */
  public Ref getNewHeadSha1() {
    return newHeadSha1;
  }

  /**
   * Gets the short message of the new head commit. Only returned when the --hard
   * option is used.
   *
   * @return The short message of the new head commit.
   */
  public String getNewHeadShortMessage() {
    return newHeadShortMessage;
  }

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

  @Override
  public int hashCode() {
    int ret = (null == newHeadSha1) ? 0 : newHeadSha1.hashCode();
    ret += (null == newHeadShortMessage) ? 0 : newHeadShortMessage.hashCode();
    for (File f : filesNeedingUpdate) {
      ret += f.hashCode();
    }
    return ret;
  }

  @Override
  public String toString() {
    StringBuffer buf = new StringBuffer();
    if (null != newHeadSha1) {
      buf.append("HEAD: ");
      buf.append(newHeadSha1);
      buf.append(" ");
      buf.append(newHeadShortMessage);
    }
    if (filesNeedingUpdate.size() > 0) {
      buf.append(filesNeedingUpdate);
    }
    return buf.toString();
  }

}


/*
 * ====================================================================
 * 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.GitStatusResponse;
import edu.nyu.cs.javagit.api.GitFileSystemObject.Status;

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

  /**
   * Constructor
   */
  public GitStatusResponseImpl(String repositoryPath) {
    super(repositoryPath);
  }

  /**
   * Sets the branch name in GitStatusResponse. NullPointerException
   * is thrown if branch is null;
   *
   * @param branch
   *          Ref of RefType.BRANCH.
   */
  public void setBranch(Ref branch) {
    this.branch = branch;
  }

  /**
   * Sets the error message in the response object.
   *
   * @param lineNumber
   *          Output line number where the error message appeared.
   * @param errorMsg
   *          String Error Message
   */
  public void setError(int lineNumber, String errorMsg) {
    errors.add(new ErrorDetails(lineNumber, errorMsg));
  }

  /**
   * Sets the String message in GitStatusResponse.
   * NullPointerException is thrown if message is null.
   *
   * @param message
   *          Output message saved from the <git-status> command.
   */
  public void setStatusOutputComment(String message) {
    this.message = message;
  }

  /**
   * Adds a file to list of files that are deleted and will be committed next time
   * <git-commit> is run.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToDeletedFilesToCommit(File file) {
    deletedFilesToCommit.add(file);
    fileToStatus.put(file, Status.DELETED_TO_COMMIT);
  }

  /**
   * Adds a file to the list of files that are deleted locally but not yet deleted from index using
   * <git-rm> command.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToDeletedFilesNotUpdated(File file) {
    deletedFilesNotUpdated.add(file);
    fileToStatus.put(file, Status.DELETED);
  }

  /**
   * Adds a file to list of files that are modified and will be committed next time
   * <git-commit> is run.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToModifiedFilesToCommit(File file) {
    modifiedFilesToCommit.add(file);
    fileToStatus.put(file, Status.MODIFIED_TO_COMMIT);
  }

  /**
   * Adds a file to the list of files that are modified files but not yet updated.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToModifiedFilesNotUpdated(File file) {
    modifiedFilesNotUpdated.add(file);
    fileToStatus.put(file, Status.MODIFIED);
  }

  /**
   * Adds a file to the list of new files that are ready to be committed next time <git-commit>
   * command is run.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToNewFilesToCommit(File file) {
    newFilesToCommit.add(file);
    fileToStatus.put(file, Status.NEW_TO_COMMIT);
  }

  /**
   * Adds a file to the list of renamed files that are ready to be committed next time <git-commit>
   * command is run.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToRenamedFilesToCommit(File file) {
    renamedFilesToCommit.add(file);
    fileToStatus.put(file, Status.RENAMED_TO_COMMIT);
  }

  /**
   * Adds a file to list of files that have been added locally but not yet added to the index.
   *
   * @param file
   *          File to be added to the list.
   */
  public void addToUntrackedFiles(File file) {
    untrackedFiles.add(file);
    fileToStatus.put(file, Status.UNTRACKED);
  }
}


package org.ucmtwine.parameter;

import intradoc.data.DataBinder;
import intradoc.data.DataResultSet;
import intradoc.data.ResultSet;
import intradoc.provider.Provider;
import intradoc.server.Service;

import java.util.Date;

import net.balusc.util.ObjectConverter;

import org.ucmtwine.parameter.types.BooleanParameter;
import org.ucmtwine.parameter.types.DateParameter;
import org.ucmtwine.parameter.types.DoubleParameter;
import org.ucmtwine.parameter.types.FloatParameter;
import org.ucmtwine.parameter.types.InjectedParameter;
import org.ucmtwine.parameter.types.IntegerParameter;
import org.ucmtwine.parameter.types.LongParameter;
import org.ucmtwine.parameter.types.ProviderParameter;
import org.ucmtwine.parameter.types.ResultSetParameter;
import org.ucmtwine.parameter.types.StringParameter;

/**
 * Encapsulates a binder parameter, taking the legwork out of enforcing type and
 * mandatory requirements.
 *
 * @author tim
 */
public abstract class Parameter implements IParameter {

  public static final int GRAMMAR_ELEMENT_UNSPECIFIED = -1;

  protected String name;
  protected boolean required = true;

  /**
   * The actual type (may be primitive, non nullable etc)
   */
  protected Class<?> type;

  protected Parameter() {
    this.name = "";
  }

  protected Parameter(Class<?> type) {
    this.type = type;
    this.name = "";
  }

  /**
   * Initialise a basic named binder variable.
   *
   * @param name
   */
  protected Parameter(String name, Class<?> type) {
    this.name = name;
    this.type = type;
  }

  /**
   * Shortcut to make a named String parameter.
   *
   * @param name
   * @return
   */
  public static Parameter create(String name) {
    return create(name, String.class, true);
  }

  /**
   * Create an un-named, required, parameter.
   *
   * @param type
   * @return
   */
  public static Parameter create(Class<?> type) {
    return create("", type, true);
  }

  /**
   * Factory method to create the concrete variable type.
   *
   * @param name
   *          The name in the binder of the variable.
   * @return
   */
  public static Parameter create(String name, Class<?> type, boolean required) throws IllegalArgumentException {

    if (InjectedParameter.isValidType(type)) {
      return new InjectedParameter(name, type);
    }

    if (type.isPrimitive() && !required) {
      String msg = "Parameter [" + name + "] found with non-nullable type. Use a wrapper type or change to required";
      throw new IllegalArgumentException(msg);
    }

    Parameter p;

    if (type == String.class) {
      p = new StringParameter(name, type);

    } else if (type == Integer.class || type == int.class) {
      p = new IntegerParameter(name, type);

    } else if (type == Long.class || type == long.class) {
      p = new LongParameter(name, type);

    } else if (type == Float.class || type == float.class) {
      p = new FloatParameter(name, type);

    } else if (type == Double.class || type == double.class) {
      p = new DoubleParameter(name, type);

    } else if (type == Date.class) {
      p = new DateParameter(name, type);

    } else if (type == ResultSet.class || type == DataResultSet.class) {
      p = new ResultSetParameter(name, type);

    } else if (type == Boolean.class || type == boolean.class) {
      p = new BooleanParameter(name, type);

    } else if (type == Provider.class) {
      p = new ProviderParameter(name);
    } else {
      throw new IllegalArgumentException("Parameter type " + type.getName() + " is not valid");
    }

    p.setRequired(required);

    return p;
  }

  /**
   * Get variable name.
   *
   * @return
   */
  public String getName() {
    return name;
  }

  /**
   * Set variable name.
   *
   * @param name
   */
  public void setName(String name) {
    this.name = name;
  }

  public boolean isRequired() {
    return required;
  }

  public void setRequired(boolean optional) {
    this.required = optional;
  }

  /**
   * Get the string value from binder.
   */
  public String getStringValue(DataBinder binder) {
    // binder can't get a non existent param
    if (this.name == null || this.name.equals("")) {
      return null;
    }

    String value = (String) binder.getLocal(this.name);

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

    return value;
  }

  /**
   * {@inheritDoc}
   */
  abstract public Object getBinderValue(Service service) throws IllegalAccessException;

  /**
   * {@inheritDoc}
   */
  public Object getArgumentValue(Object object, Service service) throws ClassCastException {
    return ObjectConverter.convert(object, type);
  }

  /**
   * {@inheritDoc}
   */
  public String toActionString() {
    return this.getType().getName() + "," + this.getName() + "," + String.valueOf(this.isRequired());
  }

  /**
   * Based on an input string, determines if the required flag is true.
   *
   * @param requiredString
   *          A string containing a boolean value or "required".
   *
   * @return A boolean representing the mandatory state of the binder variable
   */
  public static boolean parseRequiredString(String requiredString) {
    return Boolean.parseBoolean(requiredString) || requiredString.equalsIgnoreCase("required");
  }

  /**
   * Returns the actual type given a type string.
   *
   * @return A java type, if valid
   */
  public Class<?> getType() {
    return this.type;
  }
}