package com.atlassian.bitbucket.scm;

import com.atlassian.bitbucket.content.DiffContext;
import com.atlassian.bitbucket.content.DiffWhitespace;
import com.google.common.collect.ImmutableSet;

import javax.annotation.Nonnull;
import java.util.Set;

import static com.google.common.base.Preconditions.checkNotNull;

public class AbstractDiffCommandParameters extends AbstractCommandParameters {

    public static final int DEFAULT_CONTEXT_LINES = -1;

    private final int contextLines;
    private final int maxLineLength;
    private final int maxLines;
    private final Set<String> paths;
    private final DiffWhitespace whitespace;

    public AbstractDiffCommandParameters(int maxLineLength, int maxLines, int contextLines, DiffWhitespace whitespace,
                                         Set<String> paths) {
        this.contextLines = contextLines;
        this.maxLineLength = maxLineLength;
        this.maxLines = maxLines;
        this.paths = paths;
        this.whitespace = whitespace;
    }

    public int getContextLines() {
        return contextLines;
    }

    public int getMaxLineLength() {
        return maxLineLength;
    }

    public int getMaxLines() {
        return maxLines;
    }

    @Nonnull
    public Set<String> getPaths() {
        return paths;
    }

    public boolean hasContextLines() {
        return contextLines != DEFAULT_CONTEXT_LINES;
    }

    public boolean hasPaths() {
        return !paths.isEmpty();
    }

    /**
     * @return optional flag to potentially ignore whitespace
     */
    @Nonnull
    public DiffWhitespace getWhitespace() {
        return whitespace;
    }

    /**
     * Appends common attributes to the provided {@link DiffContext.Builder} before building
     * it and returning the final {@link DiffContext}.
     *
     * @param builder the starting builder to apply common attributes to before building
     * @return the {@link DiffContext} from the provided builder
     */
    @Nonnull
    protected DiffContext toContext(@Nonnull DiffContext.Builder builder) {
        return checkNotNull(builder, "builder").contextLines(getContextLines())
                .maxLineLength(getMaxLineLength())
                .maxLines(getMaxLines())
                .whitespace(getWhitespace())
                .build();
    }

    public abstract static class AbstractBuilder<B extends AbstractBuilder<B>> {

        protected final ImmutableSet.Builder<String> paths;

        protected int contextLines;
        protected int maxLineLength;
        protected int maxLines;
        protected DiffWhitespace whitespace;

        public AbstractBuilder() {
            contextLines = DEFAULT_CONTEXT_LINES;
            paths = ImmutableSet.builder();
            whitespace = DiffWhitespace.SHOW;
        }

        public B contextLines(int value) {
            contextLines = value;

            return self();
        }

        public B defaultContextLines() {
            contextLines = DEFAULT_CONTEXT_LINES;

            return self();
        }

        public B maxLineLength(int value) {
            maxLineLength = value;

            return self();
        }

        public B maxLines(int value) {
            maxLines = value;

            return self();
        }

        public B path(String value) {
            addIf(NOT_BLANK, paths, value);

            return self();
        }

        public B paths(Iterable<String> values) {
            addIf(NOT_BLANK, paths, values);

            return self();
        }

        public B paths(String value, String... values) {
            addIf(NOT_BLANK, paths, value, values);

            return self();
        }

        /**
         * @param value whitespace mode for showing diff
         * @return {@code this}
         */
        public B whitespace(@Nonnull DiffWhitespace value) {
            whitespace = checkNotNull(value, "whitespace");

            return self();
        }

        protected abstract B self();
    }
}
