package com.atlassian.bitbucket.mesh.git.hook;

import com.google.common.io.CharStreams;
import com.google.common.io.LineProcessor;

import javax.annotation.Nonnull;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.util.Objects.requireNonNull;

abstract class AbstractHookStdin implements HookStdin {

    private final AtomicBoolean released;
    private final long size;

    AbstractHookStdin(long size) {
        this.size = size;

        released = new AtomicBoolean();
    }

    @Override
    public boolean isReleased() {
        return released.get();
    }

    @Nonnull
    @Override
    public InputStream open() throws IOException {
        if (isReleased()) {
            throw new IllegalStateException("Hook stdin has already been released");
        }

        return doOpen();
    }

    @Nonnull
    @Override
    public String read() throws IOException {
        try (Reader reader = openReader()) {
            return CharStreams.toString(reader);
        }
    }

    @Override
    public <T> T readLines(@Nonnull LineProcessor<T> processor) throws IOException {
        requireNonNull(processor, "processor");

        try (Reader reader = openReader()) {
            return CharStreams.readLines(reader, processor);
        }
    }

    @Override
    public void release() {
        if (released.compareAndSet(false, true)) {
            doRelease();
        }
    }

    @Override
    public long size() {
        return size;
    }

    @Nonnull
    abstract InputStream doOpen() throws IOException;

    void doRelease() {
    }

    private Reader openReader() throws IOException {
        return new BufferedReader(new InputStreamReader(open(), StandardCharsets.UTF_8));
    }
}
