//
//  ========================================================================
//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.util.log;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.regex.Pattern;

/**
 * Redirect java.util.logging events to Jetty Log
 */
public class JettyLogHandler extends java.util.logging.Handler
{
    public static void config()
    {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        URL url = cl.getResource("logging.properties");
        if (url != null)
        {
            System.err.printf("Initializing java.util.logging from %s%n", url);
            try (InputStream in = url.openStream())
            {
                LogManager.getLogManager().readConfiguration(in);
            }
            catch (IOException e)
            {
                e.printStackTrace(System.err);
            }
        }
        else
        {
            System.err.printf("WARNING: java.util.logging failed to initialize: logging.properties not found%n");
        }

        System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.Jdk14Logger");
    }

    public JettyLogHandler()
    {
        if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.DEBUG", "false")))
        {
            setLevel(Level.FINEST);
        }

        if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.IGNORED", "false")))
        {
            setLevel(Level.ALL);
        }

        System.err.printf("%s Initialized at level [%s]%n", this.getClass().getName(), getLevel().getName());
    }

    private synchronized String formatMessage(LogRecord record)
    {
        String msg = getMessage(record);

        try
        {
            Object[] params = record.getParameters();
            if ((params == null) || (params.length == 0))
            {
                return msg;
            }

            if (Pattern.compile("\\{\\d+\\}").matcher(msg).find())
            {
                return MessageFormat.format(msg, params);
            }

            return msg;
        }
        catch (Exception ex)
        {
            return msg;
        }
    }

    private String getMessage(LogRecord record)
    {
        ResourceBundle bundle = record.getResourceBundle();
        if (bundle != null)
        {
            try
            {
                return bundle.getString(record.getMessage());
            }
            catch (java.util.MissingResourceException ignored)
            {
            }
        }

        return record.getMessage();
    }

    @Override
    public void publish(LogRecord record)
    {
        org.eclipse.jetty.util.log.Logger jettyLogger = getJettyLogger(record.getLoggerName());

        int level = record.getLevel().intValue();
        if (level >= Level.OFF.intValue())
        {
            // nothing to log, skip it.
            return;
        }

        Throwable cause = record.getThrown();
        String msg = formatMessage(record);

        if (level >= Level.WARNING.intValue())
        {
            // log at warn
            if (cause != null)
            {
                jettyLogger.warn(msg, cause);
            }
            else
            {
                jettyLogger.warn(msg);
            }
            return;
        }

        if (level >= Level.INFO.intValue())
        {
            // log at info
            if (cause != null)
            {
                jettyLogger.info(msg, cause);
            }
            else
            {
                jettyLogger.info(msg);
            }
            return;
        }

        if (level >= Level.FINEST.intValue())
        {
            // log at debug
            if (cause != null)
            {
                jettyLogger.debug(msg, cause);
            }
            else
            {
                jettyLogger.debug(msg);
            }
            return;
        }

        if (level >= Level.ALL.intValue())
        {
            // only corresponds with ignore (in jetty speak)
            jettyLogger.ignore(cause);
            return;
        }
    }

    private Logger getJettyLogger(String loggerName)
    {
        return org.eclipse.jetty.util.log.Log.getLogger(loggerName);
    }

    @Override
    public void flush()
    {
        // ignore
    }

    @Override
    public void close() throws SecurityException
    {
        // ignore
    }
}
