/*
 * 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        "@(#)CIBApplicationPerfStatsImpl.java 1.17     04/07/15 SMI"
 *
 */

package com.sun.mfwk.cib.sdk.statistics;

// Jdk
import java.util.Hashtable;
import java.util.logging.Logger;

// Core information base
import com.sun.mfwk.cib.CIBApplicationMBean;
import com.sun.mfwk.cib.statistics.CIBApplicationPerfStats;
import com.sun.mfwk.cib.statistics.CIBServicePerfStats;
import com.sun.mfwk.cib.statistics.CIBValueStatistic;
import com.sun.mfwk.cib.statistics.CIBStatistic;
import com.sun.mfwk.cib.statistics.CIBStats;
import com.sun.mfwk.cib.CIBException;
import com.sun.mfwk.cib.CIBIOException;
import com.sun.mfwk.cib.CIBAttributeNotFoundException;

// Jesmf sdk
import com.sun.mfwk.util.log.MfLogService;
import com.sun.mfwk.cib.sdk.conn.CIBConnection;

// Jmx
import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.CompositeType;

// j2ee
import javax.management.j2ee.statistics.Statistic;

/**
 * Provides a default implementation of a CIBApplicationPerfStats provider for
 * a CIBApplication.
 * This implementation is fully based on the Java-ES MF Instrumentation SDK.
 */
