/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 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.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.TreeSet;

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

import org.objectweb.jonas.management.ReconfigDispatcher;
import org.objectweb.jonas.management.ReconfiguredProp;
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.api.Handler;
import org.objectweb.util.monolog.api.Level;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;
import org.objectweb.util.monolog.api.MonologFactory;

public class LogManagement extends ReconfigDispatcher implements LogManagementMBean {

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

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

    /**
     * The unique instance of LogManagement
     */
    private static LogManagement unique = null;

    public static LogManagement getInstance() {
        if (unique == null) {
            unique = new LogManagement();
        }
        return unique;
    }

    /**
     * get Topics. 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]);
    }

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

    /**
     * set Topic Level
     */
    public void setTopicLevel(String topic, 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 {
            throw new EJBException("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 ReconfiguredProp(propName, level));
    }

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

    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 MonologFactory) {
            MonologFactory mf = (MonologFactory) 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
     * @return The map of the attributes defines for the handler
     */
    public Map getHandlerAttributes(String handlername) {
        LoggerFactory lf = Log.getLoggerFactory();

        if (lf instanceof MonologFactory) {
            MonologFactory mf = (MonologFactory) 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)
            throws IllegalArgumentException {
        Handler handler = Monolog.getMonologFactory().getHandler("jmxHandler");
        if (handler != null && (handler instanceof NotificationEmitter)) {
            ((NotificationEmitter) handler).addNotificationListener(arg0, arg1, arg2);
        }
        super.addNotificationListener(arg0, arg1, arg2);
    }

}
