/*
 * Copyright (c) 2022 MiLaboratories Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.milaboratory.util;

import java.io.FileNotFoundException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.concurrent.atomic.AtomicLong;

public final class ReportHelper {
    public static final DecimalFormatSymbols DFS;
    public static final DecimalFormat PERCENT_FORMAT;

    static {
        DFS = new DecimalFormatSymbols();
        DFS.setNaN("NaN");
        DFS.setInfinity("Inf");
        PERCENT_FORMAT = new DecimalFormat("#.##", DFS);
    }

    public static final ReportHelper STDOUT = new ReportHelper(System.out, true);
    public static final ReportHelper STDERR = new ReportHelper(System.err, true);

    private final PrintStream printStream;
    private final String linePrefix;
    private final boolean stdout;

    public ReportHelper(String fileName) {
        this(fileName, "");
    }

    public ReportHelper(String fileName, String linePrefix) {
        try {
            this.printStream = new PrintStream(fileName);
            this.linePrefix = linePrefix;
            this.stdout = false;
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public ReportHelper(OutputStream outputStream, boolean stdout) {
        this(outputStream, "", stdout);
    }

    public ReportHelper(OutputStream outputStream, String linePrefix, boolean stdout) {
        this.printStream = new PrintStream(outputStream);
        this.linePrefix = linePrefix;
        this.stdout = stdout;
    }

    public ReportHelper(PrintStream printStream, boolean stdout) {
        this(printStream, "", stdout);
    }

    public ReportHelper(PrintStream printStream, String linePrefix, boolean stdout) {
        this.printStream = printStream;
        this.linePrefix = linePrefix;
        this.stdout = stdout;
    }

    public boolean isStdout() {
        return stdout;
    }

    public ReportHelper writeLine(String line) {
        printStream.println(line);
        return this;
    }

    public ReportHelper writeField(String fieldName, Object value) {
        printStream.println(linePrefix + fieldName + ": " +
                value.toString().replace("\n", "\n" + linePrefix));
        return this;
    }

    public ReportHelper writeNotNullField(String fieldName, Object value) {
        if (value != null)
            writeField(fieldName, value);
        return this;
    }

    public ReportHelper writePercentField(String fieldName, long value, long total) {
        double percent = 100.0 * value / total;
        printStream.println(linePrefix + fieldName + ": " + PERCENT_FORMAT.format(percent) + "%");
        return this;
    }

    public ReportHelper writePercentAndAbsoluteField(String fieldName, long value, long total) {
        double percent = 100.0 * value / total;
        printStream.println(linePrefix + fieldName + ": " + value + " (" + PERCENT_FORMAT.format(percent) + "%)");
        return this;
    }

    public ReportHelper writePercentAndAbsoluteFieldNonZero(String fieldName, long value, long total) {
        if (value == 0)
            return this;
        double percent = 100.0 * value / total;
        printStream.println(linePrefix + fieldName + ": " + value + " (" + PERCENT_FORMAT.format(percent) + "%)");
        return this;
    }

    public ReportHelper writePercentAndAbsoluteField(String fieldName, double value, double total) {
        double percent = 100.0 * value / total;
        printStream.println(linePrefix + fieldName + ": " + value + " (" + PERCENT_FORMAT.format(percent) + "%)");
        return this;
    }

    public ReportHelper writePercentField(String fieldName, AtomicLong value, long total) {
        writePercentField(fieldName, value.get(), total);
        return this;
    }

    public ReportHelper writePercentAndAbsoluteField(String fieldName, AtomicLong value, long total) {
        writePercentAndAbsoluteField(fieldName, value.get(), total);
        return this;
    }

    public ReportHelper end() {
        printStream.println("======================================");
        return this;
    }

    public ReportHelper println(String str) {
        printStream.println(linePrefix + str.replace("\n", "\n" + linePrefix));
        return this;
    }

    public ReportHelper print(String str) {
        printStream.print(linePrefix + str.replace("\n", "\n" + linePrefix));
        return this;
    }

    public ReportHelper indentedHelper() {
        return new ReportHelper(printStream, linePrefix + "  ", stdout);
    }
}