public class CIBApplicationPerfStatsImpl
    extends CIBPerfStatsImpl
    implements CIBApplicationPerfStats {

  static final Logger logger = MfLogService.getLogger("cib-sdk");
  static final String className = "CIBApplicationPerfStatsImpl";

  // Communication
  private CIBConnection myConnection = null;

  private CIBServicePerfStats[] myServicesStats = null;
  private Hashtable myTable;

  // Time when the measurement has begun
  private long myStartTime = -1;

  private boolean isInitialized = false;

  /**
   * Constructor
   * @param services CIBServicePerfStats[]
   */
  public CIBApplicationPerfStatsImpl(CIBServicePerfStats[] services) {
    logger.entering(className, "Constructor");
    myServicesStats = services;
    myTable = new Hashtable();
    myTable.put("AverageResidentTime",
                new CIBValueStatisticImpl("AverageResidentTime",
                                          "Average Resident Time"));
    myTable.put("AverageServiceTime",
                new CIBValueStatisticImpl("AverageServiceTime",
                                          "Average Service Time"));

    myTable.put("TotalInRequests",
                new CIBValueStatisticImpl("TotalInRequests",
                                          "Total in Requests Time"));

    myTable.put("TotalOutRequests",
                new CIBValueStatisticImpl("TotalOutRequests",
                                          "Average out requests Time"));

    myTable.put("TotalFailedRequests",
                new CIBValueStatisticImpl("TotalFailedRequests",
                                          "Total Failed Requests"));

    super.statisticsTable = myTable;
    logger.exiting(className, "constructor", myTable);
  }

  /**
   * Constructor
   */
  public CIBApplicationPerfStatsImpl() {
    logger.entering(className, "Constructor");
    myTable = new Hashtable();
    myTable.put("AverageResidentTime",
                new CIBValueStatisticImpl("AverageResidentTime",
                                          "Average Resident Time"));
    myTable.put("AverageServiceTime",
                new CIBValueStatisticImpl("AverageServiceTime",
                                          "Average Service Time"));

    myTable.put("TotalInRequests",
                new CIBValueStatisticImpl("TotalInRequests",
                                          "Total in Requests Time"));

    myTable.put("TotalOutRequests",
                new CIBValueStatisticImpl("TotalOutRequests",
                                          "Average out requests Time"));

    myTable.put("TotalFailedRequests",
                new CIBValueStatisticImpl("TotalFailedRequests",
                                          "Total Failed Requests"));

    super.statisticsTable = myTable;
    logger.exiting(className, "constructor", myTable);
  }

  /**
   * Set the services providers on the application providers
   * @param services CIBServicePerfStats[]
   */
  public void addServicesPerfStats(CIBServicePerfStats[] services) {

    int statsLength = 0;
    int servicesLength = 0;

    // Check parameters
    if (myServicesStats != null) {
      statsLength = myServicesStats.length;
    }
    if (services != null) {
      servicesLength = services.length;
    }
    if ( (statsLength == 0) && (servicesLength == 0)) {
      return;
    }

    CIBServicePerfStats[] addServices = new CIBServicePerfStats[statsLength +
        servicesLength];

    for (int i = 0; i < statsLength; i++) {
      addServices[i] = myServicesStats[i];
    }

    System.arraycopy(services, 0, addServices, statsLength, servicesLength);
    myServicesStats = addServices;
  }

  /**
   * Get the Average ResidentTime
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getAverageResidentTime() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getAverageResidentTime");
    CIBValueStatisticImpl statistic = (CIBValueStatisticImpl) myTable.get(
        "AverageResidentTime");

    if ( (myServicesStats == null) || (myServicesStats.length == 0)) {
      statistic.setValue(0);
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, "getAverageResidentTime", statistic.toString());
      return statistic;
    }

    long average = 0;
    for (int i = 0; i < myServicesStats.length; i++) {
      average = average + myServicesStats[i].getResidentTime().getTotalTime();
    }
    statistic.setValue(average / myServicesStats.length);
    statistic.setLastSampleTime(System.currentTimeMillis());
    statistic.setStartTime(myStartTime);
    logger.exiting(className, "getAverageResidentTime", statistic.toString());
    return statistic;
  }

  /**
   * Gets the Average ServiceTime
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getAverageServiceTime() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getAverageServiceTime");
    CIBValueStatisticImpl statistic = (CIBValueStatisticImpl) myTable.get(
        "AverageServiceTime");

    if ( (myServicesStats == null) || (myServicesStats.length == 0)) {
      statistic.setValue(0);
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, "getAverageServiceTime", statistic.toString());
      return statistic;
    }

    long average = 0;
    for (int i = 0; i < myServicesStats.length; i++) {
      average = average + myServicesStats[i].getServiceTime().getTotalTime();
    }

    statistic.setValue(average / myServicesStats.length);
    statistic.setLastSampleTime(System.currentTimeMillis());
    statistic.setStartTime(myStartTime);
    logger.exiting(className, "getAverageServiceTime", statistic.toString());
    return statistic;

  }

  /**
   * Get the Total FailedRequests of the Application
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getTotalFailedRequests() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getTotalFailedRequests");
    CIBValueStatisticImpl statistic = (CIBValueStatisticImpl) myTable.get(
        "TotalFailedRequests");

    if ( (myServicesStats == null) || (myServicesStats.length == 0)) {
      statistic.setValue(0);
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, "getTotalFailedRequests", statistic.toString());
      return statistic;
    }

    long total = 0;
    for (int i = 0; i < myServicesStats.length; i++) {
      total = total + myServicesStats[i].getFailedRequests().getCount();
    }
    statistic.setValue(total);
    statistic.setLastSampleTime(System.currentTimeMillis());
    statistic.setStartTime(myStartTime);
    logger.exiting(className, "getTotalFailedRequests", statistic.toString());
    return statistic;
  }

  /**
   * Gets the Total InRequests of the application
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getTotalInRequests() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getTotalInRequests");
    CIBValueStatisticImpl statistic = (CIBValueStatisticImpl) myTable.get(
        "TotalInRequests");

    if ( (myServicesStats == null) || (myServicesStats.length == 0)) {
      statistic.setValue(0);
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, "getTotalInRequests", statistic.toString());
      return statistic;
    }

    long total = 0;
    for (int i = 0; i < myServicesStats.length; i++) {
      total = total + myServicesStats[i].getInRequests().getCount();
    }

    statistic.setValue(total);
    statistic.setLastSampleTime(System.currentTimeMillis());
    statistic.setStartTime(myStartTime);
    logger.exiting(className, "getTotalInRequests", statistic.toString());
    return statistic;

  }

  /**
   * Gets the Total OutRequests
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getTotalOutRequests() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getTotalOutRequests");
    CIBValueStatisticImpl statistic = (CIBValueStatisticImpl) myTable.get(
        "TotalOutRequests");

    if ( (myServicesStats == null) || (myServicesStats.length == 0)) {
      statistic.setValue(0);
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, "getTotalOutRequests", statistic.toString());
      return statistic;
    }

    long total = 0;
    for (int i = 0; i < myServicesStats.length; i++) {
      total = total + myServicesStats[i].getOutRequests().getCount();
    }

    statistic.setValue(total);
    statistic.setLastSampleTime(System.currentTimeMillis());
    statistic.setStartTime(myStartTime);
    logger.exiting(className, "getTotalOutRequests", statistic.toString());
    return statistic;
  }

  /**
   * Initialize the statistics mechanism. In particular, initialize the
   * communication to the instrumentation layer.
   */
  public void init() throws CIBIOException, CIBException {
    logger.entering(className, "init");
    if (isInitialized == false) {
      // nothing to do
      super.init();
      isInitialized = true;
      myStartTime = System.currentTimeMillis();
    }
    logger.exiting(className, "init");
  }

  /**
   * destroy the statistics and clean the statistics objects/values
   * when needed, close all the communications.
   */

  public void destroy() throws CIBIOException, CIBException {
    logger.entering(className, "destroy");

    if (isInitialized == true) {
      // nothing to do
      super.destroy();
      isInitialized = false;
      myStartTime = -1;
    }
    logger.exiting(className, "destroy");
  }

  /**
   * toCompositeData
   *
   * @return CompositeData
   */
  public CompositeData toCompositeData() throws OpenDataException {

    logger.entering(className, "toCompositeData");

    // Build the itemNames


    // Build the descrition;
    Statistic[] statistics = getStatistics();

    // CompositeData Type for statistics
    OpenType[] itemTypes = new OpenType[statistics.length];
    String[] itemNames = new String[statistics.length];
    String[] itemDescriptions = new String[statistics.length];

    CompositeData[] statisticsData = new CompositeDataSupport[statistics.length];

    // Build the compositeData
    for (int i = 0; i < statistics.length; i++) {
      statisticsData[i] = ( (CIBStatistic) statistics[i]).toCompositeData();
      itemTypes[i] = ( (CIBStatistic) statistics[i]).toCompositeData().
          getCompositeType();
      itemNames[i] = statistics[i].getName();
      itemDescriptions[i] = statistics[i].getDescription();
    }

    String statsName = "CIBApplicationPerfStats";
    String statsDescription = "CIBApplication Performance Statistics";
    CompositeType statsTypes = null;
    CompositeDataSupport data = null;

    try {
      statsTypes = new CompositeType(statsName, statsDescription, itemNames,
                                     itemDescriptions, itemTypes);

      data = new CompositeDataSupport(statsTypes, itemNames, statisticsData);
    }
    catch (OpenDataException e) {
      logger.throwing(className, "toCompositeData", e);
      logger.exiting(className, "toCompositeData");
      throw e;
    }

    logger.exiting(className, "toCompositeData");
    return data;
  }

  /**
   * Returns a CIBStats object from a compsoite data object
   * @param data CompositeData
   * @return CIBStats
   */
  public CIBStats fromCompositeData(CompositeData data) {
    logger.entering(className, "fromCompositeData");
    logger.exiting(className, "fromCompositeData");
    return null;
  }

}
