package net.sf.jabref.logic.util.strings;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import difflib.Delta;
import difflib.DiffUtils;

public class DiffHighlighting {

    private static final String ADDITION_START = "<span class=add>";
    private static final String REMOVAL_START = "<span class=del>";
    private static final String CHANGE_START = "<span class=change>";
    private static final String TAG_END = "</span>";

    public static final String HTML_START = "<html><body>";
    public static final String HTML_END = "</body></html>";


    public static String generateDiffHighlighting(String baseString, String modifiedString, String separator) {
        Objects.requireNonNull(separator);
        if ((baseString != null) && (modifiedString != null)) {
            List<String> stringList = new ArrayList<>(Arrays.asList(baseString.split(separator)));
            List<Delta<String>> deltaList = new ArrayList<>(
                    DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas());
            Collections.reverse(deltaList);
            for (Delta<String> delta : deltaList) {
                int startPos = delta.getOriginal().getPosition();
                List<String> lines = delta.getOriginal().getLines();
                int offset = 0;
                switch (delta.getType()) {
                case CHANGE:
                    for (String line : lines) {
                        stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.REMOVAL_START : "") + line);
                        offset++;
                    }
                    stringList.set((startPos + offset) - 1,
                            stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END + separator + DiffHighlighting.ADDITION_START
                                    + String.join(separator, delta.getRevised().getLines()) + DiffHighlighting.TAG_END);
                    break;
                case DELETE:
                    for (String line : lines) {
                        stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.REMOVAL_START : "") + line);
                        offset++;
                    }
                    stringList.set((startPos + offset) - 1,
                            stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END);
                    break;
                case INSERT:
                    stringList.add(delta.getOriginal().getPosition(),
                            DiffHighlighting.ADDITION_START + String.join(separator, delta.getRevised().getLines()) + DiffHighlighting.TAG_END);
                    break;
                default:
                    break;
                }
            }
            return String.join(separator, stringList);
        }
        return modifiedString;
    }

    public static String generateSymmetricHighlighting(String baseString, String modifiedString, String separator) {
        if ((baseString != null) && (modifiedString != null)) {
            List<String> stringList = new ArrayList<>(Arrays.asList(baseString.split(separator)));
            List<Delta<String>> deltaList = new ArrayList<>(DiffUtils
                    .diff(stringList, new ArrayList<>(Arrays.asList(modifiedString.split(separator)))).getDeltas());
            Collections.reverse(deltaList);
            for (Delta<String> delta : deltaList) {
                int startPos = delta.getOriginal().getPosition();
                List<String> lines = delta.getOriginal().getLines();
                int offset = 0;
                switch (delta.getType()) {
                case CHANGE:
                    for (String line : lines) {
                        stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.CHANGE_START : "") + line);
                        offset++;
                    }
                    stringList.set((startPos + offset) - 1, stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END);
                    break;
                case DELETE:
                    for (String line : lines) {
                        stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.ADDITION_START : "") + line);
                        offset++;
                    }
                    stringList.set((startPos + offset) - 1, stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END);
                    break;
                case INSERT:
                    break;
                default:
                    break;
                }
            }
            return String.join(separator, stringList);
        }
        return modifiedString;
    }

}
