/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2007 Bull S.A.S.
 * Contact: jonas-team@ow2.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.ow2.jonas.lib.log;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.TreeSet;

import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;

import org.ow2.jonas.lib.reconfig.PropertiesConfigurationData;
import org.ow2.jonas.lib.reconfig.ReconfigEmitter;
import org.ow2.jonas.lib.util.Log;

import org.objectweb.util.monolog.api.Handler;
import org.objectweb.util.monolog.api.HandlerFactory;
import org.objectweb.util.monolog.api.Level;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;

/**
 * MBean implementation for log management.
 * The managed resource is the monolog {@link LoggerFactory}.
 */
public class LogManagement extends ReconfigEmitter implements LogManagementMBean {

    /**
     * Value used as sequence number by reconfiguration notifications.
     */
    private long sequenceNumber = 0;

    /**
     *  Name as used to label configuration properties.
     */
    public static final String SERVICE_NAME = "log";

    /**
     * The unique instance of {@link LogManagement}.
     */
    private static LogManagement unique = null;

    /**
     * @return Returns the {@link LogManagement} unique instance.
     */
    public static LogManagement getInstance() {
        if (unique == null) {
            unique = new LogManagement();
        }
        return unique;
    }

    /**
     * @return the topics list. Assumes that all Loggers are TopicalLoggers.
     */
    public String[] getTopics() {
        Logger[] logs = Log.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]);
    }

    /**
     * Return a topic's level
     * @param topic the topic we need ti know its level
     * @return the topic's level
     */
    public String getTopicLevel(final String topic) {
        Logger topicLogger = Log.getLoggerFactory().getLogger(topic);
        Level lev = topicLogger.getCurrentLevel();
        return lev.getName();
    }

    /**
     * set Topic Level
     * @param topic topic to set
     * @param level the level to set
     */
    public void setTopicLevel(final String topic, final String level) {
        Logger topicLogger = Log.getLoggerFactory().getLogger(topic);
        Level lev = Log.getLevelFactory().getLevel(level);
        // must check null (bug monolog)
        if (lev != null) {
            topicLogger.setLevel(lev);
        } else {
        	// TO DO maybe a better error treatement could be found
            throw new RuntimeException("Unknown level " + level);
        }
        // the modified property name is 'logger.topic.level'
        String propName = "logger." + topic + ".level";
        // Send a notification containing the new value of this property to the
        // listner MBean
        sendReconfigNotification(++sequenceNumber, SERVICE_NAME, new PropertiesConfigurationData(propName, level));
    }

    /**
     * @return list of properties for logging system
     */
    public Properties getProperties() {
        Properties props = Log.getProperties();
        if (props == null) {
            Log.getLoggerFactory();
            props = Log.getProperties();
        }
        return props;
    }


    /**
     * Save updated configuration.
     */
    public void saveConfig() {
        // Send save reconfig notification
        sendSaveNotification(++sequenceNumber, SERVICE_NAME);
    }


    /**
     * Returns the names of the Monolog handlers
     * @return The handler names defines in Monolog
     */
    public String[] getHandlerNames() {
        LoggerFactory lf = Log.getLoggerFactory();

        if (lf instanceof HandlerFactory) {
            HandlerFactory mf = (HandlerFactory) lf;
            Handler[] hs = mf.getHandlers();
            String[] hns = new String[hs.length];
            for (int i = 0; i < hs.length; i++) {
                hns[i] = hs[i].getName();
            }
            return hns;
        }
        return null;
    }

    /**
     * Getter for the map of the attributes of a handler.
     * @param handlername the handler name
     * @return The map of the attributes defines for the handler
     */
    public Map getHandlerAttributes(final String handlername) {
        LoggerFactory lf = Log.getLoggerFactory();

        if (lf instanceof HandlerFactory) {
            HandlerFactory mf = (HandlerFactory) lf;

            Handler h = mf.getHandler(handlername);
            String[] ans = h.getAttributeNames();
            Map m = new HashMap(ans.length);
            for (int i = 0; i < ans.length; i++) {
                m.put(ans[i], h.getAttribute(ans[i]));
            }
            return m;
        }
        return null;
    }

    /**
     * Super charge of the methode to take advantage of JMX notification
     * offered by Monolog 2.0
     * @param arg0 The notification Listener
     * @param arg1 The notification Filter
     * @param arg2 Handback object
     */
    public void addNotificationListener(NotificationListener arg0
            , NotificationFilter arg1, Object arg2) {
        // Get jmx handler, if any
        Handler handler = Log.getJmxHandler();
        if (handler != null && (handler instanceof NotificationEmitter)) {
            // Add arg0 as listener to notifications emitted by the jmx handler
            ((NotificationEmitter) handler).addNotificationListener(arg0, arg1, arg2);
        }
        // If the listener is the ReconfigManager, the following
        // instruction allows the ReconfigManager to treat the reconfiguration notifications
        // emitted by the LogManager
        super.addNotificationListener(arg0, arg1, arg2);
    }
}
