package hu.sebcsaba.gitrelocate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class GitCmdLineRunner implements GitRunner {
	
	private final CmdLineTool cmdLine;
	
	public GitCmdLineRunner(CmdLineTool cmdLine) {
		this.cmdLine = cmdLine;
	}
	
	public CommitID getCommitId(String anyGitCommitRef) {
		return new CommitID(gitString("rev-parse", anyGitCommitRef).trim());
	}
	
	public List<CommitID> getCommitParentIds(CommitID commitId) {
		return getCommitIDList(gitStringList("log", "--pretty=%P", "-n", "1", commitId.toString()));
	}
	
	public Collection<String> getTagNames() {
		return gitStringList("tag");
	}
	
	public Collection<String> getBranchNames() {
		List<String> result = gitStringList("branch");
		result.remove("*");
		return result;
	}
	
	public String getActualHeadName() {
		String head = gitString("rev-parse", "--abbrev-ref", "HEAD");
		if ("HEAD".equals(head)) {
			head = gitString("rev-parse", "HEAD");
		}
		return head.trim();
	}

	public void createBranch(String branchName) {
		gitExec("branch", branchName);
	}

	public void createBranch(String branchName, CommitID commitId) {
		gitExec("branch", branchName, commitId.toString());
	}

	public void removeBranch(String branchName) {
		gitExec("branch", "-D", branchName);
	}

	public void moveBranch(String branchName, CommitID commitId) {
		String head = getActualHeadName();
		checkOut(branchName);
		gitExec("reset", "--hard", commitId.toString());
		checkOut(head);
	}

	public void checkOut(String branchName) {
		gitExec("checkout", branchName);
	}

	public void createTag(String tagName) {
		gitExec("tag", tagName);
	}

	public void createTag(String tagName, CommitID commitId) {
		gitExec("tag", tagName, commitId.toString());
	}

	public void removeTag(String tagName) {
		gitExec("tag", "-D", tagName);
	}

	public CommitID cherryPick(CommitID commitId) {
		gitExec("cherry-pick", commitId.toString());
		return getCommitId("HEAD");
	}

	public CommitID cherryPickMergeCommit(CommitID commitId, List<CommitID> newParentsIds) {
		try {
			gitExec("cherry-pick", "--no-ff", "--no-commit", "--mainline", "1", commitId.toString());
			String treeId = gitString("write-tree").trim();
			String message = gitString("log", "-1", "--pretty=%B", commitId.toString());

			List<String> commitParams = new ArrayList<String>();
			commitParams.addAll(Arrays.asList("git", "commit-tree", treeId));
			for (CommitID newParentId : newParentsIds) {
				commitParams.add("-p");
				commitParams.add(newParentId.toString());
			}
			String commit = cmdLine.withInput(message).getString(commitParams.toArray(new String[commitParams.size()])).trim();
			return new CommitID(commit);
		} catch (IOException ex) {
			throw new RuntimeException(ex);
		}
	}

	private void gitExec(String... params) {
		try {
			cmdLine.run(unshift("git", params));
		}
		catch (IOException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	private String gitString(String... params) {
		try {
			return cmdLine.getString(unshift("git", params));
		}
		catch (IOException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	private List<String> gitStringList(String... params) {
		try {
			return cmdLine.getStringList(unshift("git", params));
		}
		catch (IOException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	private List<CommitID> getCommitIDList(List<String> ids) {
		List<CommitID> result = new ArrayList<CommitID>(ids.size());
		for (String id : ids) {
			result.add(new CommitID(id));
		}
		return result;
	}
	
	private String[] unshift(String first, String[] rest) {
		String[] result = new String[rest.length+1];
		result[0] = first;
		System.arraycopy(rest, 0, result, 1, rest.length);
		return result;
	}

}

@@ -2284,64 +2284,32 @@
  = g
-itString(%22log%22, %22-1%22, %22--pretty=%25B%22, commitId.toString()
+etCommitMessage(commitId
 );%0A%0A
@@ -2783,16 +2783,322 @@
 %09%09%7D%0A%09%7D%0A%0A
+%09private String getCommitMessage(CommitID commitId) %7B%0A%09%09StringBuilder result = new StringBuilder();%0A%09%09String%5B%5D list = gitString(%22show%22, %22--format=full%22, commitId.toString()).split(%22%5C%5Cr?%5C%5Cn%22);%0A%09%09for (int i=5; i%3Clist.length; ++i) %7B%0A%09%09%09result.append(list%5Bi%5D).append(%22%5Cn%22);%0A%09%09%7D%0A%09%09return result.toString();%0A%09%7D%0A%0A
 %09private

fix getting merge commit message