package de.duehl.basics.logging;

/*
 * Copyright 2021 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 static org.junit.Assert.*;

import java.util.List;
import java.util.regex.Pattern;

import org.junit.Test;

import de.duehl.basics.collections.CollectionsHelper;
import de.duehl.basics.datetime.Timestamp;
import de.duehl.basics.io.FileHelper;
import de.duehl.basics.logging.reader.LogFileReader;
import de.duehl.basics.text.Text;

public class FileLoggerTest {

    private static final boolean DEBUG = false;

    @Test
    public void create() {
        FileLogger logger = new FileLogger("c:/temp/log_" + Timestamp.fullTimestamp() + "_foo.log");
        assertNotNull(logger);
    }

    @Test
    public void createWithCreateMethod() {
        FileLogger logger = FileLogger.create("FileLoggerTest1_", ".log", "c:/temp");
        assertNotNull(logger);
    }

    @Test
    public void logFullLine() {
        FileLogger logger = FileLogger.create("FileLoggerTest2_", ".log", "c:/temp");
        logger.log("test");

        List<String> logLines = getLogFileContents(logger);
        String lastLine = logLines.get(logLines.size() - 1);
        List<String> parts = Text.splitByTabulator(lastLine);

        String date = parts.get(0);
        String time = parts.get(1);
        String className = parts.get(2);
        String methodName = parts.get(3);
        String lineNumber = parts.get(4);
        String message = parts.get(5);

        assertTrue(date.matches("\\d{2}\\.\\d{2}\\.\\d{4}"));
        assertTrue(time.matches("\\d{2}:\\d{2}:\\d{2}"));
        assertEquals("de.duehl.basics.logging.FileLoggerTest", className);
        assertEquals("logFullLine", methodName);
        assertEquals("46", lineNumber);
        assertEquals("test", message);
    }

    private List<String> getLogFileContents(FileLogger logger) {
        return FileHelper.readFileToList(logger.getLogFileName());
        // Hier könnte man auch den LogReader nutzen, aber dann würde man den gleich mit testen.
    }

     @Test
    public void logWithIndex() {
        FileLogger logger = FileLogger.create("FileLoggerTest3_", ".log", "c:/temp");
        logger.log("foo", 0);

        List<String> logLines = getLogFileContents(logger);
        if (DEBUG) {
            CollectionsHelper.printListNice(logLines);
        }
        String lastLine = logLines.get(logLines.size() - 1);
        List<String> parts = Text.splitByTabulator(lastLine);

        String date = parts.get(0);
        String time = parts.get(1);
        String className = parts.get(2);
        String methodName = parts.get(3);
        String lineNumber = parts.get(4);
        String message = parts.get(5);

        assertTrue(date.matches("\\d{2}\\.\\d{2}\\.\\d{4}"));
        assertTrue(time.matches("\\d{2}:\\d{2}:\\d{2}"));
        assertEquals("de.duehl.basics.logging.FileLoggerTest", className);
        assertEquals("logWithIndex", methodName);
        assertEquals("75", lineNumber);
        assertEquals("foo", message);
    }

    @Test
    public void getLogFileName() {
        FileLogger logger = FileLogger.create("FileLoggerTest4_", ".log", "c:/temp");
        String logName = logger.getLogFileName();
        assertTrue(logName.startsWith("c:/temp\\"));
        assertTrue(logName.startsWith("c:/temp\\FileLoggerTest4_"));
        assertTrue(logName.endsWith(".log"));

        String start = Pattern.quote("c:/temp\\FileLoggerTest4_");
        String end = Pattern.quote(".log");
        assertTrue(logName.matches(start + "\\d{8}_\\d{6}" + end));
    }

    @Test
    public void getLogPath() {
        FileLogger logger = FileLogger.create("FileLoggerTest5_", ".log", "c:/temp");
        String logPath = logger.getLogPath();
        assertEquals("c:/temp\\", logPath);
    }

    @Test
    public void getLastWrittenLineNumber() {
        FileLogger logger = FileLogger.create("FileLoggerTest6_", ".log", "c:/temp");
        int lastLineNumber = logger.getLastWrittenLineNumber();

        if (DEBUG) {
            CollectionsHelper.printListNice(getLogFileContents(logger));
        }
        assertEquals(4, lastLineNumber); // Sollte dies Fehlschlagen, hat der LogEraser vielleicht
                                         // etwas gelöscht. Einfach Tests erneut starten!
    }

    @Test
    public void getLastWrittenLineNumberAfterLoggingSomeLines() {
        FileLogger logger = FileLogger.create("FileLoggerTest7_", ".log", "c:/temp");
        logger.log("foo");
        logger.log("bar");
        logger.log("baz");
        int lastLineNumber = logger.getLastWrittenLineNumber();

        if (DEBUG) {
            CollectionsHelper.printListNice(getLogFileContents(logger));
        }
        assertEquals(7, lastLineNumber); // Sollte dies Fehlschlagen, hat der LogEraser vielleicht
                                         // etwas gelöscht. Einfach Tests erneut starten!
    }

    @Test
    public void createAndLookIntoLogFile() {
        FileLogger logger = FileLogger.create("FileLoggerTest8_", ".log", "c:/temp");
        List<LogEntry> logEntries = readLogFile(logger.getLogFileName());

        assertEquals(4, logEntries.size()); // Sollte dies Fehlschlagen, hat der LogEraser vielleicht
                                            // etwas gelöscht. Einfach Tests erneut starten!
        if (DEBUG) {
            CollectionsHelper.printListNice(logEntries);
            /*
            0. [LogLineElement [date=Datum, time=Zeit, clazz=Klasse, method=Methode, lineNumber=Zeilennummer, message=Nachricht]]
            1. [LogLineElement [date=16.03.2016, time=11:31:32, clazz=de.duehl.basics.logging.DetailedFileLogger, method=create, lineNumber=245, message=Gestartet]]
            2. [LogLineElement [date=16.03.2016, time=11:31:32, clazz=de.duehl.basics.logging.LogEraser, method=erase, lineNumber=75, message=Start erasing old Logfiles in 'C:\Users\Anwender\.jerwent' with beginning 'JErwEnt_' and end '.log'.]]
            3. [LogLineElement [date=16.03.2016, time=11:31:32, clazz=de.duehl.basics.logging.LogEraser, method=erase, lineNumber=96, message=End erasing old Logfiles in 'C:\Users\Anwender\.jerwent' with beginning 'JErwEnt_' and end '.log'. Number of deleted files: 0]]
            */
        }
        LogEntry headerEntry = logEntries.get(0);
        LogEntry loggerStartMessageEntry = logEntries.get(1);
        LogEntry logEraserStartMessageEntry = logEntries.get(2);
        LogEntry logEraserEndMessageEntry = logEntries.get(3);

        assertEquals("Datum", headerEntry.getDate());
        assertEquals("Zeit", headerEntry.getTime());
        assertEquals("Klasse", headerEntry.getClassName());
        assertEquals("Methode", headerEntry.getMethod());
        assertEquals("Zeilennummer", headerEntry.getLineNumber());
        assertEquals("Nachricht", headerEntry.getMessage());

        assertEquals("de.duehl.basics.logging.FileLogger",
                loggerStartMessageEntry.getClassName());
        assertEquals("create", loggerStartMessageEntry.getMethod());

        assertEquals("de.duehl.basics.logging.eraser.LogEraser",
                logEraserStartMessageEntry.getClassName());
        assertEquals("erase", logEraserStartMessageEntry.getMethod());

        assertEquals("de.duehl.basics.logging.eraser.LogEraser",
                logEraserEndMessageEntry.getClassName());
        assertEquals("erase", logEraserEndMessageEntry.getMethod());
    }

    private List<LogEntry> readLogFile(String filename) {
        LogFileReader reader = new LogFileReader(filename);
        return reader.read();
    }

    @Test
    public void createLogFileNameBeginEndingWithUnderscoreEndStartsWithDot() {
        String filename = FileLogger.createLogFileName("FileLoggerTest8_", ".log", "c:/temp");
        assertTrue(filename.startsWith("c:/temp\\FileLoggerTest8_"));
        assertTrue(filename.endsWith(".log"));
    }

    @Test
    public void createLogFileNameBeginEndingWithoutUnderscoreEndStartsWithDot() {
        String filename = FileLogger.createLogFileName("FileLoggerTest8", ".log", "c:/temp");
        assertTrue(filename.startsWith("c:/temp\\FileLoggerTest8_"));
        assertTrue(filename.endsWith(".log"));
    }

    @Test
    public void createLogFileNameBeginEndingWithUnderscoreEndStartsWithUnderscore() {
        String filename = FileLogger.createLogFileName("FileLoggerTest8_", "_foo.log", "c:/temp");
        assertTrue(filename.startsWith("c:/temp\\FileLoggerTest8_"));
        assertTrue(filename.endsWith("_foo.log"));
    }

    @Test
    public void createLogFileNameBeginEndingWithoutUnderscoreEndStartsWithUnderscore() {
        String filename = FileLogger.createLogFileName("FileLoggerTest8", "_foo.log", "c:/temp");
        assertTrue(filename.startsWith("c:/temp\\FileLoggerTest8_"));
        assertTrue(filename.endsWith("_foo.log"));
    }

    @Test
    public void createLogFileNameBeginEndingWithUnderscoreEndStartsWithoutDotAndUnderscore() {
        String filename = FileLogger.createLogFileName("FileLoggerTest8_", "foo.log", "c:/temp");
        assertTrue(filename.startsWith("c:/temp\\FileLoggerTest8_"));
        assertTrue(filename.endsWith("_foo.log"));
    }

    @Test
    public void createLogFileNameBeginEndingWithoutUnderscoreEndStartsWithoutDotAndUnderscore() {
        String filename = FileLogger.createLogFileName("FileLoggerTest8", "foo.log", "c:/temp");
        assertTrue(filename.startsWith("c:/temp\\FileLoggerTest8_"));
        assertTrue(filename.endsWith("_foo.log"));
    }

}
