/*******************************************************************************
 * Copyright 2016, 2018 vanilladb.org contributors
 *
 * 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.vanilladb.bench.benchmarks.tpcc;

import java.util.Random;

/** A TPC-C random generator. */
public class TpccValueGenerator {
	public static final int NU_CLAST_LOAD = 0, NU_CLAST_RUN = 1, NU_CID = 2, NU_OLIID = 3;
	private static final String CHARSET = new String("QAa0bcLdUK2eHfJgTP8XhiFj61DOklNm9nBoI5pGqYVrs3CtSuMZvwWx4yE7zR");
	private static final String TOKENS[] = { "BAR", "OUGHT", "ABLE", "PRI", "PRES", "ESE", "ANTI", "CALLY", "ATION",
			"EING", };

	private Random rng = new Random();
	private NURandGenerator nug = new NURandGenerator();

	public static void main(String[] args) {
		TpccValueGenerator ranValGen = new TpccValueGenerator(100);

		System.out.println(ranValGen.nextDouble());
		System.out.println(ranValGen.nstring(10));
		System.out.println(ranValGen.randomAString(10));
		System.out.println(ranValGen.fixedDecimalNumber(10, 0.1, 1.0));

		ranValGen = new TpccValueGenerator(100);

		System.out.println(ranValGen.nextDouble());
		System.out.println(ranValGen.nstring(10));
		System.out.println(ranValGen.randomAString(10));
		System.out.println(ranValGen.fixedDecimalNumber(10, 0.1, 1.0));
	}

	public TpccValueGenerator() {
	}

	public TpccValueGenerator(long seed) {
		rng = new Random(seed);
		nug = new NURandGenerator();
	}

	public Random rng() {
		return (rng);
	}

	/**
	 * Return an integer in the (inclusive) range [min, max].
	 *
	 * @param min
	 * @param max
	 * @return
	 */
	public int number(int min, int max) {
		if (min > max)
			throw new IllegalArgumentException();
		int value = rng.nextInt(max - min + 1);
		value += min;
		return value;
	}

	/**
	 * Return the result of a random choose from a given distribution.
	 *
	 * @param probs
	 * @return
	 */
	public int randomChooseFromDistribution(double... probs) {
		int result = -1;
		int[] range = new int[probs.length];
		double accuracy = 1000;
		int total = 0;

		for (int i = 0; i < probs.length; i++) {
			range[i] = (int) (probs[i] * accuracy);
			total += range[i];
		}

		int randNum = ((int) (rng.nextDouble() * total)) % total;
		for (int i = 0; i < range.length; i++) {
			randNum -= range[i];
			if (randNum < 0) {
				result = i;
				break;
			}
		}
		return result;
	}

	public double nextDouble() {
		return rng.nextDouble();
	}

	/**
	 * Return an integer in the (inclusive) range [minimum, maximum] excluding
	 * exclusivedVal.
	 */
	public int numberExcluding(int min, int max, int exclusivedVal) {
		if (min > max)
			throw new IllegalArgumentException();
		if (min > exclusivedVal || exclusivedVal > max)
			throw new IllegalArgumentException();
		int value = number(min, max - 1);
		if (value >= exclusivedVal)
			value++;
		return value;
	}

	/**
	 * Return an fixed decimal double value in the (inclusive) range [minimum,
	 * maximum]. For example, [0.01 .. 100.00] with decimal 2 has 10,000 unique
	 * values.
	 *
	 */
	public double fixedDecimalNumber(int decimal, double min, double max) {
		if (min > max)
			throw new IllegalArgumentException();
		if (decimal < 0)
			throw new IllegalArgumentException();
		int multiplier = 1;
		for (int i = 0; i < decimal; ++i) {
			multiplier *= 10;
		}
		int top = (int) (min * multiplier);
		int bottom = (int) (max * multiplier);
		return (double) number(top, bottom) / (double) multiplier;
	}

	/** Return a last name as defined by TPC-C 4.3.2.3. */
	public String makeLastName(int number) {
		if (number < 0 && number > TpccConstants.NUM_DISTINCT_CLAST - 1)
			throw new IllegalArgumentException();
		int indicies[] = { number / 100, (number / 10) % 10, number % 10 };
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < indicies.length; ++i) {
			sb.append(TOKENS[indicies[i]]);
		}
		return sb.toString();
	}

	public String makeRandomLastName(boolean isForLoad) {
		int i;
		if (isForLoad)
			i = NURand(NU_CLAST_LOAD, 0, TpccConstants.NUM_DISTINCT_CLAST - 1);
		else
			i = NURand(NU_CLAST_RUN, 0, TpccConstants.NUM_DISTINCT_CLAST - 1);
		return makeLastName(i);
	}

	/**
	 * Return a string of random alphanumeric characters of a random length
	 * between [minLength, maxLength].
	 */
	public String randomAString(int minLength, int maxLength) {
		int length = number(minLength, maxLength);
		return randomAString(length);
	}

	public String randomAString(int length) {
		StringBuffer sb = new StringBuffer();
		int te = 0;
		for (int i = 1; i <= length; i++) {
			te = rng().nextInt(62);
			sb.append(CHARSET.charAt(te));
		}
		return sb.toString();
	}

	/**
	 *
	 * @param minimum_length
	 * @param maximum_length
	 * @return a random numeric string with length in range [minimum_length,
	 *         maximum_length].
	 */
	public String nstring(int minimum_length, int maximum_length) {
		return randomString(minimum_length, maximum_length, '0', 10);
	}

	public String nstring(int length) {
		return randomString(length, '0', 10);
	}

	public String randomZipCode() {
		StringBuffer sb = new StringBuffer();
		sb.append(nstring(4));
		sb.append("11111");
		return sb.toString();
	}

	private String randomString(int minimum_length, int maximum_length, char base, int numCharacters) {
		int length = number(minimum_length, maximum_length);
		return randomString(length, base, numCharacters);
	}

	private String randomString(int length, char base, int numCharacters) {
		byte baseByte = (byte) base;
		byte[] bytes = new byte[length];
		for (int i = 0; i < length; ++i) {
			bytes[i] = (byte) (baseByte + number(0, numCharacters - 1));
		}
		return new String(bytes);
	}

	public int NURand(int type, int min, int max) {
		return nug.NURand(type, min, max);
	}

	public class NURandGenerator {
		private final int aForCLast;
		private final int aForCId;
		private final int aForOrderLineIId;
		private int cLoadForCLast;
		private int cRunForCLast;
		private int cForCId;
		private int cForOrderLineIId;

		public NURandGenerator() {
			aForCLast = (int) (TpccConstants.NUM_DISTINCT_CLAST * ((double) 255 / 1000));
			aForCId = (int) (TpccConstants.CUSTOMERS_PER_DISTRICT * ((double) 1023 / 3000));
			aForOrderLineIId = (int) (TpccConstants.NUM_ITEMS * ((double) 8191 / 100000));
			generateC();
		}

		public void setCLoadForCLast(int cLoad) {
			cLoadForCLast = cLoad;
		}

		public void setCRunForCLast(int cRun) {
			cRunForCLast = cRun;
		}

		public void setCForCId(int c) {
			cForCId = c;
		}

		public void setCForOrderLineIId(int c) {
			cForOrderLineIId = c;
		}

		public int NURand(int type, int min, int max) {
			if (min > max)
				throw new IllegalArgumentException();
			int c, a;
			switch (type) {
			case NU_CLAST_LOAD:
				a = aForCLast;
				c = cLoadForCLast;
				break;
			case NU_CLAST_RUN:
				a = aForCLast;
				c = cRunForCLast;
				break;
			case NU_CID:
				a = aForCId;
				c = cForCId;
				break;
			case NU_OLIID:
				a = aForOrderLineIId;
				c = cForOrderLineIId;
				break;
			default:
				throw new IllegalArgumentException();
			}

			return (((number(0, a) | number(min, max)) + c) % (max - min + 1)) + min;
		}

		public String toString() {
			return "NURand with aForCLast = " + aForCLast + ", aForCId = " + aForCId + ", aForOrderLineIId = "
					+ aForOrderLineIId + ", cLoadForCLast = " + cLoadForCLast + ", cRunForCLast = " + cRunForCLast
					+ ", cForCId = " + cForCId + ", cForOrderLineIId=" + cForOrderLineIId;
		}

		private void generateC() {
			cForCId = number(0, aForCId);
			cForOrderLineIId = number(0, aForOrderLineIId);
			if (TpccConstants.CUSTOMERS_PER_DISTRICT < 1000) {
				cLoadForCLast = 91;
				cRunForCLast = 21;
			} else {
				cLoadForCLast = number(0, aForCLast);
				cRunForCLast = number(0, aForCLast);
				while (!isValidCRun())
					cRunForCLast = number(0, aForCLast);
			}
		}

		private boolean isValidCRun() {
			int cDelta = Math.abs(cRunForCLast - cLoadForCLast);
			return 65 <= cDelta && cDelta <= 119 && cDelta != 96 && cDelta != 112;
		}

	}

}


