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

import com.google.common.io.LineProcessor;
import com.google.errorprone.annotations.MustBeClosed;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;

/**
 * Describes a collection of {@code stdin} data provided to on a {@link HookRequest hook request}. This abstraction
 * allows the underlying hook code to employ different approaches for buffering {@code stdin}.
 */
public interface HookStdin {

    /**
     * @return {@code true} if {@code stdin} has been {@link #release released}; otherwise, {@code false}
     */
    boolean isReleased();

    /**
     * Open a <i>new</i> stream to read {@code stdin}. This method may be called multiple times and each will
     * receive a <i>separate</i> stream, allowing {@code stdin} to be read multiple times if necessary.
     *
     * @return a <i>new</i> stream over {@code stdin}
     * @throws IllegalStateException if {@code stdin} has been {@link #release released}
     * @throws IOException if {@code stdin} cannot be opened
     */
    @MustBeClosed
    @Nonnull
    InputStream open() throws IOException;

    /**
     * Reads the full {@code stdin} into memory, decoded as UTF-8.
     *
     * @return UTF-8-decoded {@code stdin}
     * @throws IOException if {@code stdin} cannot be opened or read
     */
    @Nonnull
    String read() throws IOException;

    /**
     * Streams {@code stdin}, decoded as UTF-8, to the provided {@link LineProcessor} and returns its
     * {@link LineProcessor#getResult result}.
     *
     * @param processor the processor to apply to the UTF-8-decoded {@code stdin}
     * @param <T> the type of result the processor returns
     * @return the processor's result
     * @throws IOException if {@code stdin} cannot be opened or read
     */
    <T> T readLines(@Nonnull LineProcessor<T> processor) throws IOException;

    /**
     * Releases the buffered {@code stdin}. Handlers are <i>not</i> required to call this method, but are
     * <i>encouraged</i> to do so when they know they no longer need access to {@code stdin} to allow any
     * memory or other resources it's consuming to be released.
     */
    void release();

    /**
     * @return {@code stdin}'s size in bytes, which may be useful for some optimizations
     */
    long size();
}
