/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License).  You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the license at
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Copyright (c) Ericsson AB, 2004-2007. All rights reserved.
 */
package com.ericsson.ssa.sip;

import com.ericsson.ssa.container.startup.PerformanceMBeanListener;
import org.jvnet.glassfish.comms.util.LogUtil;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * A singleton manager for dialog fragments.
 */
public class DialogFragmentManager {
    private static final LogUtil SIP_LOGGER =
        new LogUtil(LogUtil.SIP_LOG_DOMAIN);
    private static PersistentDialogFragmentManager replicationMgr = null;
    private AtomicLong concurrentSipDialogs;
    private AtomicLong totalSipDialogCount;
    private AtomicLong totalSipDialogLifeTime;
    private AtomicLong expiredSipDialogs;

    // Active cache of dialog fragments
    protected ConcurrentHashMap<String, DialogFragment> dialogFragments;

    static {
        try {
            replicationMgr = (PersistentDialogFragmentManager) Class.forName(
                "org.jvnet.glassfish.comms.replication.dialogmgmt.ReplicationDialogFragmentManager").newInstance();
        } catch (Throwable t) {
            throw new ExceptionInInitializerError(t);
        }
    }

    /**
     * Constructor.
     *
     * Scope is protected since this is a singleton.
     */
    protected DialogFragmentManager() {
        dialogFragments = new ConcurrentHashMap<String, DialogFragment>();
        concurrentSipDialogs = new AtomicLong();
        totalSipDialogCount = new AtomicLong();
        totalSipDialogLifeTime = new AtomicLong();
        expiredSipDialogs = new AtomicLong();
    }

    /**
     * Gets the singleton DialogFragmentManager instance.
     *
     * @return The singleton DialogFragmentManager instance
     */
    public static DialogFragmentManager getInstance() {
        return replicationMgr;
    }

    /**
     * Adds the given DialogFragment.
     *
     * @param d The DialogFragment to add
     */
    public void registerDialogFragment(DialogFragment d) {
        if (PerformanceMBeanListener.isEnabled() && (d.getFragmentId() == 1)) {
            concurrentSipDialogs.incrementAndGet();
        }

        dialogFragments.put(d.getDialogId(), d);
    }

    /**
     * Gets the DialogFragment with the given id.
     *
     * @param id The DialogFragment id to match
     *
     * @return The DialogFragment with matching id, or null if not found
     */
    public DialogFragment findDialogFragment(String id) {
        return dialogFragments.get(id);
    }

    /**
     * Removes the given DialogFragment.
     *
     * @param df The DialogFragment to be removed
     * @param hasTimedOut true if the DialogFragment is removed because it has
     * expired, false otherwise
     */
    public void removeDialogFragment(DialogFragment df, boolean hasTimedOut) {
        DialogFragment storedDlg = dialogFragments.remove(df.getDialogId());

        // if dialogfragment storedDlg is found/removed it was a "real" dialog
        if ((storedDlg != null) && PerformanceMBeanListener.isEnabled() &&
                (df.getFragmentId() == 1)) {
            concurrentSipDialogs.decrementAndGet();
            totalSipDialogCount.incrementAndGet();
            totalSipDialogLifeTime.addAndGet(df.getDialogLifetime());

            if (SIP_LOGGER.isLoggable(Level.FINE)) {
                long nDialogs = totalSipDialogCount.get();
                double cumulativeLifetime = totalSipDialogLifeTime.doubleValue();
                double average = cumulativeLifetime / nDialogs;
                SIP_LOGGER.log(Level.FINE,
                    "DialogLifetime=" + df.getDialogLifetime() +
                    "; nDialogs=" + nDialogs + "; cumulativeLifetime=" +
                    cumulativeLifetime + ";averageLifetime=" + average);
            }

            if (hasTimedOut) {
                expiredSipDialogs.incrementAndGet();
            }
        }
    }

    /**
     * Gets the total number of dialog fragments that were ever created.
     *
     * @return The total number of dialog fragments that were ever created
     */
    public long getEasTotalSipDialogCount() {
        return totalSipDialogCount.longValue();
    }

    /**
     * Gets the number of dialog fragments that are currently active.
     *
     * @return The number of dialog fragments that are currently active.
     */
    public long getEasConcurrentSipDialogs() {
        return concurrentSipDialogs.longValue();
    }

    /**
     * Gets the cumulative lifetime of all dialog fragments.
     *
     * @return The cumulative lifetime of all dialog fragments
     */
    public long getEasTotalSipDialogLifeTime() {
        return totalSipDialogLifeTime.longValue();
    }

    /**
     * Gets the total number of dialog fragments that have expired.
     *
     * @return The total number of dialog fragments that have expired
     */
    public long getEasExpiredSipDialogs() {
        return expiredSipDialogs.longValue();
    }
}