/*******************************************************************************
 * Copyright 2016, 2017 vanilladb.org contributors
 *
 * 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.vanilladb.bench.util;

import java.util.Random;

/**
 * A thread-safe random value generator.
 *
 * @author SLMT
 *
 */
public class RandomValueGenerator {

	private static final String CHARSET = new String(
			"QAa0bcLdUK2eHfJgTP8XhiFj61DOklNm9nBoI5pGqYVrs3CtSuMZvwWx4yE7zR");

	private Random rng;

	public RandomValueGenerator() {
		rng = new Random();
	}

	public RandomValueGenerator(long seed) {
		rng = new Random(seed);
	}

	public Random rng() {
		return (rng);
	}

	/**
	 * Return the result of a random choose from a given distribution.
	 *
	 * @param probs
	 * @return
	 */
	public int randomChooseFromDistribution(double... probs) {
		int result = -1;
		int[] range = new int[probs.length];
		double accuracy = 1000;
		int total = 0;

		for (int i = 0; i < probs.length; i++) {
			range[i] = (int) (probs[i] * accuracy);
			total += range[i];
		}

		int randNum = (int) (rng.nextDouble() * total);
		for (int i = 0; i < range.length; i++) {
			randNum -= range[i];
			if (randNum <= 0) {
				result = i;
				break;
			}
		}
		return result;
	}

	/**
	 * Return an integer in the (inclusive) range [min, max].
	 */
	public int number(int min, int max) {
		if (min > max)
			throw new IllegalArgumentException();
		int value = rng.nextInt(max - min + 1);
		value += min;
		return value;
	}

	/**
	 * Return a long in the (inclusive) range [min, max].
	 */
	public long randomLongRange(long min, long max) {

		if (max <= min)
			return min;

		long width = max - min;
		return (long) (rng.nextDouble() * width) + min;
	}

	/**
	 * Return a double in the (inclusive) range [min, max], with the increase
	 * precision.
	 */
	public double randomDoubleIncrRange(double min, double max, double incr) {

		long width = (long) ((max - min) / incr);
		return randomLongRange(0, width) * incr + min;
	}

	/**
	 * Return an integer in the (inclusive) range [minimum, maximum] excluding
	 * exclusivedVal.
	 */
	public int numberExcluding(int min, int max, int exclusivedVal) {
		if (min > max)
			throw new IllegalArgumentException();
		if (min > exclusivedVal || exclusivedVal > max)
			throw new IllegalArgumentException();
		int value = number(min, max - 1);
		if (value >= exclusivedVal)
			value++;
		return value;
	}

	/**
	 * Return an fixed decimal double value in the (inclusive) range [minimum,
	 * maximum]. For example, [0.01 .. 100.00] with decimal 2 has 10,000 unique
	 * values.
	 *
	 */
	public double fixedDecimalNumber(int decimal, double min, double max) {
		if (min > max)
			throw new IllegalArgumentException();
		if (decimal < 0)
			throw new IllegalArgumentException();
		int multiplier = 1;
		for (int i = 0; i < decimal; ++i) {
			multiplier *= 10;
		}
		int top = (int) (min * multiplier);
		int bottom = (int) (max * multiplier);
		return (double) number(top, bottom) / (double) multiplier;
	}

	/**
	 * Return a string of random alphanumeric characters of a random length
	 * between [minLength, maxLength].
	 */
	public String randomAString(int minLength, int maxLength) {
		int length = number(minLength, maxLength);
		return randomAString(length);
	}

	public String randomAString(int length) {
		StringBuffer sb = new StringBuffer();
		int te = 0;
		for (int i = 1; i <= length; i++) {
			te = rng().nextInt(62);
			sb.append(CHARSET.charAt(te));
		}
		return sb.toString();
	}

	/**
	 * @return a random numeric string with length in range [minimum_length,
	 *          maximum_length].
	 */
	public String nstring(int minimum_length, int maximum_length) {
		return randomString(minimum_length, maximum_length, '0', 10);
	}

	public String nstring(int length) {
		return randomString(length, '0', 10);
	}

	public String randomZipCode() {
		StringBuffer sb = new StringBuffer();
		sb.append(nstring(4));
		sb.append("11111");
		return sb.toString();
	}

	private String randomString(int minimum_length, int maximum_length,
			char base, int numCharacters) {
		int length = number(minimum_length, maximum_length);
		return randomString(length, base, numCharacters);
	}

	private String randomString(int length, char base, int numCharacters) {
		byte baseByte = (byte) base;
		byte[] bytes = new byte[length];
		for (int i = 0; i < length; ++i) {
			bytes[i] = (byte) (baseByte + number(0, numCharacters - 1));
		}
		return new String(bytes);
	}
}


package org.ucmtwine.proxy.injector;

import intradoc.data.DataException;
import intradoc.shared.PluginFilterData;
import intradoc.shared.PluginFilters;

import java.lang.reflect.Method;
import java.net.URL;
import java.util.Vector;

import org.ucmtwine.annotation.Filter;
import org.ucmtwine.proxy.FilterProxy;

/**
 * Injects classes as UCM filters. (This filter is itself a filter, but should
 * not be annotated nor injected using itself)
 *
 * @author tim
 */
public class FilterInjector extends BaseInjector implements IClassInjector {

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

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

    Method[] classMethods = klass.getMethods();

    for (Method method : classMethods) {
      Filter annotation = (Filter) method.getAnnotation(Filter.class);

      if (annotation != null) {
        injectFilterMethod(method, annotation);
      }
    }
  }

  /**
   *
   * @param method
   * @param annotation
   * @throws DataException
   */
  private void injectFilterMethod(Method method, Filter annotation) throws DataException {

    if (annotation == null) {
      throw new DataException("Method [" + method.getName() + "] is not an injectable filter.");
    }

    // TODO: is this necessary?
    if (method.getReturnType() != int.class && method.getReturnType() != void.class) {
      throw new DataException("Method [" + method.getName()
          + "] must have a return type of int or void to be a filter.");
    }

    String methodID = MethodRegistry.addMethod(method);

    if (methodID == null) {
      throw new DataException("Could not generate UUID for method " + method.getName());
    }

    Vector<PluginFilterData> filters = new Vector<PluginFilterData>();

    PluginFilterData filter = new PluginFilterData();

    filter.m_order = annotation.loadOrder();
    filter.m_parameter = methodID;
    filter.m_filterType = annotation.event();
    filter.m_location = FilterProxy.class.getName();

    filters.add(filter);

    PluginFilters.registerFilters(filters);
  }
}


/*
 * ====================================================================
 * 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.io.File;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;

import edu.nyu.cs.javagit.api.WorkingTree;
import edu.nyu.cs.javagit.api.commands.GitAdd;
import edu.nyu.cs.javagit.api.commands.GitAddResponse;
import edu.nyu.cs.javagit.api.commands.GitCommit;
import edu.nyu.cs.javagit.api.commands.GitCommitResponse;
import edu.nyu.cs.javagit.api.commands.GitMv;
import edu.nyu.cs.javagit.api.commands.GitMvResponse;
import edu.nyu.cs.javagit.api.commands.GitRm;
import edu.nyu.cs.javagit.api.commands.GitRmResponse;
import edu.nyu.cs.javagit.utilities.CheckUtilities;

/**
 * GitFileSystemObject provides some implementation shared by files and directories
 */

// TODO (rs2705): Alphabetize the methods in this class
public abstract class GitFileSystemObject {

  public static enum Status {
    // untracked (created but not added to the repository)
    UNTRACKED,
    // new, waiting to commit
    NEW_TO_COMMIT,
    // in repository and deleted locally
    DELETED,
    // deleted, waiting to commit
    DELETED_TO_COMMIT,
    // changed locally, but not updated
    MODIFIED,
    // changed and added to the index
    MODIFIED_TO_COMMIT,
    // renamed, waiting to commit
    RENAMED_TO_COMMIT,
    // in repository
    IN_REPOSITORY
  }

