/* UtilLib - Copyright (c) 2008-2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.logging;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Instant;
import java.time.format.DateTimeFormatter;


/**
 *
 * @author Vincent Calame
 */
public class TimeLogger {

    private final static DateTimeFormatter INSTANT_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss,SSS'Z'");

    private final static String SEPARATOR = "\t";
    private final long startTime;
    private final StringBuilder internalBuffer;
    private PrintWriter pw;
    private long previousTime;
    private String currentAction = null;
    private boolean empty = true;

    public TimeLogger(String logName) {
        internalBuffer = new StringBuilder();
        print(logName);
        print(SEPARATOR);
        print(SEPARATOR);
        print("00:00");
        print(SEPARATOR);
        Instant startInstant = Instant.now();
        startTime = startInstant.toEpochMilli();
        print(INSTANT_FORMAT.format(startInstant));
        previousTime = startTime;
    }

    public boolean isEmpty() {
        return empty;
    }

    public void setPrintWriter(PrintWriter pw) {
        if (pw != null) {
            pw.print(internalBuffer.toString());
            pw.flush();
        }
        this.pw = pw;
    }

    public TimeLogger logAction(String actionKey) {
        flushAction();
        print("\n");
        print(actionKey);
        empty = false;
        this.currentAction = actionKey;
        flush();
        return this;
    }

    public TimeLogger log(Exception e) {
        empty = false;
        return logStep("exception@" + e.getLocalizedMessage());
    }

    public TimeLogger logStep(String name) {
        flushAction();
        Instant currentInstant = Instant.now();
        print("\n");
        print(name);
        print(SEPARATOR);
        print(SEPARATOR);
        printIntervalle(currentInstant.toEpochMilli(), startTime);
        print(SEPARATOR);
        print(INSTANT_FORMAT.format(currentInstant));
        flush();
        return this;
    }

    @Override
    public String toString() {
        return internalBuffer.toString();
    }

    private void flushAction() {
        if (currentAction != null) {
            long currentTime = System.currentTimeMillis();
            print(SEPARATOR);
            printIntervalle(currentTime, previousTime);
            print(SEPARATOR);
            printIntervalle(currentTime, startTime);
            previousTime = currentTime;
            currentAction = null;
            flush();
        }
    }

    private void print(String text) {
        internalBuffer.append(text);
        if (pw != null) {
            pw.print(text);
            pw.flush();
        }
    }

    private void flush() {
        if (pw != null) {
            pw.flush();
        }
    }

    public static String toExceptionLogString(String name, Exception e) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter buf = new PrintWriter(stringWriter);
        stringWriter.append(name);
        stringWriter.append(SEPARATOR);
        buf.append(INSTANT_FORMAT.format(Instant.now()));
        buf.append("\n\n");
        e.printStackTrace(buf);
        return stringWriter.toString();
    }

    private void printIntervalle(long currentTime, long oldTime) {
        int diff = (int) (currentTime - oldTime);
        if (diff == 0) {
            print("00:00");
        } else {
            double ms = ((double) diff) / 1000;
            double s = Math.floor(ms);
            ms = (ms - s) * 1000;
            if (s > 0) {
                double mn = Math.floor(s / 60);
                s = s - (mn * 60);
                if (mn < 10) {
                    print("0");
                }
                print(String.valueOf((int) mn));
            } else {
                print("00");
            }
            print(":");
            if (s < 10) {
                print("0");
            }
            print(String.valueOf((int) s));
            if (ms > 0) {
                print(",");
                if (ms < 10) {
                    print("0");
                }
                if (ms < 100) {
                    print("0");
                }
                print(String.valueOf((int) ms));
            }
        }
    }

}
