/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 * 
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits réservés.
 * Ce logiciel est propriété de Sun Microsystems, Inc.
 * Distribué par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)MfGenericTransactionImpl.java 1.3     04/05/19 SMI"
 *
 */

package com.sun.mfwk.trans; 

import java.util.*;
import javax.management.*;
import java.util.logging.*;
import com.sun.mfwk.util.log.MfLogService;

/**
 * Generic class for transaction classes.
 */

public abstract class MfGenericTransactionImpl extends MfTranInterfaceImpl implements MfGenericTransaction {

    // States
    public static final int POOL = 1;
    public static final int RUNNING = 2;
    public static final int BLOCKED = 3;
    public static final int INVALID = 4;
    public static final int DISABLED = 5;
    public static final int WAITING_PARENT = 6;
    public static final int WAITING_SUB_TRANS = 7;

    public MfGenericTransactionImpl(MfTransactionDefinition def, MfGenericTransaction parent) {
	logger = getLogger();

        if ((def == null) || (def.getName() == null) || (def.getUri() == null)
            || (def.getTransactionMetrics() == null)) {
            setState(INVALID);
            this.setErrorCode(MfConstants.INVALID_DEFINITION);
            logger.finest("INVALID_DEFINITION : " + 
                          "(def == null) || (def.getName() == null) || (def.getUri() == null) || (def.getTransactionMetrics() == null)");
            return;
        }

        transDef = def;

        if (parent != null) {
            hasParent = true;
            parentTrans = parent;
	    if (((MfGenericTransactionImpl)parent).getState() == INVALID) {
		setState(INVALID);
		this.setErrorCode(MfConstants.INVALID_DEFINITION);
		logger.finest("INVALID_DEFINITION : " + "Parent transaction is INVALID");
		return;
	    }
	    ((MfGenericTransactionImpl) parent).addSubTransaction(this);
        }

        metricsMBean = getDefinition().getTransactionMetrics();
        hasCompInfo = getDefinition().hasComputingInfo();

	subTransactions = new Vector();

	// add this transaction as a listener of its MfTransactionMetrics MBean
	try {
	    metricsMBean.addNotificationListener(this, null, null);
	} catch(Exception e) {
	    // Should never happen!
	    logger.warning(e.toString());
	    return;
	}

	// Check if the related MfTransactionMetrics is disabled
	if (metricsMBean.isMonitoringEnabled() == false)
	    setState(DISABLED);
	else
	    setState(POOL);
    }

    protected int getState() {
	return state;
    }

    protected synchronized void setState(int st) {
	logger.entering("MfGenericTransactionImpl", "setState", new Integer(st));
	state = st;
    }

    public MfTransactionDefinition getDefinition() {
	setErrorCode(MfConstants.OK);
	return transDef;
    }

    public  MfGenericTransaction getParentTrans() {
	setErrorCode(MfConstants.OK);
	return parentTrans;
    }

    protected  MfTransactionMetrics getMetricsMBean() {
	return metricsMBean;
    }

    protected  Vector getSubTransactions() {
	return subTransactions;
    }

    protected boolean isParent() {
	return isParent;
    }

    protected boolean hasParent() {
	return hasParent;
    }

    protected boolean hasComputingInfo() {
	return hasCompInfo;
    }

    protected synchronized void addSubTransaction(MfGenericTransactionImpl subTrans) {
	logger.finest("Adding sub-transaction: " + subTrans.getDefinition().getName());
	subTransactions.add(subTrans);
	isParent = true;
    }

    protected synchronized void updateMinMax(long value, int metric) {
	long min = 0;
	long max = 0;
	int act = 0;

	if (metric == RESPONSE_TIME) {
	    min = metricsMBean.getMinResponseTime();
	    max = metricsMBean.getMaxResponseTime();
	} else if (metric == SERVICE_TIME) {
	    min = metricsMBean.getMinServiceTime();
	    max = metricsMBean.getMaxServiceTime();
	} else if (metric == SINGLE_SERVICE_TIME) {
	    min = metricsMBean.getSingleMinServiceTime();
	    max = metricsMBean.getSingleMaxServiceTime();
	}

	if (min == 0 && max == 0)
	    act = INIT_MIN_MAX;
	else if (value < min)
	    act = MIN_CROSSED;
	else if (value > max)
	    act = MAX_CROSSED;

	if (metric == RESPONSE_TIME) {
	    if (act == MIN_CROSSED)
		metricsMBean.setMinResponseTime(value);
	    else if (act == MAX_CROSSED)
		metricsMBean.setMaxResponseTime(value);
	    else if (act == INIT_MIN_MAX) {
		metricsMBean.setMinResponseTime(value);
		metricsMBean.setMaxResponseTime(value);
	    }		    
	} else if (metric == SERVICE_TIME) {
	    if (act == MIN_CROSSED)
		metricsMBean.setMinServiceTime(value);
	    else if (act == MAX_CROSSED)
		metricsMBean.setMaxServiceTime(value);
	    else if (act == INIT_MIN_MAX) {
		metricsMBean.setMinServiceTime(value);
		metricsMBean.setMaxServiceTime(value);
	    }		    
	} else if (metric == SINGLE_SERVICE_TIME) {
	    if (act == MIN_CROSSED)
		metricsMBean.setSingleMinServiceTime(value);
	    else if (act == MAX_CROSSED)
		metricsMBean.setSingleMaxServiceTime(value);
	    else if (act == INIT_MIN_MAX) {
		metricsMBean.setSingleMinServiceTime(value);
		metricsMBean.setSingleMaxServiceTime(value);
	    }		    
	}
    }

    ////////////////////////////////////////////////////
    //
    // Implementation of NotificationListener interface
    //
    ////////////////////////////////////////////////////

    public void handleNotification(Notification notif, Object handback) {

	logger.entering("MfGenericTransactionImpl", "handleNotification");
	logger.finest("MfGenericTransactionImpl -> handleNotification: Receive a notification" +
		      " of type " + notif.getType() +
		      " with the sequence number " + notif.getSequenceNumber());

	String type = notif.getType();

	if (type.equals(AttributeChangeNotification.ATTRIBUTE_CHANGE)) {
	    String attName = ((AttributeChangeNotification)notif).getAttributeName();
	    if (attName.equals("MonitoringEnabled")) {
		setState(POOL);
	    } else if (attName.equals("MonitoringDisabled")) {
		setState(DISABLED);
	    }
	}
    }

    private MfTransactionDefinition transDef = null;
    private MfGenericTransaction parentTrans = null;
    private MfTransactionMetrics metricsMBean = null;
    private boolean hasCompInfo = true;
    private Vector subTransactions = null;
    private boolean isParent = false;
    private boolean hasParent = false;
    private int state = POOL;
    private int errorCode = 0;
    private Logger logger = null;

    private static final int INIT_MIN_MAX = 1;
    private static final int MIN_CROSSED = 2;
    private static final int MAX_CROSSED = 3;
    protected static final int RESPONSE_TIME = 1;
    protected static final int SERVICE_TIME = 2;
    protected static final int SINGLE_SERVICE_TIME = 3;
}
