package de.duehl.basics.logging;

/*
 * Copyright 2017 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import de.duehl.basics.datetime.DateAndTime;
import de.duehl.basics.datetime.date.ImmutualDate;
import de.duehl.basics.datetime.time.ImmutualTime;

/**
 * Dieses Klasse dient zum Loggen von Prozessabläufen in eine Datei. Es wird vermerkt, wann und von
 * wo aufgerufen wird. Die Folgenden Informationen werden geloggt:
 *
 *     1: Datum
 *     2: Uhrzeit
 *     3: Klasse des Aufrufers
 *     4: Methode des Aufrufers
 *     5: Zeilennummer
 *     6: Inhalt der Nachricht
 *
 * @version 1.01     2017-03-31
 * @author Christian Dühl
 */

abstract class StructuredLogger extends NumberOfLinesLogger {

    /** Der zuletzt erzeugte Log-Eintrag. */
    private LogEntry lastLogEntry;

    private String actualDate;
    private String actualTime;
    private String className;
    private String methodName;
    private String lineNumber;
    private String message;

    /**
     * Konstruktor. Es wird automatisch angehängt, will man die Datei überschreiben, so muss
     * clearLogFile() aufgerufen werden nach der Erstellung des Objekts.
     */
    StructuredLogger() {
        super();
        lastLogEntry = new LogEntry("noch", "nicht", "initialisiert", "!", "!", "!");
    }

    /**
     * Hier wird ein komplexerer Eintrag erzeugt mit sechs tabgetrennten Spalten.
     *     1: Datum
     *     2: Zeit
     *     3: Klasse des Aufrufers
     *     4: Methode des Aufrufers
     *     5: Zeilennummer
     *     6: Inhalt der Nachricht
     *
     * @param text
     *            Inhalt der Nachricht.
     */
    @Override
    public void log(String text) {
        log(text, 1);
    }

    /**
     * Hier wird ein komplexerer Eintrag erzeugt mit sechs tabgetrennten Spalten.
     *     1: Datum
     *     2: Zeit
     *     3: Klasse des Aufrufers
     *     4: Methode des Aufrufers
     *     5: Zeilennummer
     *     6: Inhalt der Nachricht
     *
     * @param text
     *            Inhalt der Nachricht.
     * @param stacktraceOffset
     *            Offset im Stacktrace zum Ermitteln des richtigen Aufrufers.
     */
    @Override
    synchronized
    public void log(String text, int stacktraceOffset) {
        message = text;
        setActualDateAndTime();
        setClassNameMethodNameAndLineNumber(stacktraceOffset);
        buildElement();
    }

    private void setActualDateAndTime() {
        DateAndTime now = new DateAndTime();

        ImmutualTime time = now.getTime();
        actualTime = time.toString();

        ImmutualDate date = now.getDate();
        actualDate = date.toString();
    }

    private void setClassNameMethodNameAndLineNumber(int stacktraceOffset) {
        className = "dummyClass";
        methodName = "dummyMethod";
        lineNumber = "x";

        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        /*
         * Richtiges Element des Stacktrace bestimmen:
         * 0: java.lang.Thread.getStackTrace(Thread.java:1552)
         * 1: de.duehl.basics.logging.StructuredLogger.setClassNameMethodNameAndLineNumber(
         *    StructuredLogger.java:110)
         * 2: de.duehl.basics.logging.StructuredLogger.log(StructuredLogger.java:91)
         * 3: de.duehl.basics.logging.FileLogger.log(FileLogger.java:108)
         * 4: de.duehl.basics.logging.FileLogger.log(FileLogger.java:84)
         * 5: Aufrufende Methode
         */
        //for (StackTraceElement element : elements) System.out.println(element);
        int correctIndex = 4 + stacktraceOffset; // 2
        if (elements.length > correctIndex) {
            StackTraceElement element = elements[correctIndex];
            className = element.getClassName();
            methodName = element.getMethodName();
            lineNumber = Integer.toString(element.getLineNumber());
        }
    }

    private void buildElement() {
        lastLogEntry = new LogEntry(actualDate, actualTime, className, methodName, lineNumber,
                message);
        incrementNumberOfLinesInLogfile();
    }

    /** Getter für den zuletzt erzeugten Log-Eintrag. */
    protected LogEntry getLastLogEntry() {
        return lastLogEntry;
    }

    /*
     * TODO Aus Vererbungslinie nehmen und zu reinem Utility machen?
     */

}
