/** 
 * 
 * Copyright 2004 Protique Ltd
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 * 
 **/
package org.codehaus.activemq.management;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.util.IndentPrinter;

import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.management.j2ee.statistics.CountStatistic;
import javax.management.j2ee.statistics.JMSEndpointStats;
import javax.management.j2ee.statistics.TimeStatistic;

/**
 * Statistics for a JMS endpoint, typically a MessageProducer or MessageConsumer
 * but this class can also be used to represent statistics on a {@link Destination} as well.
 *
 * @version $Revision: 1.1 $
 */
public class JMSEndpointStatsImpl extends StatsImpl implements JMSEndpointStats {
    private static final Log log = LogFactory.getLog(JMSEndpointStatsImpl.class);

    protected CountStatisticImpl messageCount;
    protected CountStatisticImpl pendingMessageCount;
    protected CountStatisticImpl expiredMessageCount;
    protected TimeStatistic messageWaitTime;
    protected TimeStatisticImpl messageRateTime;

    /**
     * This constructor is used to create statistics for a
     * {@link MessageProducer} or {@link MessageConsumer} as it passes in a
     * {@link Session} parent statistic.
     *
     * @param sessionStats
     */
    public JMSEndpointStatsImpl(JMSSessionStatsImpl sessionStats) {
        this();
        setParent(messageCount, sessionStats.getMessageCount());
        setParent(pendingMessageCount, sessionStats.getPendingMessageCount());
        setParent(expiredMessageCount, sessionStats.getExpiredMessageCount());
        setParent(messageWaitTime, sessionStats.getMessageWaitTime());
        setParent(messageRateTime, sessionStats.getMessageRateTime());
    }

    /**
     * This constructor is typically used to create a statistics object for a
     * {@link Destination}
     */
    public JMSEndpointStatsImpl() {
        this(new CountStatisticImpl("messageCount", "Number of messages processed"),
                new CountStatisticImpl("pendingMessageCount", "Number of pending messages"),
                new CountStatisticImpl("expiredMessageCount", "Number of expired messages"),
                new TimeStatisticImpl("messageWaitTime", "Time spent by a message before being delivered"),
                new TimeStatisticImpl("messageRateTime", "Time taken to process a message (thoughtput rate)"));
    }

    public JMSEndpointStatsImpl(CountStatisticImpl messageCount, CountStatisticImpl pendingMessageCount, CountStatisticImpl expiredMessageCount, TimeStatisticImpl messageWaitTime, TimeStatisticImpl messageRateTime) {
        this.messageCount = messageCount;
        this.pendingMessageCount = pendingMessageCount;
        this.expiredMessageCount = expiredMessageCount;
        this.messageWaitTime = messageWaitTime;
        this.messageRateTime = messageRateTime;

        // lets add named stats
        addStatistic("messageCount", messageCount);
        addStatistic("pendingMessageCount", pendingMessageCount);
        addStatistic("expiredMessageCount", expiredMessageCount);
        addStatistic("messageWaitTime", messageWaitTime);
        addStatistic("messageRateTime", messageRateTime);
    }

    public CountStatistic getMessageCount() {
        return messageCount;
    }

    public CountStatistic getPendingMessageCount() {
        return pendingMessageCount;
    }

    public CountStatistic getExpiredMessageCount() {
        return expiredMessageCount;
    }

    public TimeStatistic getMessageWaitTime() {
        return messageWaitTime;
    }

    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(messageCount);
        buffer.append(" ");
        buffer.append(messageRateTime);
        buffer.append(" ");
        buffer.append(pendingMessageCount);
        buffer.append(" ");
        buffer.append(expiredMessageCount);
        buffer.append(" ");
        buffer.append(messageWaitTime);
        return buffer.toString();
    }

    public void onMessage(Message message) {
        long start = messageCount.getLastSampleTime();
        messageCount.increment();
        long end = messageCount.getLastSampleTime();
        messageRateTime.addTime(end - start);
    }

    public void dump(IndentPrinter out) {
        out.printIndent();
        out.println(messageCount);
        out.printIndent();
        out.println(messageRateTime);
        out.printIndent();
        out.println(pendingMessageCount);
        out.printIndent();
        out.println(messageRateTime);
        out.printIndent();
        out.println(expiredMessageCount);
        out.printIndent();
        out.println(messageWaitTime);
    }

    // Implementation methods
    //-------------------------------------------------------------------------
    protected void setParent(CountStatistic child, CountStatistic parent) {
        if (child instanceof CountStatisticImpl && parent instanceof CountStatisticImpl) {
            CountStatisticImpl c = (CountStatisticImpl) child;
            c.setParent((CountStatisticImpl) parent);
        }
        else {
            log.warn("Cannot associate endpoint counters with session level counters as they are not both CountStatisticImpl clases. Endpoint: " + child + " session: " + parent);
        }
    }

    protected void setParent(TimeStatistic child, TimeStatistic parent) {
        if (child instanceof TimeStatisticImpl && parent instanceof TimeStatisticImpl) {
            TimeStatisticImpl c = (TimeStatisticImpl) child;
            c.setParent((TimeStatisticImpl) parent);
        }
        else {
            log.warn("Cannot associate endpoint counters with session level counters as they are not both TimeStatisticImpl clases. Endpoint: " + child + " session: " + parent);
        }
    }
}
