/*
 * 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        "@(#)CIBExternalResourcePerfStatsImpl.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;

// 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;

// cib
import com.sun.mfwk.cib.statistics.CIBExternalResourcePerfStats;
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.CIBAttributeNotFoundException;
import com.sun.mfwk.cib.CIBIOException;
import com.sun.mfwk.cib.CIBException;

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

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

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

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

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

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

  private long myStartTime = -1;

  public CIBExternalResourcePerfStatsImpl(
      MBeanServerConnection connection,
      String name) {

    logger.entering(className, "Constructor");
    try {
      myConnection = new CIBConnection(connection,
                                       CIBObjectNameMapFactory.
                                       getCIBExternalResourcePerfStatsMap(name));
    }
    catch (MalformedObjectNameException ex) {
    }
    // Create the hashTable for the CIBExternalServicePerfStats
    myTable = new Hashtable();
    myTable.put("AccumulatedOutboundAssociations",
                new CIBValueStatisticImpl(
        "AccumulatedOutboundAssociations",
        "Accumulated Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("FailedOutboundAssociations",
                new CIBValueStatisticImpl(
        "FailedOutboundAssociations",
        "Failed Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("FailedQueries",
                new CIBValueStatisticImpl("FailedQueries",
                                          "Number of Failed Queries of a CIBExternalServicePerfStats"));
    myTable.put("LastOutboundActivity",
                new CIBValueStatisticImpl("LastOutboundActivity",
                                          "Time of Last Outbound Activity of a CIBExternalServicePerfStats"));
    myTable.put("OutboundAssociations",
                new CIBValueStatisticImpl("OutboundAssociations",
                                          "Number of Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("QueriesTime",
                new CIBTimeStatisticImpl("QueriesTime",
                                         "Queries Time of a CIBExternalServicePerfStats"));

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

  public CIBExternalResourcePerfStatsImpl(
      MBeanServerConnection connection,
      ObjectName name) {

    logger.entering(className, "Constructor");
    try {
      myConnection = new CIBConnection(connection,
                                       CIBObjectNameMapFactory.
                                       getCIBExternalResourcePerfStatsMap(name));
    }
    catch (MalformedObjectNameException ex) {
    }
    // Create the hashTable for the CIBExternalServicePerfStats
    myTable = new Hashtable();
    myTable.put("AccumulatedOutboundAssociations",
                new CIBValueStatisticImpl(
        "AccumulatedOutboundAssociations",
        "Accumulated Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("FailedOutboundAssociations",
                new CIBValueStatisticImpl(
        "FailedOutboundAssociations",
        "Failed Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("FailedQueries",
                new CIBValueStatisticImpl("FailedQueries",
                                          "Number of Failed Queries of a CIBExternalServicePerfStats"));
    myTable.put("LastOutboundActivity",
                new CIBValueStatisticImpl("LastOutboundActivity",
                                          "Time of Last Outbound Activity of a CIBExternalServicePerfStats"));
    myTable.put("OutboundAssociations",
                new CIBValueStatisticImpl("OutboundAssociations",
                                          "Number of Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("QueriesTime",
                new CIBTimeStatisticImpl("QueriesTime",
                                         "Queries Time of a CIBExternalServicePerfStats"));

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

  public CIBExternalResourcePerfStatsImpl(
      MBeanServerConnection connection,
      Map map) {

    logger.entering(className, "Constructor");
    myConnection = new CIBConnection(connection, map);
    // Create the hashTable for the CIBExternalServicePerfStats
    myTable = new Hashtable();
    myTable.put("AccumulatedOutboundAssociations",
                new CIBValueStatisticImpl(
        "AccumulatedOutboundAssociations",
        "Accumulated Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("FailedOutboundAssociations",
                new CIBValueStatisticImpl(
        "FailedOutboundAssociations",
        "Failed Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("FailedQueries",
                new CIBValueStatisticImpl("FailedQueries",
                                          "Number of Failed Queries of a CIBExternalServicePerfStats"));
    myTable.put("LastOutboundActivity",
                new CIBValueStatisticImpl("LastOutboundActivity",
                                          "Time of Last Outbound Activity of a CIBExternalServicePerfStats"));
    myTable.put("OutboundAssociations",
                new CIBValueStatisticImpl("OutboundAssociations",
                                          "Number of Outbound Associations of a CIBExternalServicePerfStats"));
    myTable.put("QueriesTime",
                new CIBTimeStatisticImpl("QueriesTime",
                                         "Queries Time of a CIBExternalServicePerfStats"));

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

  ///////////////////////////////////////
  // operations

  /**
   * Returns a Statistic representing the total number of associations to the application entity
   * since application initialization, where it was the initiator.
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getAccumulatedOutboundAssociations() throws
      CIBIOException, CIBAttributeNotFoundException {
    String methodName = "getAccumulatedOutboundAssociations";
    logger.entering(className, methodName);
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;

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

      logger.finest(className + " getAttribute AccumulatedOutboundAssociations");
      attribute = myConnection.getAttribute("AccumulatedOutboundAssociations");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setValue(value);
        statistic.setLastSampleTime(System.currentTimeMillis());
        statistic.setStartTime(myStartTime);
      }

      logger.exiting(className, methodName,
                     statistic.toString());
      return statistic;
    }
    else {
      logger.finest(className + " Stats Provider not Started");
      logger.exiting(className, methodName);
      return null;
    }
  }

  /**
   * Returns a Statistic representing the total number associations where the application entity
   * is initiator and association establishment has failed,
   * since application initialization.  Failed associations are
   * not counted in the accumulated association totals."
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getFailedOutboundAssociations() throws
      CIBIOException, CIBAttributeNotFoundException {
    String methodName = "getFailedOutboundAssociations";
    logger.entering(className, methodName);
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;

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

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

  /**
   * Return a Statistic representing the number of current associations to the network service
   * application, where it is the initiator.  An outbound
   * association occurs when this application successfully
   * connects to another one.
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getOutboundAssociations() throws CIBIOException,
      CIBAttributeNotFoundException {
    String methodName = "getOutboundAssociations";
    logger.entering(className, methodName);
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;

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

      logger.finest(className + " getAttribute OutboundAssociations");

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

  /**
   * Returns a Statistic representing the value of sysUpTime at the time this application last
   * had an outbound association.
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getLastOutboundActivity() throws CIBIOException,
      CIBAttributeNotFoundException {
    String methodName = "getLastOutboundActivity";
    logger.entering(className, methodName);
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;

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

      logger.finest(className + " getAttribute LastOutboundActivity");
      attribute = myConnection.getAttribute("LastOutboundActivity");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setValue(value);
        statistic.setLastSampleTime(System.currentTimeMillis());

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

  /**
   * Returns a Statistic object representing the time for queries
   * @return CIBTimeStatistic
   */
  public CIBTimeStatistic getQueriesTime() throws CIBIOException,
      CIBAttributeNotFoundException {
    String methodName = "getQueriesTime";
    logger.entering(className, methodName);
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;

      CIBTimeStatisticImpl statistic = (CIBTimeStatisticImpl) myTable.get(
          "QueriesTime");

      logger.finest(className + " getAttribute MinQueriesTime");
      attribute = myConnection.getAttribute("MinQueriesTime");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setMinTime(value);
      }

      logger.finest(className + " getAttribute MaxQueriesTime");
      attribute = myConnection.getAttribute("MaxQueriesTime");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setMaxTime(value);
      }

      logger.finest(className + " getAttribute AccumulatedQueriesTime");
      attribute = myConnection.getAttribute("AccumulatedQueriesTime");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setTotalTime(value);
      }

      logger.finest(className + " getAttribute NbQueries");
      attribute = myConnection.getAttribute("NbQueries");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setCount(value);
      }

      logger.finest(className + " getAttribute AccumulatedSqQueriesTime");
      attribute = myConnection.getAttribute("AccumulatedSqQueriesTime");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setTotalSquaredTime(value);
      }

      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, methodName, statistic.toString());
      return statistic;
    }

    else {
      logger.finest(className + " Stats Provider not Started");
      logger.exiting(className, methodName);
      return null;
    }

  }

  /**
   * Returns a Statistic object containing the number of failed queries
   * @return CIBValueStatistic
   */
  public CIBValueStatistic getFailedQueries() throws CIBIOException,
      CIBAttributeNotFoundException {
    logger.entering(className, "getFailedQueries");
    if (isStarted == true) {
      logger.finest(className + " Stats Provider started");
      Attribute attribute = null;
      long value;

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

      logger.finest(className + " getAttribute FailedQueries");
      attribute = myConnection.getAttribute("FailedQueries");
      if (attribute != null) {
        value = (new Long(attribute.getValue().toString())).longValue();
        statistic.setValue(value);
      }
      statistic.setLastSampleTime(System.currentTimeMillis());
      statistic.setStartTime(myStartTime);
      logger.exiting(className, " getFailedQueries", statistic.toString());
      return statistic;
    }
    else {
      logger.finest(className + " Stats Provider not Started");
      logger.exiting(className, "getFailedQueries");
      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();
      this.stop();
      this.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;
      stop();
      logger.finest(className + " Stats Provider destroyed");
    }
    else {
      logger.finest(className + " Stats Provider already destroy");
    }
    logger.exiting(className, "destroy");
  }

  /**
   * Start the monitoring
   */
  public void start() throws CIBIOException, CIBException {
    logger.entering(className, "start");
    if (isStarted == false) {
      logger.finest(className + " Enable Monitoring for the provider");
      myConnection.invoke("enableMonitoring");
      logger.finest(className + " Stats provider started");
      isStarted = true;
      myStartTime = System.currentTimeMillis();
    }
    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 = "CIBExternalResourcePerfStats";
    String statsDescription = "CIBExternalResource 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 composite data
   * @param data CompositeData
   * @return CIBStats
   */
  public CIBStats fromCompositeData(CompositeData data) {
    logger.entering(className, "fromCompositeData");
    logger.exiting(className, "fromCompositeData");
    return null;
  }
}