  /**
   * file path, as specified by the user
   */
  protected File file;
  /**
   * path, relative to working directory; used to pass around data to command API
   */
  protected File relativePath;

  protected WorkingTree workingTree;

  /**
   * The constructor.
   *
   * @param file
   *          underlying java.io.File object
   */
  protected GitFileSystemObject(File file, WorkingTree workingTree) throws JavaGitException {
    this.workingTree = workingTree;
    this.file = file;
    this.relativePath = getRelativePath(file, workingTree.getPath());
  }

  /**
   * Returns a file, with path relative to git working tree
   *
   * @param in
   *          input File object
   *        repositoryPath
   *          path to git repository
   * @return
   *        File object with relative path
   * @throws JavaGitException
   *         input file does not belong to git working tree/ repo
   */
  public static File getRelativePath(File in, File repositoryPath) throws JavaGitException {
    String path = in.getPath();
    String absolutePath = in.getAbsolutePath();

    //check if the path is relative or absolute
    if(path.equals(absolutePath)) {
      //if absolute, make sure it belongs to working tree
      String workingTreePath = repositoryPath.getAbsolutePath();
      if(!path.startsWith(workingTreePath)) {
        throw new JavaGitException(999, "Invalid path :" + path
            + ". Does not belong to the git working tree/ repository: " + workingTreePath);
      }

      //make path relative
      if(!path.equals(workingTreePath)) {
        path = path.substring(workingTreePath.length()+1);
      }
    }

    return new File(path);
  }

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

    GitFileSystemObject gitObj = (GitFileSystemObject) obj;
    return CheckUtilities.checkObjectsEqual(gitObj.getFile(), file);
  }

  /**
   * Gets the name of the file system object
   *
   * @return The name
   */
  public String getName() {
    return file.getName();
  }

  /**
   * Gets the underlying java.io.File object
   *
   * @return java.io.File object
   */
  public File getFile() {
    return file;
  }

  /**
   * Gets parent directory of this GitFileSystemObject object
   *
   * @return parent directory (null if invalid)
   *
   */
  public GitDirectory getParent() {
    // NOTE: file.getParentFile() returns null if there is no parent.
    if(file.getParentFile() == null) {
      return null;
    }

    try {
      return new GitDirectory(file.getParentFile(), workingTree);
    }
    catch(JavaGitException e) {
      //invalid git parent
      return null;
    }
  }

  /**
   * Adds the object to the git index
   *
   * @return response from git add
   */
  public GitAddResponse add() throws IOException, JavaGitException {
    GitAdd gitAdd = new GitAdd();

    // create a list of filenames and add yourself to it
    List<File> list = new ArrayList<File>();
    File relativeFilePath;
    if(relativePath.isDirectory()){
    	for(File f : relativePath.listFiles()){
    		if(!f.isHidden() && !f.getName().startsWith(".")){
    			relativeFilePath = this.getRelativePath(f, this.getWorkingTree().getPath());
    			list.add(relativeFilePath );
    		}
    	}
    }
    else{

    	list.add(relativePath);
    }
    // run git-add command
    return gitAdd.add(workingTree.getPath(), null, list);
  }

  /**
   * Commits the file system object
   *
   * @param comment
   *          Developer's comment
   *
   * @return response from git commit
   */
  public GitCommitResponse commit(String comment) throws IOException, JavaGitException {
    // first add the file
    add();

    // create a list of filenames and add yourself to it
    List<File> list = new ArrayList<File>();
    list.add(relativePath);

    GitCommit gitCommit = new GitCommit();
    return gitCommit.commitOnly(workingTree.getPath(), comment, list);
  }

  /**
   * Moves or renames the object
   *
   * @param dest
   *          destination path (relative to the Git Repository)
   *
   * @return response from git mv
   */
  public GitMvResponse mv(File dest) throws IOException, JavaGitException {
    // source; current location (relative)
    File source = relativePath;
    //get relative path for destination
    File relativeDest = getRelativePath(dest, workingTree.getPath());

    // perform git-mv
    GitMv gitMv = new GitMv();
    GitMvResponse response = gitMv.mv(workingTree.getPath(), source, relativeDest);

    // file has changed; update
    file = dest;
    relativePath = relativeDest;

    return response;
  }

  /**
   * Removes the file system object from the working tree and the index
   *
   * @return response from git rm
   */
  public GitRmResponse rm() throws IOException, JavaGitException {
    GitRm gitRm = new GitRm();

    // run git rm command
    return gitRm.rm(workingTree.getPath(), relativePath);
  }

  /**
   * Checks out some earlier version of the object
   *
   * @param sha1
   *          Commit id
   */
  public void checkout(String sha1) throws JavaGitException {
    // GitCheckout.checkout(path, sha1);
  }

  /**
   * Show differences between current file system object and index version of it
   *
   * @return diff between working directory and git index
   */
  public Diff diff() throws JavaGitException {
    // GitLog.log(path);
    return null;
  }

  /**
   * Show differences between current file system object and some commit
   *
   * @param commit
   *          Git commit to compare with
   *
   * @return diff between working directory and a given git commit
   */
  public Diff diff(Commit commit) throws JavaGitException {
    // GitLog.log(path);
    return null;
  }

  /**
   * Return the WorkingTree this object is in
   *
   * @return working tree
   */
  public WorkingTree getWorkingTree() {
    return workingTree;
  }
}


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

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

import edu.nyu.cs.javagit.api.JavaGitException;
import edu.nyu.cs.javagit.client.ClientManager;
import edu.nyu.cs.javagit.client.IClient;
import edu.nyu.cs.javagit.client.IGitStatus;
import edu.nyu.cs.javagit.utilities.CheckUtilities;
import edu.nyu.cs.javagit.api.GitFileSystemObject;
import edu.nyu.cs.javagit.api.GitFileSystemObject.Status;

/**
 * GitStatus provides an API to status of a git repository.
 */
public final class GitStatus {

  /**
   * It returns a GitStatusResponse object that contains all the details of the
   * output of <git-status> command.
   *
   * @param repositoryPath
   *          Directory pointing to the root of the repository.
   * @param options
   *          Options that are passed to <git-status> command.
   * @param paths
   *          List of paths or patterns
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null or if options or paths are invalid.
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse status(File repositoryPath, GitStatusOptions options, List<File> paths)
      throws JavaGitException, IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.status(repositoryPath, options, paths);
  }

  /**
   * It returns a GitStatusResonse object that contains all the details of the output
   * of <git-status> command. It has no options passed as parameter to the method.
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @param paths
   *          List of paths or file patterns.
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null or if options or paths are invalid.
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse status(File repositoryPath, List<File> paths) throws JavaGitException,
      IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.status(repositoryPath, paths);
  }

  /**
   * It returns a GitStatusResonse object that contains all the details of the output
   * of <git-status> command. It has no path passed as parameter to the method.
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @param options
   *          Options that are passed to <git-status> command.
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null or if options or paths are invalid.
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse status(File repositoryPath, GitStatusOptions options)
      throws JavaGitException, IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.status(repositoryPath, options);
  }

  /**
   * It returns a GitStatusResonse object that contains all the details of the output
   * of <git-status> command. Instead of passing a list of paths, this method takes a
   * String argument to a file-path.
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @param options
   *          Options that are passed to <git-status> command.
   * @param file
   *          Filename or directory
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null or if options or paths are invalid.
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse status(File repositoryPath, GitStatusOptions options, File file)
      throws JavaGitException, IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    CheckUtilities.checkFileValidity(file);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.status(repositoryPath, options, file);
  }

  /**
   * It returns a GitStatusResonse object that contains all the details of the output
   * of <git-status> command. It does not pass any options or file paths. This is the most
   * generic execution of <git-status> command.
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null or if options or paths are invalid.
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse status(File repositoryPath) throws JavaGitException, IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.status(repositoryPath);
  }

  /**
   * It returns a GitStatusResonse object that contains all the details of the output
   * of <git-status> command. It is equivalent of executing <git-status> command with
   * '-a' option.
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null or if options or paths are invalid.
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse statusAll(File repositoryPath) throws JavaGitException, IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.statusAll(repositoryPath);
  }

  /**
   * It returns a GitStatusResonse object that contains all the details of the output
   * of <git-status> command, but filters output for a single file
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @param path
   * @return GitStatusResponse object
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitStatusResponse getSingleFileStatus(File repositoryPath, File path) throws JavaGitException, IOException {
    CheckUtilities.checkFileValidity(repositoryPath);
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    return gitStatus.getSingleFileStatus(repositoryPath, null, path);
  }

  /**
   * It returns a GitFileSystemObject.Status for a single file
   *
   * @param repositoryPath
   *          Directory path to the root of the repository.
   * @param path
   * @return GitFileSystemObject.Status
   * @throws JavaGitException
   *           Exception thrown if the repositoryPath is null
   * @throws IOException
   *           Exception is thrown if any of the IO operations fail.
   */
  public GitFileSystemObject.Status getFileStatus(File repositoryPath, File path) throws JavaGitException, IOException {
    //check validity of a repository path
    CheckUtilities.checkFileValidity(repositoryPath);

    //run git status
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitStatus gitStatus = client.getGitStatusInstance();
    GitStatusResponse response = gitStatus.status(repositoryPath);

    return response.getFileStatus(path);
    /*
     * TODO: quote from Michael Schidlowsky: "this block of if statements is a little smelly... I'd
     * prefer to see something like return response.asStatus()...
     */
    /*
    if (response.getUntrackedFilesSize() > 0) {
      return Status.UNTRACKED;
    }

    if (response.getNewFilesToCommitSize() > 0) {
      return Status.NEW_TO_COMMIT;
    }

    if (response.getDeletedFilesNotUpdatedSize() > 0) {
      return Status.DELETED;
    }

    if (response.getDeletedFilesToCommitSize() > 0) {
      return Status.DELETED_TO_COMMIT;
    }

    if (response.getModifiedFilesNotUpdatedSize() > 0) {
      return Status.MODIFIED;
    }

    if (response.getModifiedFilesToCommitSize() > 0) {
      return Status.MODIFIED_TO_COMMIT;
    }

    // default
    return Status.IN_REPOSITORY;
    */
  }
}


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

