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

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

// jdk
import java.util.Map;
import java.util.Hashtable;
import java.util.logging.Logger;

// cib
import com.sun.mfwk.cib.statistics.CIBResourcePerfStats;
import com.sun.mfwk.cib.statistics.CIBValueStatistic;
import com.sun.mfwk.cib.statistics.CIBTimeStatistic;
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;

// Java ES-MF sdk
import com.sun.mfwk.util.log.MfLogService;
import com.sun.mfwk.cib.sdk.conn.CIBConnection;
import com.sun.mfwk.cib.sdk.util.CIBObjectNameMapFactory;

// 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;
import javax.management.*;
import com.sun.mfwk.cib.statistics.CIBServicePerfStats;
import com.sun.mfwk.cib.statistics.CIBCountStatistic;
import com.sun.mfwk.cib.statistics.CIBRangeStatistic;

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

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

  private CIBConnection myConnection = null;
  private Hashtable myTable = null;

  private boolean isInitialized = false;
  private boolean isStarted = false;

  private long myStartTime = -1;

  public CIBResourcePerfStatsImpl(
      MBeanServerConnection connection,
      String name) {
    logger.entering(className, "Constructor");
    try {
      myConnection = new CIBConnection(connection,
                                       CIBObjectNameMapFactory.
                                       getCIBResourcePerfStatsMap(name));
    }
    catch (MalformedObjectNameException ex) {
    }
    myTable = new Hashtable();

    // Create the Hashtable for the CIBResourcePerfStats
    myTable.put("FailedOperations",
                new CIBValueStatisticImpl("FailedOperations",
                                          "FailedOperations"));
    myTable.put("OperationTime",
                new CIBTimeStatisticImpl("OperationTime", "OperationTime"));

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

  public CIBResourcePerfStatsImpl(
      MBeanServerConnection connection,
      ObjectName name) {
    logger.entering(className, "Constructor");
    try {
      myConnection = new CIBConnection(connection,
                                       CIBObjectNameMapFactory.
                                       getCIBResourcePerfStatsMap(name));
    }
    catch (MalformedObjectNameException ex) {
    }
    myTable = new Hashtable();

    // Create the Hashtable for the CIBResourcePerfStats
    myTable.put("FailedOperations",
                new CIBValueStatisticImpl("FailedOperations",
                                          "FailedOperations"));
    myTable.put("OperationTime",
                new CIBTimeStatisticImpl("OperationTime", "OperationTime"));

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

  public CIBResourcePerfStatsImpl(
      MBeanServerConnection connection,
      Map map) {
    logger.entering(className, "Constructor");
    myConnection = new CIBConnection(connection, map);
    myTable = new Hashtable();

    // Create the Hashtable for the CIBResourcePerfStats
    myTable.put("FailedOperations",
                new CIBValueStatisticImpl("FailedOperations",
                                          "FailedOperations"));
    myTable.put("OperationTime",
                new CIBTimeStatisticImpl("OperationTime", "OperationTime"));

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

  /**
   * Return statistic object containing values regarding the Operation Time
   * @return TimeStatistic
   */
  public CIBTimeStatistic getOperationTime() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getOperationTime");
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;
      CIBTimeStatisticImpl statistic = (CIBTimeStatisticImpl) myTable.get(
          "OperationTime");

      logger.finest(className + " getAttribute MinOperationTime");
      attribute = myConnection.getAttribute("MinOperationTime");
      value = (new Long(attribute.getValue().toString())).longValue();
      statistic.setMinTime(value);

      logger.finest(className + " getAttribute MaxOperationTime");
      attribute = myConnection.getAttribute("MaxOperationTime");
      value = (new Long(attribute.getValue().toString())).longValue();
      statistic.setMaxTime(value);

      logger.finest(className + " getAttribute AccumulatedOperationTime");
      attribute = myConnection.getAttribute("AccumulatedOperationTime");
      value = (new Long(attribute.getValue().toString())).longValue();
      statistic.setTotalTime(value);

      logger.finest(className + " getAttribute NbOperations");
      attribute = myConnection.getAttribute("NbOperations");
      value = (new Long(attribute.getValue().toString())).longValue();
      statistic.setCount(value);

      logger.finest(className + " getAttribute AccumulatedSqOperationTime");
      attribute = myConnection.getAttribute("AccumulatedSqOperationTime");
      value = (new Long(attribute.getValue().toString())).longValue();
      statistic.setTotalSquaredTime(value);

      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, " getOperationTime", statistic.toString());
      return statistic;
    }
    else {
      logger.finest(className + " Stats Provider not Started");
      logger.exiting(className, "getOperationTime");
      return null;
    }
  }

  /**
   * Return a statistic object containing the number of failed operations
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getFailedOperations() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getFailedOperations");
    if (isStarted == true) {
      logger.finest(className + " Stats Provider Started");
      Attribute attribute = null;
      long value;

      CIBValueStatisticImpl statistic = (CIBValueStatisticImpl) myTable.get(
          "FailedOperations");

      logger.finest(className + " getAttribute FailedOperations");
      attribute = myConnection.getAttribute("FailedOperations");
      value = (new Long(attribute.getValue().toString())).longValue();
      statistic.setValue(value);
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, "getFailedOperations", statistic.toString());
      return statistic;
    }
    else {
      logger.finest(className + " Stats Provider not started");
      logger.exiting(className, "getFailedOperations");
      return null;
    }
  }

  /**
   * 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) {
      logger.finest(className + " Initialize the provider");
      super.init();
      stop();
      start();
      logger.finest(className + " Stats Provider initialized");
      isInitialized = true;
      isStarted = true;
    }
    else {
      logger.finest(className + " Stats Provider already initialized");
    }
    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) {
      logger.finest(className + " Stats Provider initialized");
      super.destroy();
      isInitialized = false;
      this.stop();
      logger.finest(className + " Stats Provider destroyed");
    }
    else {
      logger.finest(className + " Stats Provider already destroy");
    }
    logger.exiting(className, "destroy");
  }

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

  public void start() throws CIBIOException, CIBAttributeNotFoundException {
    logger.entering(className, "start");
    if (isStarted == false) {
      logger.finest(className + " Enable Monitoring for the provider");
      myConnection.invoke("enableMonitoring");
      logger.finest(className + " Stats provider started");
      myStartTime = System.currentTimeMillis();
      isStarted = true;
    }
    else {
      logger.finest(className + " Stats provider already started");
    }
    logger.exiting(className, "start");
  }

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

  public void stop() throws CIBIOException, CIBException {
    logger.entering(className, "stop");
    if (isStarted == true) {
      logger.finest(className + " Disable Monitoring for the provider");
      myConnection.invoke("disableMonitoring");
      isStarted = false;
      myStartTime = -1;
      logger.finest(className + " Stats provider stopped");
    }
    logger.exiting(className, "stop");
  }

  /**
   * 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 = "CIBResourcePerfStats";
    String statsDescription = "CIBResource 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");
      return null;
    }

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

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