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

import com.atlassian.bitbucket.mesh.git.batch.BatchChange;
import com.atlassian.bitbucket.mesh.git.batch.BatchChangeType;
import com.atlassian.bitbucket.mesh.io.NullTerminatedReader;
import com.atlassian.bitbucket.mesh.io.NullTerminatedWriter;

import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.UncheckedIOException;

/**
 * A {@code git cat-file --batch-check} handler that reads metadata from a file, feeds it to {@code git cat-file}
 * and then writes the same metadata, augmented with the file size, to another file.
 */
public class BatchCheckCatFileStdioHandler extends AbstractBatchCheckCatFileStdioHandler<Void> {

    private final NullTerminatedReader reader;
    private final NullTerminatedWriter writer;

    private BatchChange batchChange;

    public BatchCheckCatFileStdioHandler(BufferedReader reader, BufferedWriter writer) {
        this.reader = new NullTerminatedReader(reader);
        this.writer = new NullTerminatedWriter(writer);
    }

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

    @Override
    protected String getNextObjectId() {
        try {
            while (true) { //Loop to handle deletions
                batchChange = BatchChange.read(reader);
                if (batchChange == null) {
                    return null; //End of input
                }
                if (batchChange.getChangeType() == BatchChangeType.DELETE) {
                    BatchChange.write(batchChange, 0L, writer);
                    continue; //Read the next ID
                }

                //Otherwise, for any other change type, request the object to get its size
                return batchChange.getContentId();
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Failed reading next file change", e);
        }
    }

    @Override
    protected void onMissing(@Nonnull String objectId) {
        throw new IllegalStateException("Object with ID " + objectId + " was missing");
    }

    @Override
    protected void onObject(@Nonnull BatchHeader header) {
        try {
            BatchChange.write(batchChange, header.getSize(), writer);
        } catch (IOException e) {
            throw new UncheckedIOException("Failed writing file change for [" + header.getObjectId() + "]", e);
        }
    }
}