/**
 * A class for managing options and passing these options to <git-status> command.
 *
 * The <git-status> command takes the same set of options as <git-commit> it shows what
 * would be committed if the same options are given to git-commit.
 */

public final class GitStatusOptions {

  private boolean optQuiet = false;
  private boolean optVerbose = false;
  private boolean optSignOff = false;
  private boolean optEdit = false;
  private boolean optAll = false;
  private boolean optInclude = false;
  private boolean optOnly = false;
  private boolean optNoVerify = false;
  private boolean optUntrackedFiles = false;
  private boolean optAllowEmpty = false;
  private File optReadFromLogFile = null;
  private String author = null;

  /**
   * Returns true if the quiet (-q) option is set.
   *
   * @return optQuite
   */
  public boolean isOptQuiet() {
    return optQuiet;
  }

  /**
   * Sets the quiet(-q) option.
   *
   * @param optQuiet
   */
  public void setOptQuiet(boolean optQuiet) {
    this.optQuiet = optQuiet;
  }

  /**
   * Returns true if verbose(-v) option is passed to <git-status> command.
   *
   * @return
   *           True if verbose(-v) option is passed to <git-status> command.
   */
  public boolean isOptVerbose() {
    return optVerbose;
  }

  /**
   * Sets the verbose option for <git-status>.
   *
   * @param optVerbose
   */
  public void setOptVerbose(boolean optVerbose) {
    this.optVerbose = optVerbose;
  }

  /**
   * Returns true if read from log file(-F) is null.
   *
   * @return
   *          True if read from log file(-F) is null.
   */
  public boolean isOptReadFromLogFileNull() {
    return optReadFromLogFile == null;
  }

  /**
   * Sets the readFromLogFile option, if we are reading logs from a file.
   *
   * @param optReadFromLogFile
   *          File for reading log.
   */
  public void setOptReadFromLogFile(File optReadFromLogFile) {
    this.optReadFromLogFile = optReadFromLogFile;
  }

  /**
   * Returns the file from where log is to be read.
   *
   * @return log file.
   */
  public File getOptReadFromLogFile() {
    return optReadFromLogFile;
  }

  /**
   * Returns true if sign-off(-s) options is set.
   *
   * @return value of sign-off option
   */
  public boolean isOptSignOff() {
    return optSignOff;
  }

  /**
   * Sets the signOff(-s) option to <git-status> command.
   *
   * @param signOff
   */
  public void setOptSignOff(boolean signOff) {
    this.optSignOff = signOff;
  }

  /**
   * Returns true if edit(-e) option is set.
   *
   * @return true if edit is set
   */
  public boolean isOptEdit() {
    return optEdit;
  }

  /**
   * Sets the edit(-e) option to <git-status> command
   *
   * @param edit
   */
  public void setOptEdit(boolean edit) {
    this.optEdit = edit;
  }

  /**
   * optAll tells the command to automatically stage files that have been modified and deleted, but
   * new files you have not told git about are not affected.
   *
   * Returns true if all(-a) option need to be used for <git-status> command.
   *
   * @return value of optAll
   */
  public boolean isOptAll() {
    return optAll;
  }

  /**
   * Sets the '-a' options to <git-status> command. If any one of the optOnly or OptInclude
   * options are set then optAll should not be set. While setting optAll to true, if optOnly or
   * optInclude is set set then IllegalArgumentException is thrown.
   *
   * @param all
   */
  public void setOptAll(boolean all) {
    if (all && (optOnly || optInclude)) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000100")
          + "  The \"all\" option can not be set when the \"only\" or \"include\" option is set.");
    }
    this.optAll = all;
  }

  /**
   * Before making a commit out of staged contents so far, stage the contents of paths given on the
   * command line as well. This is normally not used.
   *
   * Returns true if include(-i) option is set for <git-status> command.
   *
   * @return optInclude
   */
  public boolean isOptInclude() {
    return optInclude;
  }

  /**
   * Sets the value of optInclude to <git-status> command.
   *
   * @param include
   */
  public void setOptInclude(boolean include) {
    if (include && optAll) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000100")
          + "  The \"include\" option can not be set when the \"all\" option is set.");
    }
    this.optInclude = include;
  }

  /**
   * Returns true if only(-o) option is set.
   *
   * @return optOnly
   */
  public boolean isOptOnly() {
    return optOnly;
  }

  /**
   * Sets the optOnly option for <git-status> command. optOnly should not be set if optAll(-a)
   * option is set. IllegalArgumentException is thrown if both '-a' and 'o' are set.
   *
   * @param only
   */
  public void setOptOnly(boolean only) {
    if (only && optAll) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000100")
          + "  The \"only\" option can not be set when the \"all\" option is set.");
    }
    this.optOnly = only;
  }

  /**
   * Returns true if no-verify(-n) options is set.
   *
   * @return optNoVerify
   */
  public boolean isOptNoVerify() {
    return optNoVerify;
  }

  /**
   * Set the value to true if no verify(-n) option is set.
   *
   * @param noVerify
   */
  public void setOptNoVerify(boolean noVerify) {
    this.optNoVerify = noVerify;
  }

  /**
   * Returns true if --untracked-files options is set.
   *
   * @return optUntrackedFiles.
   */
  public boolean isOptUntrackedFiles() {
    return optUntrackedFiles;
  }

  /**
   * Sets the value to true if untracked (--untracked-files) option need to be set.
   *
   * @param untrackedFiles
   */
  public void setOptUntrackedFiles(boolean untrackedFiles) {
    this.optUntrackedFiles = untrackedFiles;
  }

  /**
   * Returns true if allow empty options is set. This option should be set if it's okay to record
   * an empty change.
   *
   * @return
   *           True if allow empty options is set. This option should be set if it's okay to record
   *           an empty change.
   */
  public boolean isOptAllowEmpty() {
    return optAllowEmpty;
  }

  /**
   * Sets the value of allow empty option to true if we would like to record an empty change.
   *
   * @param allowEmpty
   */
  public void setOptAllowEmpty(boolean allowEmpty) {
    this.optAllowEmpty = allowEmpty;
  }

  /**
   * Returns the author. This option should be used if we would like to override the value in
   * commit.
   *
   * @return author
   */
  public String getAuthor() {
    return author;
  }

  /**
   * Sets the author name.
   *
   * @param author
   */
  public void setAuthor(String author) {
    CheckUtilities.checkStringArgument(author, "Author name for override");
    this.author = author;
  }

  /**
   * Returns true if author name is null.
   *
   * @return true if author name for override is set.
   */
  public boolean isAuthorNull() {
    return author == null;
  }

}


