/*
 * 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        "@(#)MfTranReportImpl.java 1.14     04/07/01 SMI"
 *
 */

package com.sun.mfwk.trans; 

import java.util.logging.*;
import java.util.*;

/**
 * Implementation of the MfTranReport interface
 */

class MfTranReportImpl extends MfGenericTransactionImpl implements MfTranReport {

    public MfTranReportImpl (MfTransactionDefinition def, MfTranReport parent) {
	super(def, (MfGenericTransaction) parent);
	logger = getLogger();
    }

    public synchronized int report(int pstatus, long respTime, long pservTime, long stopTime) {
	logger.entering("TransactionReportImpl", "report", new Integer(pstatus));

	this.setErrorCode(MfConstants.OK);

	// Check if the transition is valid vs the state diagram
	if (isParent()) {
	    // parent transaction
	    if (getState() != WAITING_SUB_TRANS) {
		if (getState() == DISABLED) {
		    setErrorCode(MfConstants.MONITORING_DISABLED);
		    logger.finest("MONITORING_DISABLED");		
		} else {
		    setErrorCode(MfConstants.INVALID_TRANSITION);
		    logger.finest("INVALID_TRANSITION : " +
				  "getState() != WAITING_SUB_TRANS");
		}
		return MfConstants.NOT_OK;
	    }
	    for (Enumeration e=getSubTransactions().elements(); e.hasMoreElements();) {
		MfTranReportImpl subTrans = (MfTranReportImpl) e.nextElement();
		if (subTrans.getState() != WAITING_PARENT) {
		    setErrorCode(MfConstants.INVALID_TRANSITION);
		    logger.finest("INVALID_TRANSITION : " +
				  "subTrans.getState() != WAITING_PARENT");
		    return MfConstants.NOT_OK;
		}
	    }
	} else {
	    // sub-transaction or Simple transaction
	    if (getState() != POOL) {
		if (getState() == DISABLED) {
		    setErrorCode(MfConstants.MONITORING_DISABLED);
		    logger.finest("MONITORING_DISABLED");		
		} else {
		    setErrorCode(MfConstants.INVALID_TRANSITION);
		    logger.finest("INVALID_TRANSITION : " +
				  "getState() != POOL");
		}
		return MfConstants.NOT_OK;
	    }
	}

	servTime = pservTime;
	
	MfTransactionMetrics metrics = getMetricsMBean();

	synchronized (metrics) {
	    metrics.setNbInRequests(metrics.getNbInRequests() + 1);

	    status = pstatus;

	    // Response time update
	    metrics.setAccumulatedResponseTime(metrics.getAccumulatedResponseTime() + respTime);
	    metrics.setAccumulatedSqResponseTime(metrics.getAccumulatedSqResponseTime() + (respTime*respTime));
	}
	updateMinMax(respTime, RESPONSE_TIME);

	if (!isParent()) {
	    // This is NOT a parent transaction

	    synchronized (metrics) {
		if (status == MfConstants.STATUS_FAILED)
		    metrics.setNbFailedRequests(metrics.getNbFailedRequests() + 1);
		else if (status == MfConstants.STATUS_ABORT)
		    metrics.setNbAbortedRequests(metrics.getNbAbortedRequests() + 1);
		else
		    metrics.setNbOutRequests(metrics.getNbOutRequests() + 1);

		// Service time update
		metrics.setAccumulatedServiceTime(metrics.getAccumulatedServiceTime() + servTime);
		metrics.setAccumulatedSqServiceTime(metrics.getAccumulatedSqServiceTime() + (servTime*servTime));
	    }
	    updateMinMax(servTime, SERVICE_TIME);

	    if (hasParent()) {
		setState(WAITING_PARENT);
		MfTranReportImpl parent = (MfTranReportImpl)getParentTrans();
		if (parent.getState() == POOL)
		    parent.setState(WAITING_SUB_TRANS);
	    }
	    else
		setState(POOL);

	} else {
	    // This is a parent transaction

	    // Initialize the correlated metrics to the ones of the parent (ie this) transaction

	    int corrStatus = status;
	    long corrServTime = servTime;
	    for (Enumeration enumer=getSubTransactions().elements(); enumer.hasMoreElements();) {
		// Add to this transaction servTime, the servTime of all the sub-transactions
		MfTranReportImpl subTrans = (MfTranReportImpl) enumer.nextElement();
		corrServTime += subTrans.getServTime();
		// Check if at least one of the sub-transactions has failed or aborted
		if (subTrans.status == MfConstants.STATUS_FAILED)
		    corrStatus = MfConstants.STATUS_FAILED;
		else if (subTrans.status == MfConstants.STATUS_ABORT)
		    corrStatus = MfConstants.STATUS_ABORT;
	    }

	    // Update the correlated metrics
	    synchronized (metrics) {
		if (corrStatus == MfConstants.STATUS_FAILED)
		    metrics.setNbFailedRequests(metrics.getNbFailedRequests() + 1);
		else if (corrStatus == MfConstants.STATUS_ABORT)
		    metrics.setNbAbortedRequests(metrics.getNbAbortedRequests() + 1);
		else
		    metrics.setNbOutRequests(metrics.getNbOutRequests() + 1);

		metrics.setAccumulatedServiceTime(metrics.getAccumulatedServiceTime() + corrServTime);
		metrics.setAccumulatedSqServiceTime(metrics.getAccumulatedSqServiceTime() + (corrServTime*corrServTime));

		updateMinMax(corrServTime, SERVICE_TIME);

		// Update the metrics related to the parent (ie this) transaction only
		if (status == MfConstants.STATUS_FAILED)
		    metrics.setSingleNbFailedRequests(metrics.getSingleNbFailedRequests() + 1);
		else if (status == MfConstants.STATUS_ABORT)
		    metrics.setSingleNbAbortedRequests(metrics.getSingleNbAbortedRequests() + 1);

		metrics.setSingleAccumulatedServiceTime(metrics.getSingleAccumulatedServiceTime() + servTime);
		metrics.setSingleAccumulatedSqServiceTime(metrics.getSingleAccumulatedSqServiceTime() + (servTime*servTime));
	    }
	    updateMinMax(servTime, SINGLE_SERVICE_TIME);

	    // Update the parent transaction (this) and its sub-transactions states
	    for (Enumeration enumer=getSubTransactions().elements(); enumer.hasMoreElements();) {
		((MfTranReportImpl) enumer.nextElement()).setState(POOL);
	    }
	    setState(POOL);

	}
	return MfConstants.OK;
    }

    protected long getServTime() {
	return servTime;
    }

    private int status = 0;
    private long servTime = 0;
    private Logger logger = null;
}
