package org.eclipse.compare.internal.core.patch;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.compare.internal.core.ComparePlugin;
import org.eclipse.compare.internal.core.Messages;
import org.eclipse.compare.patch.IFilePatchResult;
import org.eclipse.compare.patch.IHunk;
import org.eclipse.compare.patch.PatchConfiguration;
import org.eclipse.compare.patch.ReaderCreator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.osgi.util.NLS;
public class FileDiffResult implements IFilePatchResult {
private FilePatch2 fDiff;
private boolean fMatches= false;
private boolean fDiffProblem;
private String fErrorMessage;
private Map<Hunk, HunkResult> fHunkResults = new HashMap<>();
private List<String> fBeforeLines, fAfterLines;
private final PatchConfiguration configuration;
private String charset;
public FileDiffResult(FilePatch2 diff, PatchConfiguration configuration) {
super();
this.fDiff = diff;
this.configuration = configuration;
}
public PatchConfiguration getConfiguration() {
return this.configuration;
}
public boolean canApplyHunk(Hunk hunk) {
HunkResult result = getHunkResult(hunk);
return result.isOK() && !this.fDiffProblem;
}
public void refresh(ReaderCreator content, IProgressMonitor monitor) {
this.fMatches= false;
this.fDiffProblem= false;
boolean create= false;
this.charset = Utilities.getCharset(content);
boolean exists = targetExists(content);
if (this.fDiff.getDiffType(getConfiguration().isReversed()) == FilePatch2.ADDITION) {
if ((!exists || isEmpty(content)) && canCreateTarget(content)) {
this.fMatches= true;
} else {
this.fDiffProblem= true;
this.fErrorMessage= Messages.FileDiffResult_0;
}
create= true;
} else {
if (exists) {
this.fMatches= true;
} else {
this.fDiffProblem= true;
this.fErrorMessage= Messages.FileDiffResult_1;
}
}
if (this.fDiffProblem) {
this.fBeforeLines = new ArrayList<>(getLines(content, false));
this.fAfterLines = this.fMatches ? new ArrayList<>() : this.fBeforeLines;
IHunk[] hunks = this.fDiff.getHunks();
for (IHunk h : hunks) {
Hunk hunk = (Hunk) h;
hunk.setCharset(getCharset());
HunkResult result = getHunkResult(hunk);
result.setMatches(false);
}
} else {
patch(getLines(content, create), monitor);
}
if (containsProblems()) {
if (this.fMatches) {
this.fMatches = false;
IHunk[] hunks = this.fDiff.getHunks();
for (IHunk h : hunks) {
Hunk hunk = (Hunk) h;
HunkResult result = getHunkResult(hunk);
if (result.isOK()) {
this.fMatches = true;
break;
}
}
}
}
}
protected boolean canCreateTarget(ReaderCreator content) {
return true;
}
protected boolean targetExists(ReaderCreator content) {
return content != null && content.canCreateReader();
}
protected List<String> getLines(ReaderCreator content, boolean create) {
List<String> lines = LineReader.load(content, create);
return lines;
}
protected boolean isEmpty(ReaderCreator content) {
if (content == null)
return true;
return LineReader.load(content, false).isEmpty();
}
public void patch(List<String> lines, IProgressMonitor monitor) {
this.fBeforeLines = new ArrayList<>();
this.fBeforeLines.addAll(lines);
if (getConfiguration().getFuzz() != 0) {
calculateFuzz(this.fBeforeLines, monitor);
}
int shift= 0;
IHunk[] hunks = this.fDiff.getHunks();
for (IHunk h : hunks) {
Hunk hunk = (Hunk) h;
hunk.setCharset(getCharset());
HunkResult result = getHunkResult(hunk);
result.setShift(shift);
if (result.patch(lines)) {
shift = result.getShift();
}
}
this.fAfterLines = lines;
}
public boolean getDiffProblem() {
return this.fDiffProblem;
}
public boolean containsProblems() {
if (this.fDiffProblem)
return true;
for (HunkResult result : this.fHunkResults.values()) {
if (!result.isOK())
return true;
}
return false;
}
public String getLabel() {
String label= getTargetPath().toString();
if (this.fDiffProblem)
return NLS.bind(Messages.FileDiffResult_2, new String[] {label, this.fErrorMessage});
return label;
}
@Override
public boolean hasMatches() {
return this.fMatches;
}
public List<String> getLines() {
return this.fAfterLines;
}
public int calculateFuzz(List<String> lines, IProgressMonitor monitor) {
if (monitor == null)
monitor = new NullProgressMonitor();
this.fBeforeLines = new ArrayList<>(lines);
if (this.fDiff.getDiffType(getConfiguration().isReversed()) == FilePatch2.ADDITION) {
return -1;
}
int shift= 0;
int highestFuzz = -1;
String name = getTargetPath() != null ? getTargetPath().lastSegment() : "";
IHunk[] hunks = this.fDiff.getHunks();
for (int j = 0; j < hunks.length; j++) {
Hunk h = (Hunk) hunks[j];
monitor.subTask(NLS.bind(Messages.FileDiffResult_3, new String[] {name, Integer.toString(j + 1)}));
HunkResult result = getHunkResult(h);
result.setShift(shift);
int fuzz = result.calculateFuzz(lines, monitor);
shift = result.getShift();
if (fuzz > highestFuzz)
highestFuzz = fuzz;
monitor.worked(1);
}
this.fAfterLines = lines;
return highestFuzz;
}
public IPath getTargetPath() {
return this.fDiff.getStrippedPath(getConfiguration().getPrefixSegmentStripCount(), getConfiguration().isReversed());
}
private HunkResult getHunkResult(Hunk hunk) {
HunkResult result = this.fHunkResults.get(hunk);
if (result == null) {
result = new HunkResult(this, hunk);
this.fHunkResults.put(hunk, result);
}
return result;
}
public List<Hunk> getFailedHunks() {
List<Hunk> failedHunks = new ArrayList<>();
IHunk[] hunks = this.fDiff.getHunks();
for (IHunk hunk : hunks) {
HunkResult result = this.fHunkResults.get(hunk);
if (result != null && !result.isOK())
failedHunks.add(result.getHunk());
}
return failedHunks;
}
public FilePatch2 getDiff() {
return this.fDiff;
}
public List<String> getBeforeLines() {
return this.fBeforeLines;
}
public List<String> getAfterLines() {
return this.fAfterLines;
}
public HunkResult[] getHunkResults() {
List<HunkResult> results = new ArrayList<>();
IHunk[] hunks = this.fDiff.getHunks();
for (IHunk hunk : hunks) {
HunkResult result = this.fHunkResults.get(hunk);
if (result != null) {
results.add(result);
}
}
return results.toArray(new HunkResult[results.size()]);
}
@Override
public InputStream getOriginalContents() {
String contents = LineReader.createString(isPreserveLineDelimeters(), getBeforeLines());
return asInputStream(contents, getCharset());
}
@Override
public InputStream getPatchedContents() {
String contents = LineReader.createString(isPreserveLineDelimeters(), getLines());
return asInputStream(contents, getCharset());
}
@Override
public String getCharset() {
return this.charset;
}
public boolean isPreserveLineDelimeters() {
return false;
}
@Override
public IHunk[] getRejects() {
List<Hunk> failedHunks = getFailedHunks();
return failedHunks.toArray(new IHunk[failedHunks.size()]);
}
@Override
public boolean hasRejects() {
return getFailedHunks().size() > 0;
}
public static InputStream asInputStream(String contents, String charSet) {
byte[] bytes = null;
if (charSet != null) {
try {
bytes = contents.getBytes(charSet);
} catch (UnsupportedEncodingException e) {
ComparePlugin.log(e);
}
}
if (bytes == null) {
bytes = contents.getBytes();
}
return new ByteArrayInputStream(bytes);
}
}