/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.common;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TreeSet;
import javax.ejb.EJBException;
import org.objectweb.common.TraceCore;
import org.objectweb.jonas_ejb.container.TraceEjb;
import org.objectweb.jonas_jms.TraceJms;
import org.objectweb.jonas_timer.TraceTimer;
import org.objectweb.jonas_tm.TraceTm;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.HandlerFactory;
import org.objectweb.util.monolog.api.Level;
import org.objectweb.util.monolog.api.LevelFactory;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;
import org.objectweb.util.monolog.wrapper.printwriter.PrintWriterImpl;
import org.objectweb.util.monolog.file.monolog.PropertiesConfAccess;


/**
 *  This class provides utility method for using Monolog
 * @author Philippe Coq.
 * 02/04/30: Sebastien Chassande-Barrioz sebastien.chassande@inrialpes.fr
 * 02/05/13: Philippe Durieux         
 */
public class Log implements LogMBean {    

    // default values when no config (client for example)
    private static String configFile = "trace.properties";
    private static boolean usecp = true;

    // This class is actually a wrapper on the unique loggerFactory
    private static LoggerFactory lf = null;

    // Properties used for Logging system
    // Kept here mainly for debugging
    private static Properties props = null;

    // List of topic used inside JOnAS
    // This list may be not exhaustive since many topics can be added for
    // different purposes or to refine debugging.
    // To get the complete list, use JonasAdmin -trace
    public static final String JONAS_DBM_PREFIX = 	"org.objectweb.jonas.dbm";
    public static final String JONAS_JCA_PREFIX = 	"org.objectweb.jonas.jca";
    public static final String JONAS_JDBCXA_PREFIX = 	"org.objectweb.jonas.jdbc_xa";
    public static final String JONAS_NAMING_PREFIX = 	"org.objectweb.jonas.naming";
    public static final String JONAS_PROPCTX_PREFIX = 	"org.objectweb.jonas.propagation";
    public static final String JONAS_REGISTRY_PREFIX = 	"org.objectweb.jonas.registry";
    public static final String JONAS_SECURITY_PREFIX = 	"org.objectweb.jonas.security";
    public static final String JONAS_SERVER_PREFIX = 	"org.objectweb.jonas.server";
    public static final String JONAS_TOMCAT_PREFIX = 	"org.objectweb.jonas.tomcat";
    public static final String JONAS_TESTS_PREFIX = 	"org.objectweb.jonas_tests";

    // The Log unique instance
    private static Log unique = null;

    /**
     * constructor should be private to prevent client program from instanciating a 'Log'
     * but MBean must have a public constructor.
     * Another solution would be to use delegation model for MBean.
     * We assume here that the JmxServer will never use this constructor (it should not)
     */
    public Log() {
    }

    /**
     * Get the unique instance. Used for MBean.
     * Create it at first call.
     */
    public static Log getInstance() {
	if (unique == null) {
	    unique = new Log();
	}
	return unique;
    }

    /**
     * Configure Logger for JOnAS modules
     * This is called only from EJBServer.
     */
    public static void configure(String file, boolean useclasspath) {
	configFile = file;
	usecp = useclasspath;
	LoggerFactory lf = getLoggerFactory();
        TraceTimer.configure(lf);
        TraceCore.configure(lf);
        TraceTm.configure(lf);
        TraceEjb.configure(lf);
        TraceJms.configure(lf);
    }

    /**
     * It returns the unique LoggerFactory used in JOnAS.
     * initialize it if not already done.
     */
    public synchronized static LoggerFactory getLoggerFactory() {
        if (lf == null) {
	    try {
		// load properties from config file
		props = new Properties();
		if (usecp) {
		    props.load(ClassLoader.getSystemResourceAsStream(configFile));
		} else {
		    props.load(new FileInputStream(configFile));
		}
		// Instanciate the LoggerFactory
		String b = props.getProperty("log.config.classname", null);
		if (b == null) {
		    System.err.println("Malformed configuration log file: log.config.classname not available");
		    return null;
		}
		lf = (LoggerFactory) Class.forName(b).newInstance();
		// Configure the LoggerFactory with the properties
		PropertiesConfAccess.load(props, lf, (HandlerFactory)lf, (LevelFactory)lf);
	    } catch (Exception e) {
		System.err.println("Cannot get LoggerFactory:"+e);
	    }
        }
        return lf;
    }

   /**
    * Returns the standard PrintWriter associated to the logger defined by
    * its topic.
    * This is mainly used for DBM and Connectors.
    */
    public static PrintWriter getLogWriter(String topic) {
	// TODO : should not create a new object at each call
        return new PrintWriterImpl(getLogger(topic));
    }

    /**
     * Shortcut that returns the LevelFactory
     */
    public static LevelFactory getLevelFactory() {
	return (LevelFactory) getLoggerFactory();
    }

    /**
     * Shortcut to get the Logger by its topic name.
     * @param is the topic of the returned logger
     * @return always a logger instance (never null value).
     */
    public static Logger getLogger(String topic) {
        return getLoggerFactory().getLogger(topic);
    }

    // ------------------------------------------------------------------
    // LogMBean implementation
    // ------------------------------------------------------------------

    /**
     * get Topics. 
     * Assumes that all Loggers are TopicalLoggers.
     */
    public String [] getTopics() {
	Logger [] logs = getLoggerFactory().getLoggers();
	// put names in alphabetical order
	TreeSet tset = new TreeSet();
	for (int i = 0; i < logs.length; i++) {
	    tset.add(logs[i].getName());
	}
	return (String []) tset.toArray(new String [0]);
    }

    /**
     * get Topic Level
     */
    public String getTopicLevel(String topic) {
	String ret = null;
	Logger log = getLogger(topic);
	Level lev = log.getCurrentLevel();
	return lev.getName();
    }

    /**
     * set Topic Level
     */
    public void setTopicLevel(String topic, String l) {
	Logger log = getLogger(topic);
	Level lev = getLevelFactory().getLevel(l);
	// must check null (bug monolog)
	if (lev != null) {
	    log.setLevel(lev);
	} else {
	    throw new EJBException("Unknown level "+l);
	}
    }	
    
    /**
     * returns list of properties for logging system
     */
    public Properties getProperties() {
	if (props == null) {
	    getLoggerFactory();
	}
	return props;
    }
}
