/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.trace;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import net.ranides.assira.junit.LogMessage;
import net.ranides.assira.junit.LogObserver;
import static net.ranides.assira.junit.NewAssert.*;
import net.ranides.assira.text.Wildcard;
import org.junit.After;
import org.junit.Test;
import org.junit.Before;
import org.slf4j.Logger;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class LoggerLevelTest {
    
    private static final Logger LOGGER = LoggerUtils.getLogger();
    
    @Before
    public void init() {
        LogObserver.reset(true);
    }
    
    @After
    public void release() {
        LogObserver.reset(false);
    }
    
    @Test
    public void testEnumInvariants() throws Exception {
        assertEnumInvariants(LoggerLevel.class);
    }
    
    @Test
    public void testLogObserver() {
        LOGGER.trace("m1");
        LOGGER.debug("m2");
        LOGGER.info("m3");
        LOGGER.warn("m4");
        LOGGER.error("m5");

        LogMessage m1 = LogObserver.forText("[main] TRACE net.ranides.assira.trace.LoggerLevelTest - m1").findFirst().get();
        LogMessage m5 = LogObserver.forText(Wildcard.compile("*5")).findFirst().get();
        LogMessage m3 = LogObserver.forLevel(LoggerLevel.INFO::test).findFirst().get();        
        LogMessage m2 = LogObserver.forLevel(LoggerLevel.DEBUG.level()).findFirst().get();
        LogMessage m4 = LogObserver.forLevel(LoggerLevel.WARN).findFirst().get();
        
        
        assertEquals("[main] TRACE net.ranides.assira.trace.LoggerLevelTest - m1", m1.text());
        assertEquals("[main] DEBUG net.ranides.assira.trace.LoggerLevelTest - m2", m2.text());
        assertEquals("[main] INFO net.ranides.assira.trace.LoggerLevelTest - m3", m3.text());
        assertEquals("[main] WARN net.ranides.assira.trace.LoggerLevelTest - m4", m4.text());
        assertEquals("[main] ERROR net.ranides.assira.trace.LoggerLevelTest - m5", m5.text());
    }
    
    @Test
    public void testGetFLogger() {
        Logger r1 = getFLogger(LoggerLevel.INFO.level());
        assertFalse(r1.isTraceEnabled() );
        assertFalse(r1.isDebugEnabled() );
        assertTrue(r1.isInfoEnabled() );
        assertTrue(r1.isWarnEnabled() );
        assertTrue(r1.isErrorEnabled() );
    }
    
    @Test
    public void testIsEnabled_Logger() {
        Logger r1 = getFLogger(LoggerLevel.TRACE.level());

        assertTrue( LoggerLevel.UNKNOWN.isEnabled(r1) );        
        assertTrue( LoggerLevel.ERROR.isEnabled(r1) );
        assertTrue( LoggerLevel.WARN.isEnabled(r1) );
        assertTrue( LoggerLevel.INFO.isEnabled(r1) );
        assertTrue( LoggerLevel.DEBUG.isEnabled(r1) );
        assertTrue( LoggerLevel.TRACE.isEnabled(r1) );
        
        Logger r2 = getFLogger(LoggerLevel.WARN.level());
        
        assertTrue( LoggerLevel.UNKNOWN.isEnabled(r2) );
        assertTrue( LoggerLevel.ERROR.isEnabled(r2) );
        assertTrue( LoggerLevel.WARN.isEnabled(r2) );
        assertFalse( LoggerLevel.INFO.isEnabled(r2) );
        assertFalse( LoggerLevel.DEBUG.isEnabled(r2) );
        assertFalse( LoggerLevel.TRACE.isEnabled(r2) );
        
    }
    
    @Test
    public void testTestIntLevel() {
        int r1 = LoggerLevel.TRACE.level();
        
        assertFalse( LoggerLevel.UNKNOWN.test(r1) );
        assertFalse( LoggerLevel.ERROR.test(r1) );
        assertFalse( LoggerLevel.WARN.test(r1) );
        assertFalse( LoggerLevel.INFO.test(r1) );
        assertFalse( LoggerLevel.DEBUG.test(r1) );
        assertTrue( LoggerLevel.TRACE.test(r1) );
        
        
        int r2 = LoggerLevel.INFO.level();

        assertFalse( LoggerLevel.UNKNOWN.test(r2) );        
        assertFalse( LoggerLevel.ERROR.test(r2) );
        assertFalse( LoggerLevel.WARN.test(r2) );
        assertTrue( LoggerLevel.INFO.test(r2) );
        assertTrue( LoggerLevel.DEBUG.test(r2) );
        assertTrue( LoggerLevel.TRACE.test(r2) );
    }
    
    @Test
    public void testValueOf_int() throws Exception {
        LOGGER.trace("m1");
        LOGGER.debug("m2");
        LOGGER.info("m3");
        LOGGER.warn("m4");
        LOGGER.error("m5");
        
        List<LogMessage> ms = LogObserver.list();
        assertEquals(LoggerLevel.TRACE, LoggerLevel.valueOf(ms.get(0).level()) );
        assertEquals(LoggerLevel.DEBUG, LoggerLevel.valueOf(ms.get(1).level()) );
        assertEquals(LoggerLevel.INFO, LoggerLevel.valueOf(ms.get(2).level()) );
        assertEquals(LoggerLevel.WARN, LoggerLevel.valueOf(ms.get(3).level()) );
        assertEquals(LoggerLevel.ERROR, LoggerLevel.valueOf(ms.get(4).level()) );
        assertEquals(LoggerLevel.UNKNOWN, LoggerLevel.valueOf(13) );
        assertEquals(LoggerLevel.UNKNOWN, LoggerLevel.valueOf(1113) );
    }
    
    @Test
    public void testValueOf_Logger() throws Exception {
        Logger r1 = getFLogger(LoggerLevel.TRACE.level());
        Logger r2 = getFLogger(LoggerLevel.DEBUG.level());
        Logger r3 = getFLogger(LoggerLevel.INFO.level());
        Logger r4 = getFLogger(LoggerLevel.WARN.level());
        Logger r5 = getFLogger(LoggerLevel.ERROR.level());
        Logger r6 = getFLogger(LoggerLevel.ERROR.level() + 20);
        
        assertEquals(LoggerLevel.TRACE, LoggerLevel.valueOf(r1) );
        assertEquals(LoggerLevel.DEBUG, LoggerLevel.valueOf(r2) );
        assertEquals(LoggerLevel.INFO, LoggerLevel.valueOf(r3) );
        assertEquals(LoggerLevel.WARN, LoggerLevel.valueOf(r4) );
        assertEquals(LoggerLevel.ERROR, LoggerLevel.valueOf(r5) );
        assertEquals(LoggerLevel.UNKNOWN, LoggerLevel.valueOf(r6) );
    }
    
    private static Logger getFLogger(int level) {
        return (Logger)Proxy.newProxyInstance(Logger.class.getClassLoader(), new Class[]{Logger.class}, (Object proxy, Method method, Object[] args)->{
            if(method.getName().equals("isTraceEnabled")) {
                return level <= LoggerLevel.TRACE.level();
            }
            if(method.getName().equals("isDebugEnabled")) {
                return level <= LoggerLevel.DEBUG.level();
            }
            if(method.getName().equals("isInfoEnabled")) {
                return level <= LoggerLevel.INFO.level();
            }
            if(method.getName().equals("isWarnEnabled")) {
                return level <= LoggerLevel.WARN.level();
            }
            if(method.getName().equals("isErrorEnabled")) {
                return level <= LoggerLevel.ERROR.level();
            }
            throw new UnsupportedOperationException();
        });
    }
    
}