/*
 * ====================================================================
 * 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.io.File;
import java.io.IOException;
import java.util.List;

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

/**
 * This class provides utilities methods that perform various checks for validity.
 */
public class CheckUtilities {

  /**
   * Checks that the specified filename exists. This assumes that the above check for string
   * validity has already been run and the path/filename is neither null or of size 0.
   *
   * @param filename
   *          File or directory path
   */
  public static void checkFileValidity(String filename) throws IOException {
    File file = new File(filename);
    if (!file.exists()) {
      throw new IOException(ExceptionMessageMap.getMessage("020001") + "  { filename=[" + filename
          + "] }");
    }
  }

  /**
   * Checks that the specified file exists.
   *
   * @param file
   *          File or directory path
   */
  public static void checkFileValidity(File file) throws IOException {
    if (!file.exists()) {
      throw new IOException(ExceptionMessageMap.getMessage("020001") + "  { filename=["
          + file.getName() + "] }");
    }
  }

  /**
   * Checks that the int to check is greater than lowerBound. If the int to check is
   * not greater than lowerBound, an IllegalArgumentException is
   * thrown.
   *
   * @param toCheck
   *          The int to check.
   * @param lowerBound
   *          The lower bound to check against.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void checkIntArgumentGreaterThan(int toCheck, int lowerBound, String variableName) {
    if (lowerBound >= toCheck) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000004") + "  { toCheck=["
          + toCheck + "], lowerBound=[" + lowerBound + "], variableName=[" + variableName + "] }");
    }
  }

  /**
   * Performs a null check on the specified object. If the object is null, a
   * NullPointerException is thrown.
   *
   * @param obj
   *          The object to check.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void checkNullArgument(Object obj, String variableName) {
    if (null == obj) {
      throw new NullPointerException(ExceptionMessageMap.getMessage("000003")
          + "  { variableName=[" + variableName + "] }");
    }
  }

  /**
   * Checks a List<?> argument to make sure it is not null, has length > 0, and
   * none of its elements are null. If the List<?> or any contained instance is
   * null, a NullPointerException is thrown. If the List<?> or
   * any contained instance has length zero, an IllegalArgumentException is thrown.
   *
   * @param list
   *          The list to check.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void checkNullListArgument(List<?> list, String variableName) {
    // TODO (jhl388): Write a unit test for this method.
    if (null == list) {
      throw new NullPointerException(ExceptionMessageMap.getMessage("000005")
          + "  { variableName=[" + variableName + "] }");
    }
    if (list.size() == 0) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000005")
          + "  { variableName=[" + variableName + "] }");
    }
    for (int i = 0; i < list.size(); i++) {
      checkNullArgument(list.get(i), variableName);
    }
  }

  /**
   * Checks that two lists are equal, specifically: they are both null or the both contain the same
   * elements.
   *
   * @param l1
   *          The first list to check.
   * @param l2
   *          The second list to check.
   * @return True if one of the following conditions hold:
   *

   *
Both lists are null

   *
a) Neither list is null; b) for each element in list 1 an equivalent element
   *         exists in list 2; and c) for each element in list 2, an equivalent element exists in
   *         list 1

   *

   */
  public static boolean checkListsEqual(List<?> l1, List<?> l2) {

    // TODO (jhl388): write a test case for this method.

    if (null != l1 && null == l2) {
      return false;
    }

    if (null == l1 && null != l2) {
      return false;
    }

    if (null != l1) {
      for (Object e : l1) {
        if (!l2.contains(e)) {
          return false;
        }
      }

      for (Object e : l2) {
        if (!l1.contains(e)) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * Checks to see if two objects are equal. The Object.equal() method is used to check for
   * equality.
   *
   * @param o1
   *          The first object to check.
   * @param o2
   *          The second object to check.
   * @return True if the two objects are equal. False if the objects are not equal.
   */
  public static boolean checkObjectsEqual(Object o1, Object o2) {
    if (null != o1 && !o1.equals(o2)) {
      return false;
    }

    if (null == o1 && null != o2) {
      return false;
    }

    return true;
  }

  /**
   * Checks a String argument to make sure it is not null and contains one or more
   * characters. If the String is null, a NullPointerException is
   * thrown. If the String has length zero, an IllegalArgumentException
   * is thrown.
   *
   * @param str
   *          The string to check.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void checkStringArgument(String str, String variableName) {
    if (null == str) {
      throw new NullPointerException(ExceptionMessageMap.getMessage("000001")
          + "  { variableName=[" + variableName + "] }");
    }
    if (str.length() == 0) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000001")
          + "  { variableName=[" + variableName + "] }");
    }
  }

  /**
   * Checks a List<String> argument to make sure it is not null, none of its
   * elements are null, and all its elements contain one or more characters. If the
   * List<String> or a contained String is null, a
   * NullPointerException is thrown. If the List<String> or a
   * contained String has length zero, an IllegalArgumentException is
   * thrown.
   *
   * @param str
   *          The List<String> to check.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void checkStringListArgument(List<String> str, String variableName) {
    if (null == str) {
      throw new NullPointerException(ExceptionMessageMap.getMessage("000002")
          + "  { variableName=[" + variableName + "] }");
    }
    if (str.size() == 0) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000002")
          + "  { variableName=[" + variableName + "] }");
    }
    for (int i = 0; i < str.size(); i++) {
      checkStringArgument(str.get(i), variableName);
    }
  }

  /**
   * Checks if two unordered lists are equal.
   *
   * @param l1
   *          The first list to test.
   * @param l2
   *          The second list to test.
   * @return True if:
   *

   *
both lists are null or

   *
both lists are the same length, there exists an equivalent object in l2 for all
   *         objects in l1, and there exists an equivalent object in l1 for all objects in l2

   *

   *         False otherwise.
   */
  public static boolean checkUnorderedListsEqual(List<?> l1, List<?> l2) {
    if (null == l1 && null != l2) {
      return false;
    }

    if (null != l1 && null == l2) {
      return false;
    }

    if (l1.size() != l2.size()) {
      return false;
    }

    for (Object o : l1) {
      if (!l2.contains(o)) {
        return false;
      }
    }

    for (Object o : l2) {
      if (!l1.contains(o)) {
        return false;
      }
    }

    return true;
  }

  /**
   * Check if the index provided to list is within the range i.e. positive and less than the size of
   * the <List>. If the index is less than 0 or greater than equal to the size of the list then
   * IndexOutOfBoundsException is thrown.
   *
   * @param list
   *          <List> for which the index is being verified.
   * @param index
   *          Index in the list.
   */
  public static void checkIntIndexInListRange(List<?> list, int index) {
    checkIntInRange(index, 0, list.size());
  }

  /**
   * A general range check utility for checking whether a given <integer> value is between a
   * given start and end indexes. This is a helper method for other methods such as
   * checkIntIndexInListRange or can also be used independently by external objects.
   *
   * @param index
   *          Given index that is being checked for validity between start and end.
   * @param start
   *          index should be greater than or equal to start.
   * @param end
   *          index should be less than end.
   */
  public static void checkIntInRange(int index, int start, int end) {
    if (index < start) {
      throw new IndexOutOfBoundsException(ExceptionMessageMap.getMessage("000006") + "  { index=["
          + index + "], start=[" + start + "], end=[" + end + "] }");
    }
    if (index >= end) {
      throw new IndexOutOfBoundsException(ExceptionMessageMap.getMessage("000006") + "  { index=["
          + index + "], start=[" + start + "], end=[" + end + "] }");
    }
  }

  /**
   * Checks a List argument to make sure that all the Ref in the list
   * are of same refType type. If there is a mismatch
   * IllegalArgumentException is thrown.
   *
   * @param list
   *          The List to check.
   * @param type
   *          The refType check against.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void validateListRefType(List<Ref> list, Ref.RefType type, String variableName) {
    // TODO (ns1344): Write a unit test for this method.
    checkNullListArgument(list, variableName);
    for (Ref ref : list) {
      validateArgumentRefType(ref, type, variableName);
    }
  }

  /**
   * Checks a Ref argument to make sure that it is of given refType type.
   * If not IllegalArgumentException is thrown.
   *
   * @param name
   *          The argument to check.
   * @param type
   *          The refType to check against.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void validateArgumentRefType(Ref name, Ref.RefType type, String variableName) {
    checkNullArgument(name, variableName);
    if (name.getRefType() != type) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("100000")
          + "  { variableName=[" + variableName + "] }");
    }
  }

  /**
   * Checks a File argument to make sure that it is a directory. If not
   * IllegalArgumentException is thrown.
   *
   * @param fileName
   *          The File to be checked.
   * @param variableName
   *          The name of the variable being checked; for use in exception messages.
   */
  public static void checkDirectoryArgument(File fileName, String variableName) {
    checkNullArgument(fileName, variableName);
    if (!fileName.isDirectory()) {
      throw new IllegalArgumentException(ExceptionMessageMap.getMessage("000007")
          + "  { variableName=[" + variableName + "] }");
    }
  }
}


/*
 * ====================================================================
 * 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.util.HashMap;
import java.util.Map;

import edu.nyu.cs.javagit.client.cli.CliClient;

/**
 * This class manages the IClient instances of the various ClientTypes.
 * It contains factory type functionality (the getClientType() method) but manages
 * much more than just creating IClient instances.
 */
public class ClientManager {

  // An enumeration of the available client types.
  public static enum ClientType {
    CLI
  };

  // The singleton instance of the class ClientManager.
  private static ClientManager INSTANCE = new ClientManager();

  /**
   * Gets the singleton instance.
   *
   * @return The singleton instance.
   */
  public static ClientManager getInstance() {
    return INSTANCE;
  }

  // The preferred client type.
  private ClientType preferredClientType = ClientType.CLI;

  /**
   * A Map to hold IClient instances for the ClientTypes by
   * ClientType.
   */
  private Map<ClientType, IClient> clientImpls = new HashMap<ClientType, IClient>();

  /**
   * Private to make this class a singleton.
   */
  private ClientManager() {
  }

  /**
   * Gets an instance of the specified client type.
   *
   * @param clientType
   *          The type of client to get.
   * @return An instance of the specified client type.
   */
  public IClient getClientInstance(ClientType clientType) {
    IClient clientInstance = clientImpls.get(clientType);
    if (null == clientInstance) {
      if (ClientType.CLI == clientType) {
        clientInstance = new CliClient();
      }
      if (null != clientInstance) {
        clientImpls.put(clientType, clientInstance);
      }
    }
    return clientInstance;
  }

  /**
   * Gets an instance of the preferred client type as set via the
   * setPreferredClientType() method.
   *
   * @return An IClient instance for the preferred client type.
   */
  public IClient getPreferredClient() {
    return getClientInstance(preferredClientType);
  }

  /**
   * Sets the preferred client type.
   *
   * @param preferredClientType
   *          The type to set as the preferred client type. If the value is null, then the preferred
   *          client type is set to ClientType.CLI.
   */
  public void setPreferredClientType(ClientType preferredClientType) {
    if (null == preferredClientType) {
      this.preferredClientType = ClientType.CLI;
    } else {
      this.preferredClientType = preferredClientType;
    }
  }
}


/*
 * ====================================================================
 * 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.commands.GitAddOptions;
import edu.nyu.cs.javagit.api.commands.GitAddResponse;
import edu.nyu.cs.javagit.client.GitAddResponseImpl;
import edu.nyu.cs.javagit.client.IGitAdd;
import edu.nyu.cs.javagit.utilities.CheckUtilities;
import edu.nyu.cs.javagit.utilities.ExceptionMessageMap;

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

/**
 * Command-line implementation of the IGitAdd interface.
 *

 * TODO (gsd216) - to implement exception chaining.
 */
public class CliGitAdd implements IGitAdd {

    /**
     * Implementations of <git-add> with options and list of files provided.
     */
    public GitAddResponse add(File repositoryPath, GitAddOptions options, List<File> paths)
            throws JavaGitException, IOException {
        CheckUtilities.checkFileValidity(repositoryPath);
        GitAddParser parser = new GitAddParser();
        List<String> command = buildCommand(repositoryPath, options, paths);
        GitAddResponseImpl response = (GitAddResponseImpl) ProcessUtilities.runCommand(repositoryPath,
                command, parser);

        if (options != null) {
            addDryRun(options, response);
        }
        return (GitAddResponse) response;
    }

    /**
     * Adds a list of files with no GitAddOptions.
     */
    public GitAddResponse add(File repositoryPath, List<File> files) throws JavaGitException,
            IOException {
        GitAddOptions options = null;
        return add(repositoryPath, options, files);
    }

    /**
     * Adds one file to the index with no GitAddOptions.
     */
    public GitAddResponse add(File repositoryPath, File file) throws JavaGitException, IOException {
        List<File> filePaths = new ArrayList<File>();
        filePaths.add(file);
        GitAddOptions options = null;
        return add(repositoryPath, options, filePaths);
    }

    /**
     * Implementations of <git-add> with options and one file to be added to index.
     */
    public GitAddResponse add(File repositoryPath, GitAddOptions options, File file)
            throws JavaGitException, IOException {
        List<File> paths = new ArrayList<File>();
        paths.add(file);
        return add(repositoryPath, options, paths);
    }

    /**
     * Implementation of <git-add> dry run.
     */
    public GitAddResponse addDryRun(File repositoryPath, List<File> paths) throws JavaGitException,
            IOException {
        GitAddOptions options = new GitAddOptions();
        options.setDryRun(true);
        return add(repositoryPath, options, paths);
    }

    /**
     * Implementations of <git-add> in verbose mode.
     */
    public GitAddResponse addVerbose(File repositoryPath, List<File> paths) throws JavaGitException,
            IOException {
        GitAddOptions options = new GitAddOptions();
        options.setVerbose(true);
        return add(repositoryPath, options, paths);
    }

    /**
     * Implementations of <git-add> with force option set.
     */
    public GitAddResponse addWithForce(File repositoryPath, List<File> paths)
            throws JavaGitException, IOException {
        GitAddOptions options = new GitAddOptions();
        options.setForce(true);
        return add(repositoryPath, options, paths);
    }

    /**
     * if the dry run option was selected then set the flag in response.
     *
     * @param options  GitAddOptions
     * @param response gitAddResponse
     */
    private void addDryRun(GitAddOptions options, GitAddResponseImpl response) {
        if (options.dryRun()) {
            response.setDryRun(true);
        }
    }

    private List<String> buildCommand(File repositoryPath, GitAddOptions options, List<File> paths) {
        List<String> command = new ArrayList<String>();
        command.add(JavaGitConfiguration.getGitCommand());
        command.add("add");
        if (options != null) {
            if (options.dryRun()) {
                command.add("-n");
            }
            if (options.verbose()) {
                command.add("-v");
            }
            if (options.force()) {
                command.add("-f");
            }
            if (options.update()) {
                command.add("-u");
            }
            if (options.refresh()) {
                command.add("--refresh");
            }
            if (options.ignoreErrors()) {
                command.add("--ignore-errors");
            }
        }
        if (paths != null && paths.size() > 0) {
            for (File file : paths) {
                command.add(file.getPath());
            }
        }
        return command;
    }

    /**
     * Parser class that implements IParser for implementing a parser for
     * <git-add> output.
     */
    public static class GitAddParser implements IParser {

        private int lineNum;
        private GitAddResponseImpl response;
        private boolean error = false;
        private List<Error> errorList;

        public GitAddParser() {
            lineNum = 0;
            response = new GitAddResponseImpl();
        }

        public void parseLine(String line) {
            if (line == null || line.length() == 0) {
                return;
            }
            lineNum++;
            if (isError(line)) {
                error = true;
                errorList.add(new Error(lineNum, line));
            } else if (isComment(line))
                response.setComment(lineNum, line);
            else
                processLine(line);
        }

        private boolean isError(String line) {
            if (line.trim().startsWith("fatal") || line.trim().startsWith("error")) {
                if (errorList == null) {
                    errorList = new ArrayList<Error>();
                }
                return true;
            }
            return false;
        }

        private boolean isComment(String line) {
            if (line.startsWith("Nothing specified") || line.contains("nothing added")
                    || line.contains("No changes") || line.contains("Maybe you wanted to say")
                    || line.contains("usage")) {
                return true;
            }
            return false;
        }

        /**
         * Lines that start with "add" have the second token as the name of the file added by
         * <git-add&gt.
         *
         * @param line
         */
        private void processLine(String line) {
            if (line.startsWith("add")) {
                StringTokenizer st = new StringTokenizer(line);

                if (st.nextToken().equals("add") && st.hasMoreTokens()) {
                    String extractedFileName = filterFileName(st.nextToken());
                    if (extractedFileName != null && extractedFileName.length() > 0) {
                        File file = new File(extractedFileName);
                        response.add(file);
                    }
                }
            } else {
                processSpaceDelimitedFilePaths(line);
            }
        }

        private void processSpaceDelimitedFilePaths(String line) {
            if (!line.startsWith("\\s+")) {
                StringTokenizer st = new StringTokenizer(line);
                while (st.hasMoreTokens()) {
                    File file = new File(st.nextToken());
                    response.add(file);
                }
            }
        }

        public String filterFileName(String token) {
            if (token.length() > 0 && enclosedWithSingleQuotes(token)) {
                int firstQuote = token.indexOf("'");
                int nextQuote = token.indexOf("'", firstQuote + 1);
                if (nextQuote > firstQuote) {
                    return token.substring(firstQuote + 1, nextQuote);
                }
            }
            return null;
        }

        public boolean enclosedWithSingleQuotes(String token) {
            return token.matches("'.*'");
        }

        public void processExitCode(int code) {
        }

        /**
         * Gets a GitAddResponse object containing the info generated by <git-add> command.
         * If there was an error generated while running <git-add> then it throws an exception.
         *
         * @return GitAddResponse object containing <git-add> response.
         * @throws JavaGitException If there are any errors generated by <git-add> command.
         */
        public GitAddResponse getResponse() throws JavaGitException {
            if (error) {
                throw new JavaGitException(401000, ExceptionMessageMap.getMessage("401000") +
                        " - git add error message: { " + getError() + " }");
            }
            return response;
        }

        /**
         * Retrieves all the errors in the error list and concatenate them together in one string.
         *
         * @return  concatenation of errors
         */
        private String getError() {
            StringBuffer buf = new StringBuffer();
            for (int i = 0; i < errorList.size(); i++) {
                buf.append("Line " + errorList.get(i).lineNum + ". " + errorList.get(i).getErrorString());
                if (i < errorList.size() - 1) {
                    buf.append(" ");
                }
            }
            return buf.toString();
        }

        /**
         * Class for storing error details from the <git-add> output.
         */
        private static class Error {
            final int lineNum;
            final String errorStr;

            Error(int lineNum, String errorStr) {
                this.lineNum = lineNum;
                this.errorStr = errorStr;
            }

            public String getErrorString() {
                return errorStr;
            }
        }
    }
}


package edu.nyu.cs.javagit.api;

import edu.nyu.cs.javagit.api.commands.CommandResponse;
import edu.nyu.cs.javagit.utilities.ExceptionMessageMap;

/**
 * Git version is composed by major.minor.releaseMajor{"." + releaseMinor|"-" + tag}  meaning that
 * release minor and tag are optional and mutually excluded.
 *

 * These rules are valid for Git v1.1.0 onwards. This object is not intended to manage Git versions previous to this one
 *

 * Valid values are : 1.7.0, 1.8.0.1 and 1.8.2-rc4 among others
 */
public class GitVersion implements CommandResponse, Comparable<GitVersion> {

    public static final int LATER = +1;
    public static final int PREVIOUS = -1;
    public static final int SAME = 0;

    private String tag;
    private Integer releaseMinor = null;
    private int releaseMajor;
    private int major;
    private int minor;

    // The version of git that gets passed into our constructor.
    private String version;

    /**
     * Constructor.
     *
     * @param version The version of git being used.
     */
    public GitVersion(String version) throws JavaGitException {
        this.version = version.trim();

        String[] versionNumber = this.version.split("\\.", 4);
        if (versionNumber.length > 0) {
            parseMajor(versionNumber[0]);
            if (versionNumber.length > 1) {
                parseMinor(versionNumber[1]);
                if (versionNumber.length > 2) {
                    String[] relDashSplit = versionNumber[2].split("-", 2);
                    if (relDashSplit.length == 2) {
                        parseMajorRelease(relDashSplit[0]);
                        this.tag = relDashSplit[1];
                    } else if (versionNumber.length == 4) {
                        parseMajorRelease(versionNumber[2]);
                        parseMinorRelease(versionNumber[3]);
                    } else {
                        parseMajorRelease(versionNumber[2]);
                    }
                } else {
                    throw new JavaGitException(442003, ExceptionMessageMap.getMessage("442003"));
                }

            } else {
                throw new JavaGitException(442002, ExceptionMessageMap.getMessage("442002"));
            }
        } else {
            throw new JavaGitException(442001, ExceptionMessageMap.getMessage("442001"));
        }
    }

    private void parseMajor(String s) throws JavaGitException {
        try {
            this.major = Integer.parseInt(s);
        } catch (NumberFormatException e) {
            throw new JavaGitException(442001, ExceptionMessageMap.getMessage("442001"));
        }
    }

    private void parseMinor(String s) throws JavaGitException {
        try {
            this.minor = Integer.parseInt(s);
        } catch (NumberFormatException e) {
            throw new JavaGitException(442002, ExceptionMessageMap.getMessage("442002"));
        }
    }

    private void parseMinorRelease(String s) throws JavaGitException {
        try {
            this.releaseMinor = Integer.parseInt(s);

        } catch (NumberFormatException e) {
            throw new JavaGitException(442004, ExceptionMessageMap.getMessage("442004"));
        }
    }

    private void parseMajorRelease(String s) throws JavaGitException {
        try {
            this.releaseMajor = Integer.parseInt(s);

        } catch (NumberFormatException e) {
            throw new JavaGitException(442003, ExceptionMessageMap.getMessage("442003"));
        }
    }

    /**
     * Gets the version of git being used in String format.
     *
     * @return The git version string.
     */
    @Override
    public String toString() {
        return version;
    }

    public int getMinor() {
        return minor;
    }

    public int getMajor() {
        return major;
    }

    public int getReleaseMajor() {
        return releaseMajor;
    }

    public String getTag() {
        return tag;
    }

    public int getReleaseMinor() {
        return releaseMinor;
    }

    public boolean containsReleaseMinor() {
        return releaseMinor != null;
    }

    public boolean containsTag() {
        return getTag() != null;
    }

    public boolean equals(Object that) {
        if (!(that instanceof GitVersion))
            return super.equals(that);

        return( this.version.equals( ((GitVersion)that).version) );
    }

    public int compareTo(GitVersion that) {

        if (this.getMajor() > that.getMajor()) {
            return LATER;
        } else if (this.getMajor() < that.getMajor()) {
            return PREVIOUS;
        } else {
            if (this.getMinor() > that.getMinor()) {
                return LATER;
            } else if (this.getMinor() < that.getMinor()) {
                return PREVIOUS;
            } else {
                if (this.getReleaseMajor() > that.getReleaseMajor()) {
                    return LATER;
                } else if (this.getReleaseMajor() < that.getReleaseMajor()) {
                    return PREVIOUS;
                } else {
                    return compareToReleaseMinorAndTag(that);
                }
            }
        }
    }

    private int compareToReleaseMinorAndTag(GitVersion that) {
        if (!this.containsReleaseMinor() && !that.containsReleaseMinor())
            return compareToTag(that);
        else if (!this.containsTag() && !that.containsTag())
            return compareToReleaseMinor(that);
        else if (this.containsReleaseMinor() && !that.containsTag())
            return LATER;
        else
            return PREVIOUS;
    }

    /**
     * Compares minor releases values given that git version contains no tag
     * for none of GitVersion objects
     *
     * @param that
     * @return  SAME if both are equal, LATER if that is previous to this or PREVIOUS otherwise
     */
    private int compareToReleaseMinor(GitVersion that) {
        if (this.containsReleaseMinor() && that.containsReleaseMinor())
            return compareToInt(this.getReleaseMinor(), that.getReleaseMinor());
        else if (!this.containsReleaseMinor() && !that.containsReleaseMinor())
            return SAME;
        else if (this.containsReleaseMinor() && !that.containsReleaseMinor())
            return LATER;
        else
            return PREVIOUS;
    }

    /**
     * Compares tag values given that git version contains no minor release
     * for none of GitVersion objects
     *

     * When both contain a tag or not contain  it the comparison is easy but
     * if only one of them contains it the release that doesn't contains it
     * is the one released earlier
     *

     * e.g. v1.8.0-rc0 is previous to v1.8.0
     *
     * @param that
     * @return SAME if both are equal, LATER if that is previous to this or PREVIOUS otherwise
     */
    private int compareToTag(GitVersion that) {
        if (this.containsTag() && that.containsTag())
            return this.getTag().compareTo(that.getTag());
        else if (!this.containsTag() && !that.containsTag())
            return SAME;
        else if (this.containsTag() && !that.containsTag())
            return PREVIOUS;
        else
            return LATER;
    }

    private int compareToInt(int iThis, int iThat) {
        if (iThis > iThat)
            return LATER;
        else if (iThis < iThat)
            return PREVIOUS;
        else return SAME;

    }
}


/*
 * 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.database.Cursor;
import android.database.CursorWrapper;

import org.droitateddb.cursor.ObjectCursor;

/**
 * Provides utility methods for cursors.
 *
 * @author Falk Appel
 * @author Alexander Frank
 */
public class CursorUtil {

	/**
	 * Convert a standard Android {@link Cursor} into a {@link org.droitateddb.cursor.ObjectCursor}.<br>
	 * This is only possible for {@link Cursor}s that where queried over a {@link ContentResolver} from a
	 * {@link ContentProvider} derived by {@link BaseContentProvider}.
	 *
	 * @param <T>    Entity class represented within the Cursor
	 * @param cursor Android {@link Cursor}
	 * @return The {@link org.droitateddb.cursor.ObjectCursor} representation of the given Android {@link Cursor}
	 * @throws NullPointerException     When the given cursor is null
	 * @throws IllegalArgumentException When the given cursor is not of the type {@link CursorWrapper}, which will be returned by a
	 *                                  {@link ContentResolver}
	 * @throws IllegalStateException    When the wrapped cursor within the given cursor is not of type {@link org.droitateddb.cursor.ObjectCursor}. This indicates
	 *                                  that the given cursor was not queried from a derivation {@link BaseContentProvider}
	 */
	@SuppressWarnings("unchecked")
	public static <T> ObjectCursor<T> getObjectCursor(final Cursor cursor) {
		if (cursor == null) {
			throw new NullPointerException("The given cursor is null");
		}
		if (!(cursor instanceof CursorWrapper)) {
			throw new IllegalArgumentException(
					"The given cursor is not of type " + CursorWrapper.class.getCanonicalName() + ". It has type " + cursor.getClass().getCanonicalName() +
							". Was it queried with a ContentResolver?");
		}

		CursorWrapper wrapper = (CursorWrapper) cursor;
		Cursor wrappedCursor = wrapper.getWrappedCursor();

		if (!(wrappedCursor instanceof ObjectCursor)) {
			throw new IllegalStateException(
					"The wrapped cursor of the given CursorWrapper is not of type " + ObjectCursor.class.getCanonicalName() + ". It has type " +
							wrappedCursor.getClass().getCanonicalName() +
							". Was it queried over a ContentResolver from BaseContentProvider derived ContentProvider?");
		}
		return (ObjectCursor<T>) wrappedCursor;
	}

}


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

package edu.nyu.cs.javagit.api.commands;

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

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

/**
 * GitAdd provides an interface for adding files or directory tree into git
 * repository
 */
public final class GitAdd {
  /**
   * This command adds the current content of new or modified files to the index, thus staging that
   * content for inclusion in the next commit.
   *
   * @param repositoryPath
   *          The path to the repository to commit against. A non-zero length argument is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param options
   *          GitAddOptions that are passed to the <git-add> command.
   * @param paths
   *          List of file paths that will be added to the index.
   * @return GitAddResponse Response generated by the add command.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown if -
   *

   *
repositoryPath is not valid

   *
filenames assigned do not exist

   *
files or repository path does not have access rights

   *

   * @exception JavaGitException
   *              Exception thrown
   *

   *
if the repositoryPath is null.

   *
if the <git-add> command generates error.

   *

   */
  public GitAddResponse add(File repositoryPath, GitAddOptions options, List<File> paths)
      throws IOException, JavaGitException {
    CheckUtilities.checkFileValidity(repositoryPath.getAbsoluteFile());
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.add(repositoryPath, options, paths);
  }

  /**
   * This command adds the current content of new or modified files to the index, with verbose
   * option set.
   *
   * @param repositoryPath
   *          The path to the repository to commit against. A non-zero length argument is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param paths
   *          List of file paths that will be added to the index.
   * @return GitAddResponse Response generated by the add command.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown if -
   *

   *
repositoryPath is not valid

   *
filenames assigned do not exist

   *
files or repository path does not have access rights

   *

   * @exception JavaGitException
   *              Exception thrown
   *

   *
if the repositoryPath is null.

   *
if the <git-add> command generates error.

   *

   */
  public GitAddResponse addVerbose(File repositoryPath, List<File> paths) throws IOException,
      JavaGitException {
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.addVerbose(repositoryPath, paths);
  }

  /**
   * This command adds the current content of new or modified files to the index, with Force option
   * set i.e. it adds the ignored files as well.
   *
   * @param repositoryPath
   *          The path to the repository to commit against. A non-zero length argument is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param paths
   *          List of file paths that will be added to the index.
   * @return GitAddResponse Response generated by the add command.
   * @exception IOException
   *              There are many reasons for which an IOException may be thrown if -
   *

   *
repositoryPath is not valid

   *
filenames assigned do not exist

   *
files or repository path does not have access rights

   *              </ul
   * @exception JavaGitException
   *              Exception thrown
   *

   *
if the repositoryPath is null.

   *
if the <git-add> command generates error.

   *

   */
  public GitAddResponse addWithForce(File repositoryPath, List<File> paths) throws IOException,
      JavaGitException {
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.addWithForce(repositoryPath, paths);
  }

  /**
   * This command just executes <git-add> in dry run mode.
   *
   * @param repositoryPath
   *          The path to the repository to commit against. A non-zero length argument is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param paths
   *          List of file paths that will be added to the index.
   * @return results GitAddResponse from the add command.
   * @exception IOException
   *              There are many reasons for which an IOException could be thrown if -
   *

   *
repositoryPath is not valid

   *
filenames assigned do not exist

   *
files or repository path does not have access rights

   *

   * @exception JavaGitException
   *              Exception thrown
   *

   *
if the repositoryPath is null.

   *
if the <git-add> command generates error.

   *

   */
  public GitAddResponse addDryRun(File repositoryPath, List<File> paths) throws IOException,
      JavaGitException {
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.addDryRun(repositoryPath, paths);
  }

  /**
   * This command adds the current content of new or modified file to the index, thus staging that
   * content for inclusion in the next commit.
   *
   * @param repositoryPath
   *          The path to the repository to commit against. A non-zero length argument is required
   *          for this parameter, otherwise a NullPointerException or
   *          IllegalArgumentException will be thrown.
   * @param options
   *          GitAddOptions that are passed to the <git-add> command.
   * @param file File to be added to the index.
   * @return GitAddResponse object.
   * @exception IOException There are many reasons for which an IOException
   *              may be thrown if -
   *

   *
repositoryPath is not valid

   *
filenames assigned do not exist

   *
files or repository path does not have access rights

   *

   * @exception JavaGitException
   *              Exception thrown
   *

   *
if the repositoryPath is null.

   *
if the <git-add> command generates error.

   *

   */
  public GitAddResponse add(File repositoryPath, GitAddOptions options, File file)
      throws IOException, JavaGitException {
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.add(repositoryPath, options, file);
  }

  /**
   * Adds list of files to the index.
   *
   * @param repositoryPath
   *          File path pointing to the root of the repository.
   * @param file
   *          File will added to the index.
   * @return GitAddResponse object.
   * @throws JavaGitException Thrown when there is an error while running the add command.
   * @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

   *

   */
  public GitAddResponse add(File repositoryPath, File file) throws IOException, JavaGitException {
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.add(repositoryPath, file);
  }

  /**
   * Adds list of files to the index with no options set.
   *
   * @param repositoryPath
   *          File path pointing to the root of the repository
   * @param paths
   *          List of file paths that are going to be added to the index.
   * @return GitAddResponse object.
   * @throws JavaGitException Thrown when there is an error while running the add command.
   * @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

   *

   */
  public GitAddResponse add(File repositoryPath, List<File> paths) throws JavaGitException,
      IOException {
    IClient client = ClientManager.getInstance().getPreferredClient();
    IGitAdd gitAdd = client.getGitAddInstance();
    return gitAdd.add(repositoryPath, paths);
  }

}