package com.atlassian.bitbucket.content;

import com.atlassian.bitbucket.property.SimplePropertySupport;
import com.google.common.collect.ImmutableList;
import org.apache.commons.collections.CollectionUtils;

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

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

public class SimpleDiff extends SimplePropertySupport implements Diff {

    private final boolean binary;
    private final Path destination;
    private final List<DiffHunk> hunks;
    private final Path source;
    private final boolean truncated;

    private SimpleDiff(Builder builder) {
        super(builder);

        this.binary = builder.binary;
        this.destination = builder.destination;
        this.hunks = checkNotNull(builder.hunks.build(), "hunks");
        this.source = builder.source;
        this.truncated = builder.truncated;
    }

    @Override
    public Path getDestination() {
        return destination;
    }

    @Nonnull
    @Override
    public List<DiffHunk> getHunks() {
        return hunks;
    }

    @Override
    public Path getSource() {
        return source;
    }

    @Override
    public boolean isBinary() {
        return binary;
    }

    @Override
    public boolean isTruncated() {
        return truncated;
    }

    public static final class Builder extends AbstractPropertyBuilder<Builder> {

        private final ImmutableList.Builder<DiffHunk> hunks = ImmutableList.builder();

        private boolean binary;
        private Path destination;
        private Path source;
        private boolean truncated;

        public Builder() {
        }

        public Builder(Diff diff) {
            super(diff);

            binary = diff.isBinary();
            destination = diff.getDestination();
            source = diff.getSource();
            truncated = diff.isTruncated();

            List<DiffHunk> h = diff.getHunks();
            if (CollectionUtils.isNotEmpty(h)) {
                hunks.addAll(h);
            }
        }

        public Builder binary(boolean value) {
            binary = value;

            return this;
        }

        public SimpleDiff build() {
            checkState(destination != null || source != null, "A destination or source path is required");

            return new SimpleDiff(this);
        }

        public Builder destination(@Nonnull Path value) {
            destination = checkNotNull(value, "destination");

            return this;
        }

        public Builder destination(@Nonnull String value) {
            return destination(new SimplePath(checkNotNull(value, "destination")));
        }

        public Builder hunk(@Nonnull DiffHunk value) {
            hunks.add(value);

            return this;
        }

        public Builder hunks(@Nonnull DiffHunk value, @Nonnull DiffHunk... values) {
            hunks.add(value)
                    .add(values);

            return this;
        }

        public Builder hunks(Iterable<DiffHunk> value) {
            if (value != null) {
                hunks.addAll(value);
            }

            return this;
        }

        public Builder source(@Nonnull Path value) {
            source = checkNotNull(value, "source");

            return this;
        }

        public Builder source(@Nonnull String value) {
            return source(new SimplePath(checkNotNull(value, "source")));
        }

        public Builder truncated(boolean value) {
            truncated = value;

            return this;
        }

        @Nonnull
        @Override
        protected Builder self() {
            return this;
        }
    }
}
