package org.implab.gradle.common.exec.runtime;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.CompletableFuture;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
 * Describes how to redirect input streams. This interface is used to configure
 * lazy redirection. {@link #redirect(OutputStream)} is called when the process
 * is started. Before the process is started the redirection isn't invoked and
 * no resources are allocated or used.
 */
@NonNullByDefault
public interface RedirectFrom {
    CompletableFuture<Void> redirect(OutputStream to);

    /**
     * Read file contents and redirect it to the output stream.
     */
    public static RedirectFrom file(final File file) {
        return to -> CompletableFuture.runAsync(() -> {
            try (var from = new FileInputStream(file); to) {
                from.transferTo(to);
            } catch (Exception e) {
                // silence!
            }
        });
    }

    public static RedirectFrom stream(final InputStream from) {
        return to -> CompletableFuture.runAsync(() -> {
            try (from; to) {
                from.transferTo(to);
            } catch (Exception e) {
                // silence!
            }
        });
    }

    public static RedirectFrom any(final Object output) {
        if (output instanceof File f) {
            return file(f);
        } else if (output instanceof InputStream stm) {
            return stream(stm);
        } else if (output instanceof RedirectFrom self) {
            return self;
        } else {
            throw new IllegalArgumentException("The specified argument type isn't supported: " + output.getClass());
        }
    }

}
