package com.atlassian.bitbucket.mesh.git.content;

import com.atlassian.bitbucket.mesh.git.GitChangeType;
import com.atlassian.bitbucket.mesh.repository.Repository;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public interface DiffCallback {

    /**
     * Called to indicate a binary file differs. The exact differences cannot be effectively conveyed, however, so
     * no hunks/segments will be provided for binary files.
     *
     * @param src the source binary file
     * @param dst the destination binary file
     */
    void onBinary(@Nullable String src, @Nullable String dst);

    /**
     * Called upon reaching the end of the current overall diff, indicating no more changes exist for the current
     * source/destination pair.
     *
     * @param truncated {@code true} if any segment or hunk in the diff had to be truncated; otherwise, {@code false}
     */
    void onDiffEnd(boolean truncated);

    /**
     * Called to mark the start of an overall diff. The source and destination paths being compared, relative to their
     * containing {@link Repository repository}, are provided.
     * <ul>
     * <li>For {@link GitChangeType#ADD added} files, the {@code src} path will be {@code null}</li>
     * <li>For {@link GitChangeType#DELETE deleted} files, the {@code dst} path will be {@code null}</li>
     * <li>For all other {@link GitChangeType changes}, both paths will be provided</li>
     * </ul>
     *
     * @param src the source file being compared
     * @param dst the destination file being compared
     */
    void onDiffStart(@Nullable String src, @Nullable String dst);

    /**
     * Called upon reaching the end of a hunk of segments within the current overall diff.
     *
     * @param truncated {@code true} if any segment in the hunk had to be truncated; otherwise, {@code false}
     */
    void onHunkEnd(boolean truncated);

    /**
     * Called to mark the start of a new hunk within the current overall diff, containing one or more contiguous
     * segments of lines anchored at the provided line numbers in the source and destination files.
     *
     * @param srcLine the line in the source file at which the hunk starts
     * @param srcSpan the number of lines spanned by this hunk in the source file
     * @param dstLine the line in the destination file at which the hunk starts
     * @param dstSpan the number of lines spanned by this hunk in the destination file
     * @param context an optional context, such as a method or class name, for the hunk's lines
     */
    void onHunkStart(int srcLine, int srcSpan, int dstLine, int dstSpan, @Nullable String context);

    /**
     * Called upon reaching the end of a segment within the current hunk, where a segment may end either because lines
     * with a different type were encountered or because there are no more contiguous lines in the hunk.
     * <p>
     * Note: Internal restrictions may prevent streaming full segments if they are overly large. For example, if a new
     * file containing tens of thousands of lines is added (or an existing file of such size is deleted), the resulting
     * segment may be truncated.
     *
     * @param truncated {@code true} if the overall segment exceeded the maximum allowed lines, indicating one or more
     *                  lines were omitted from the segment; otherwise {@code false} to indicate all lines were sent
     */
    void onSegmentEnd(boolean truncated);

    /**
     * Called to process a line within the current segment.
     * <p>
     * Note: Internal restrictions may prevent receiving the full line if it contains too many characters. When this
     * happens {@code truncated} will be set to {@code true} to indicate the line is not complete.
     *
     * @param line      a single line of content
     * @param truncated {@code true} if the line exceeded the maximum allowed length and was truncated; otherwise,
     *                  {@code false} to indicate the line is complete
     */
    void onSegmentLine(@Nonnull String line, boolean truncated);

    /**
     * Called to mark the start of a new segment within the current hunk, containing one or more contiguous lines which
     * all share the same {@link DiffSegmentType type}.
     *
     * @param type the shared type for all lines in the new segment
     */
    void onSegmentStart(@Nonnull DiffSegmentType type);
}
