package org.xbib.logging.ext.test.handlers;

import java.util.logging.SimpleFormatter;

import org.xbib.logging.ExtHandler;
import org.xbib.logging.ext.formatters.PatternFormatter;
import org.junit.jupiter.api.Test;
import org.xbib.logging.ext.test.AssertingErrorManager;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ExtHandlerTests {

    public ExtHandlerTests() {
    }

    @Test
    public void testHandlerClose() {
        final CloseHandler parent = new CloseHandler();
        final CloseHandler child1 = new CloseHandler();
        final CloseHandler child2 = new CloseHandler();
        parent.setHandlers(new CloseHandler[] { child1, child2, new CloseHandler() });

        // Ensure all handlers are not closed
        assertFalse(parent.closed);
        assertFalse(child1.closed);
        assertFalse(child2.closed);

        // Close the parent handler, the children should be closed
        parent.close();
        assertTrue(parent.closed);
        assertTrue(child1.closed);
        assertTrue(child2.closed);

        // Reset and wrap
        parent.reset();
        child1.reset();
        child2.reset();

        parent.setCloseChildren(false);

        // Ensure all handlers are not closed
        assertFalse(parent.closed);
        assertFalse(child1.closed);
        assertFalse(child2.closed);

        parent.close();

        // The parent should be closed, the others should be open
        assertTrue(parent.closed);
        assertFalse(child1.closed);
        assertFalse(child2.closed);

    }

    @Test
    public void testCallerCalculationCheckFormatterChange() {
        try (CloseHandler parent = new CloseHandler()) {

            // Create a formatter for the parent that will require caller calculation
            final PatternFormatter formatter = new PatternFormatter("%d %M %s%e%n");
            parent.setFormatter(formatter);

            assertTrue(parent.isCallerCalculationRequired());

            // Change the formatter to not require calculation, this should trigger false to be returned
            formatter.setPattern("%d %s%e%n");
            assertFalse(parent.isCallerCalculationRequired());
        }
    }

    @Test
    public void testCallerCalculationCheckNewFormatter() {
        try (CloseHandler parent = new CloseHandler()) {

            // Create a formatter for the parent that will require caller calculation
            final PatternFormatter formatter = new PatternFormatter("%d %M %s%e%n");
            parent.setFormatter(formatter);

            assertTrue(parent.isCallerCalculationRequired());

            // Add a new formatter which should result in the caller calculation not to be required
            parent.setFormatter(new PatternFormatter("%d %s%e%n"));
            assertFalse(parent.isCallerCalculationRequired());
        }
    }

    @Test
    public void testCallerCalculationCheckChildFormatter() {
        try (CloseHandler parent = new CloseHandler(); CloseHandler child = new CloseHandler()) {
            parent.addHandler(child);

            // Create a formatter for the parent that will require caller calculation
            final PatternFormatter formatter = new PatternFormatter("%d %M %s%e%n");
            child.setFormatter(formatter);
            assertTrue(parent.isCallerCalculationRequired());

            // Remove the child handler which should result in the caller calculation not being required since the formatter
            // is null
            parent.removeHandler(child);
            assertFalse(parent.isCallerCalculationRequired());

            // Add a formatter to the parent and add he child back, the parent handler will not require calculation, but
            // the child should
            parent.setFormatter(new PatternFormatter("%d %s%e%n"));
            parent.addHandler(child);
            assertTrue(parent.isCallerCalculationRequired());
        }
    }

    @Test
    public void testCallerCalculationNonExtFormatter() {
        try (CloseHandler parent = new CloseHandler(); CloseHandler child = new CloseHandler()) {
            parent.addHandler(child);
            // Create a non ExtFormatter for the parent that will require caller calculation
            child.setFormatter(new SimpleFormatter());
            assertTrue(child.isCallerCalculationRequired());
            assertTrue(parent.isCallerCalculationRequired());
            parent.setFormatter(new SimpleFormatter());
            assertTrue(parent.isCallerCalculationRequired());
        }
    }

    static class CloseHandler extends ExtHandler {
        private boolean closed = false;

        CloseHandler() {
            setErrorManager(AssertingErrorManager.of());
        }

        @Override
        public void close() {
            closed = true;
            super.close();
        }

        void reset() {
            closed = false;
        }
    }
}
