package com.atlassian.stash.internal.comment;

import com.atlassian.bitbucket.content.Change;
import com.atlassian.bitbucket.content.ChangeCallback;
import com.atlassian.bitbucket.content.ChangeContext;
import com.atlassian.bitbucket.content.ChangeSummary;
import com.atlassian.stash.internal.content.InternalChangeLocation;

import com.atlassian.bitbucket.property.PropertyMap;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Map;

/**
 * Wraps a {@link ChangeCallback} and applies {@link CommentCounts count} information to changes as they are streamed.
 * <p>
 * If the {@link Change#getPath() path} and {@link Change#getSrcPath() srcPath} combination for a given {@link Change}
 * match a {@link InternalChangeLocation change location} from the map of counts supplied during construction,
 * {@link PropertyMap properties} with the number of active and orphaned comment counts on that path are added to the
 * {@link Change change}. Otherwise, the change will be streamed as-is.
 *
 * @since 2.0
 */
public class CommentCountChangeCallback implements ChangeCallback {

    private final CommentCountChangeTransform transformer;
    private final ChangeCallback delegate;

    public CommentCountChangeCallback(@Nonnull ChangeCallback delegate,
                                      @Nonnull Map<InternalChangeLocation, CommentCounts> countsByLocation) {
        this.delegate = delegate;

        transformer = new CommentCountChangeTransform(countsByLocation);
    }

    /**
     * Applies {@link CommentCounts count} information to the provided {@link Change}, if available, before delegating
     * the wrapped {@link ChangeCallback}.
     *
     * @param change the change to process
     * @return {@code true} or {@code false}, as returned by the delegate
     * @throws IOException propagated if thrown by the delegate
     */
    @Override
    public boolean onChange(@Nonnull Change change) throws IOException {
        return delegate.onChange(transformer.apply(change));
    }

    @Override
    public void onEnd(@Nonnull ChangeSummary summary) throws IOException {
        delegate.onEnd(summary);
    }

    /**
     * Delegates to the wrapped {@link ChangeCallback}.
     *
     * @param context context describing the change tree
     * @throws IOException propagated if thrown by the delegate
     */
    @Override
    public void onStart(@Nonnull ChangeContext context) throws IOException {
        delegate.onStart(context);
    }
}
