package com.atlassian.bitbucket.repository.sync;

import com.atlassian.bitbucket.event.repository.RepositoryRefsChangedEvent;
import com.atlassian.event.api.AsynchronousPreferred;
import com.atlassian.bitbucket.event.repository.AbstractRepositoryRefsChangedEvent;
import com.atlassian.bitbucket.repository.RefChange;
import com.atlassian.bitbucket.repository.Repository;
import com.google.common.collect.ImmutableList;

import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;

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

/**
 * Raised whenever refs are synchronized between two repositories. Synchronization can either be automatic, in response
 * to a {@link RepositoryRefsChangedEvent RepositoryRefsChangedEvent}, or it can be manual,
 * in response to a developer's {@link RefSyncRequest}.
 * <p>
 * When automatic syncing is being performed, it starts from a set of upstream {@link RefChange changes} and attempts
 * to apply the same changes to all interested repositories. If <i>none</i> of the upstream changes can be applied,
 * this event is still raised. It will contain no {@link #getRefChanges() changes} of its own, but will include the
 * changes it attempted as {@link #getRejectedRefs() rejected refs}.
 */
@AsynchronousPreferred
public class RefsSynchronizedEvent extends AbstractRepositoryRefsChangedEvent {

    private final Collection<RejectedRef> rejectedRefs;
    private final Repository upstream;
    private final Collection<RefChange> upstreamChanges;

    public RefsSynchronizedEvent(@Nonnull Object source, @Nonnull Repository repository,
                                 @Nonnull Repository upstream, @Nonnull RefChange refChange) {
        this(source, repository, Collections.singleton(refChange), Collections.<RejectedRef>emptySet(),
                upstream, Collections.<RefChange>emptySet());
    }

    public RefsSynchronizedEvent(@Nonnull Object source, @Nonnull Repository repository,
                                 @Nonnull Collection<RefChange> refChanges, @Nonnull Iterable<RejectedRef> rejectedRefs,
                                 @Nonnull Repository upstream, @Nonnull Iterable<RefChange> upstreamChanges) {
        super(source, repository, refChanges);

        this.rejectedRefs = ImmutableList.copyOf(checkNotNull(rejectedRefs, "rejectedRefs"));
        this.upstream = checkNotNull(upstream, "upstream");
        this.upstreamChanges = ImmutableList.copyOf(checkNotNull(upstreamChanges, "upstreamChanges"));
    }

    @Nonnull
    public Collection<RejectedRef> getRejectedRefs() {
        return rejectedRefs;
    }

    @Nonnull
    public Repository getUpstream() {
        return upstream;
    }

    @Nonnull
    public Collection<RefChange> getUpstreamChanges() {
        return upstreamChanges;
    }
}
