package com.atlassian.stash.internal.repository.sync;

import com.atlassian.bitbucket.repository.sync.RejectedRefState;
import com.atlassian.bitbucket.scm.CommandOutputHandler;
import com.atlassian.utils.process.LineOutputHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;

/**
 * Parses the output of {@code git rev-list --left-right --count} to determine the correct {@link RejectedRefState}
 * for a pair of branches.
 * <p>
 * The command run, when using this output handler, is <i>required</i> to put the upstream branch on the right-hand
 * side. That means the left-hand count will be commits on the local branch and not on upstream, and the right-hand
 * count will be commits on the upstream branch and not on the local branch. If the branches are not ordered
 * correctly, the wrong {@link RejectedRefState} will be chosen.
 *
 * @since 2.6
 */
public class StateRevListCommandOutputHandler
        extends LineOutputHandler
        implements CommandOutputHandler<RejectedRefState> {

    private static final Logger log = LoggerFactory.getLogger(StateRevListCommandOutputHandler.class);

    private RejectedRefState state;

    @Nullable
    @Override
    public RejectedRefState getOutput() {
        return state;
    }

    @Override
    protected void processLine(int lineNum, String line) {
        int split = line.indexOf("\t");
        if (split == -1) {
            throw new IllegalStateException("Output [" + line + "] does not match the expected format");
        }

        int localCount = Integer.parseInt(line.substring(0, split));
        int upstreamCount = Integer.parseInt(line.substring(split + 1));
        if (upstreamCount > 0) {
            if (localCount > 0) {
                //There are commits on both branches that are not on the other, so the two refs have diverged
                state = RejectedRefState.DIVERGED;
            } else {
                log.debug("That's odd; the local branch is still behind its upstream?");
            }
        } else if (localCount > 0) {
            //There are no commits upstream that are not on the local branch, but the local branch does have have
            //one or more commits which are not on the upstream, so the local ref is ahead
            state = RejectedRefState.AHEAD;
        } else {
            log.debug("That's odd; the local branch is in sync with its upstream?");
        }
    }
}
