package com.atlassian.stash.internal.scm.git.command.revlist;

import com.atlassian.bitbucket.commit.MinimalCommit;
import com.atlassian.bitbucket.commit.SimpleMinimalCommit;
import com.atlassian.bitbucket.commit.graph.*;
import com.atlassian.bitbucket.io.EolDetectingLineOutputHandler;
import com.atlassian.bitbucket.scm.CommandOutputHandler;
import com.atlassian.bitbucket.scm.CommandResult;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;

import java.util.Iterator;
import java.util.List;

/**
 * An output handler able to read a rev-list index
 *
 * @since 2.11
 */
public class TraversalRevListOutputHandler
        extends EolDetectingLineOutputHandler
        implements CommandOutputHandler<Void> {

    private static final TraversalContext EMPTY_CONTEXT = new TraversalContext.Builder().build();
    private static final Splitter SPLITTER = Splitter.on(' ');
    private static final TraversalSummary TRAVERSAL_SUMMARY_SUCCESS = new TraversalSummary.Builder(CommandResult.SUCCEEDED).build();
    private static final TraversalSummary TRAVERSAL_SUMMARY_FAILURE = new TraversalSummary.Builder(CommandResult.FAILED).build();

    private final TraversalCallback callback;
    private boolean started;
    private boolean successful;

    public TraversalRevListOutputHandler(TraversalCallback callback) {
        this.callback = callback;
        this.successful = true;
    }

    @Override
    public Void getOutput() {
        if (!started) {
            callback.onStart(EMPTY_CONTEXT);
        }
        callback.onEnd(successful ? TRAVERSAL_SUMMARY_SUCCESS : TRAVERSAL_SUMMARY_FAILURE);
        return null;
    }

    @Override
    protected void processEndByException(int counter) {
        successful = false;
        super.processEndByException(counter);
    }

    @Override
    protected void processLine(int lineNum, String line) {
        if (!started) {
            callback.onStart(EMPTY_CONTEXT);
            started = true;
        }
        Iterator<String> commitIds = SPLITTER.split(line).iterator();

        MinimalCommit current = new SimpleMinimalCommit.Builder(commitIds.next()).build();
        List<MinimalCommit> parents = ImmutableList.copyOf(Iterators.transform(commitIds,
                commitId -> new SimpleMinimalCommit.Builder(commitId).build()));

        CommitGraphNode node = new SimpleCommitGraphNode.Builder()
                .commit(current)
                .parents(parents)
                .build();

        if (callback.onNode(node) == TraversalStatus.FINISH) {
            cancelProcess();
        }
    }
}
