package com.atlassian.bitbucket.mesh.git.builder.revlist;

import com.atlassian.bitbucket.mesh.git.commit.CommitGraphNode;
import com.atlassian.bitbucket.mesh.git.commit.TraversalCallback;
import com.atlassian.bitbucket.mesh.git.commit.TraversalStatus;
import com.atlassian.bitbucket.mesh.process.OsProcess;
import com.atlassian.bitbucket.mesh.process.handler.AbstractLineStdioHandler;
import com.atlassian.bitbucket.mesh.process.handler.LineEncoder;
import com.google.common.base.Splitter;

import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;

public class TraversalRevListStdioHandler extends AbstractLineStdioHandler<Void> {

    private static final Splitter SPLITTER = Splitter.on(' ');

    private final TraversalCallback callback;
    private final LineEncoder stdinEncoder;

    public TraversalRevListStdioHandler(TraversalCallback callback) {
        this(null, callback);
    }

    public TraversalRevListStdioHandler(Stream<String> stdin, TraversalCallback callback) {
        super(UTF_8);

        this.callback = callback;

        stdinEncoder = stdin == null ? null : new LineEncoder(stdin, UTF_8);
    }

    @Override
    public Void getResult() {
        return null;
    }

    @Override
    public void onStart(@Nonnull OsProcess process) {
        super.onStart(process);

        if (stdinEncoder != null && stdinEncoder.hasMore()) {
            process.wantWrite();
        } else {
            //stdinEncoder is null, or empty
            process.closeStdin(false);
        }
    }

    @Override
    public boolean onStdinReady(@Nonnull ByteBuffer buffer) {
        if (stdinEncoder.encodeTo(buffer)) {
            return true;
        }
        closeStdin();
        return false;
    }

    @Override
    protected boolean onStdout(@Nonnull String line, boolean truncated) {
        Iterator<String> commitIds = SPLITTER.split(line).iterator();
        if (commitIds.hasNext()) {
            String commitId = commitIds.next();
            return callback.onNode(new CommitGraphNode(commitId, commitIds)) == TraversalStatus.CONTINUE;
        }
        return true;
    }
}
