package com.atlassian.bitbucket.mesh.io;

import com.google.common.base.MoreObjects;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;

import static java.util.Objects.requireNonNull;

public class SyncFileTreeParameters {

    private static final SyncFileTreeCallback DEFAULT_CALLBACK = new SyncFileTreeCallback() {

        @Override
        public void onConflict(@Nonnull Path source, @Nonnull BasicFileAttributes attrs, @Nonnull Path destination) {
            //No op
        }
    };

    private final boolean allowHardLinks;
    private final SyncFileTreeCallback callback;
    private final Path destination;
    private final boolean detectMissing;
    private final Instant modifiedSince;
    private final boolean replaceExisting;
    private final Path source;

    private SyncFileTreeParameters(Builder builder) {
        allowHardLinks = builder.allowHardLinks;
        callback = MoreObjects.firstNonNull(builder.callback, DEFAULT_CALLBACK);
        destination = builder.destination;
        detectMissing = builder.detectMissing;
        modifiedSince = builder.modifiedSince;
        replaceExisting = builder.replaceExisting;
        source = builder.source;
    }

    @Nonnull
    public SyncFileTreeCallback getCallback() {
        return callback;
    }

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

    @Nullable
    public Instant getModifiedSince() {
        return modifiedSince;
    }

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

    public boolean isAllowHardLinks() {
        return allowHardLinks;
    }

    public boolean isDetectMissing() {
        return detectMissing;
    }

    public boolean isReplaceExisting() {
        return replaceExisting;
    }

    public static class Builder {

        private final Path destination;
        private final Path source;

        private boolean allowHardLinks;
        private SyncFileTreeCallback callback;
        private boolean detectMissing;
        private Instant modifiedSince;
        private boolean replaceExisting;

        public Builder(@Nonnull Path source, @Nonnull Path destination) {
            this.destination = requireNonNull(destination, "destination");
            this.source = requireNonNull(source, "source");

            allowHardLinks = true;
        }

        @Nonnull
        public SyncFileTreeParameters build() {
            return new SyncFileTreeParameters(this);
        }

        @Nonnull
        public Builder allowHardLinks(boolean value) {
            allowHardLinks = value;
            return this;
        }

        @Nonnull
        public Builder callback(@Nullable SyncFileTreeCallback value) {
            callback = value;
            return this;
        }

        @Nonnull
        public Builder detectMissing(boolean value) {
            detectMissing = value;
            return this;
        }

        @Nonnull
        public Builder modifiedSince(@Nullable Instant value) {
            modifiedSince = value;
            return this;
        }

        @Nonnull
        public Builder replaceExisting(boolean value) {
            replaceExisting = value;
            return this;
        }
    }
}
