package com.elphel.imagej.common;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.file.Path;

/**
 * Tee System.out/System.err to a per-scene log file while preserving console output.
 * Usage:
 *   LogTee.install(); // once at startup
 *   LogTee.setSceneLog(path); // enable per-scene logging (append)
 *   LogTee.clearSceneLog();   // stop file logging
 */
public final class LogTee {
    private static final Object LOCK = new Object();
    private static final PrintStream ORIGINAL_OUT = System.out;
    private static final PrintStream ORIGINAL_ERR = System.err;
    private static volatile PrintStream fileStream = null;
    private static volatile Path sceneLogPath = null;
    private static volatile boolean installed = false;

    private LogTee() {
    }

    public static void install() {
        synchronized (LOCK) {
            if (installed) return;
            System.setOut(new PrintStream(new TeeStream(ORIGINAL_OUT), true));
            System.setErr(new PrintStream(new TeeStream(ORIGINAL_ERR), true));
            installed = true;
        }
    }

    public static void setSceneLog(Path path) throws IOException {
        if (path == null) {
            clearSceneLog();
            return;
        }
        synchronized (LOCK) {
            closeFileStream();
            fileStream = new PrintStream(new FileOutputStream(path.toFile(), true), true);
            sceneLogPath = path;
        }
    }

    public static void clearSceneLog() {
        synchronized (LOCK) {
            closeFileStream();
            fileStream = null;
            sceneLogPath = null;
        }
    }

    public static Path getSceneLog() {
        return sceneLogPath;
    }

    private static void closeFileStream() {
        if (fileStream != null) {
            fileStream.flush();
            fileStream.close();
        }
    }

    private static final class TeeStream extends OutputStream {
        private final PrintStream console;

        private TeeStream(PrintStream console) {
            this.console = console;
        }

        @Override
        public void write(int b) throws IOException {
            console.write(b);
            PrintStream fs = fileStream;
            if (fs != null) fs.write(b);
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            console.write(b, off, len);
            PrintStream fs = fileStream;
            if (fs != null) fs.write(b, off, len);
        }

        @Override
        public void flush() throws IOException {
            console.flush();
            PrintStream fs = fileStream;
            if (fs != null) fs.flush();
        }
    }
}
