package com.atlassian.bitbucket.mesh.network;

import com.atlassian.bitbucket.mesh.rpc.v1.RpcPartition;
import com.atlassian.bitbucket.mesh.util.BuilderSupport;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMap;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;

import static java.util.Objects.requireNonNull;

public class Partition {

    private final String id;
    private final Map<String, PartitionReplica> replicas;

    private Partition(Builder builder) {
        id = builder.id;
        replicas = builder.replicas.build();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Partition that = (Partition) o;
        return id.equals(that.id);
    }

    /**
     * @return the partition ID
     */
    @Nonnull
    public String getId() {
        return id;
    }

    /**
     * @param id the replica ID
     * @return the partition replica matching the provided ID, or {@code null} if not found
     */
    @Nullable
    public PartitionReplica getReplica(@Nonnull String id) {
        return replicas.get(requireNonNull(id, "id"));
    }

    /**
     * @return the list of replicas for this partition
     */
    @Nonnull
    public Collection<PartitionReplica> getReplicas() {
        return replicas.values();
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Nonnull
    public RpcPartition toPartition() {
        return RpcPartition.newBuilder()
                .setId(id)
                .addAllReplicas(Collections2.transform(replicas.values(), PartitionReplica::toPartitionReplica))
                .build();
    }

    @Override
    public String toString() {
        return "Partition{" +
                "id=" + id +
                ", replicas=" + replicas +
                '}';
    }

    public static class Builder extends BuilderSupport {

        private final String id;
        private final ImmutableMap.Builder<String, PartitionReplica> replicas;

        public Builder(@Nonnull String id) {
            this.id = requireNonBlank(id, "id");
            replicas = ImmutableMap.builder();
        }

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

        @Nonnull
        public Builder replicas(@Nullable PartitionReplica value, @Nullable PartitionReplica... moreValues) {
            if (value != null) {
                replicas.put(value.getId(), value);
            }
            if (moreValues != null) {
                for (PartitionReplica replica : moreValues) {
                    if (replica != null) {
                        replicas.put(replica.getId(), replica);
                    }
                }
            }
            return this;
        }
    }
}
