/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

package monitoring.web.oss;

import ilog.cpl.datasource.IlpDataSource;
import ilog.cpl.service.IlpContext;
import integration.AlarmProvider;
import integration.DataSourceProvider;
import integration.IntegrationDispatcher;
import integration.IntegrationRequest;
import integration.RequestHandler;
import integration.impl.AbstractRequestHandler;
import integration.impl.DataSourcesHandler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import monitoring.shared.LoggingUtils;

/**
 * This abstraction acts as an integration provider that isolates its users from 
 * the intricacies of the integration API.
 * <p>  
 * It handles the <code>IntegrationDispatcher</code> creation as well as the
 * data sources initialization. It provides access to the
 * <code>DataSourceProvider</code> and <code>AlarmProvider</code> 
 * interfaces.
 * <p>
 * This bean needs the TGO context (<code>IlpContext</code>), the
 * prefix for the system identifier and the user identifier as parameters. This 
 * three properties must be set, before this bean can be used for integration purposes..
 */
abstract public class AbstractIntegrationProvider {

  /** The system id prefix */
  private String systemIdPrefix = null;

  /** The system id */
  private String systemId = null;

  /** The system id */
  private String userId = null;

  /** The TGO context */
  private IlpContext tgoContext = null;

  /** Whether the bean has been initialized or not */
  private boolean isInitialized;

  /** The data source handler reference */
  private DataSourcesHandler dsHandler;

  /** The integration dispatcher reference */
  private IntegrationDispatcher iDispatcher;

  /** The internal logger */
  private Logger logger;

  /** The request handler */
  private RequestHandler requestHandler;

  /**
   * Should create the <code>DataSourcesHandler</code> that is to be used.
   */
  abstract protected DataSourcesHandler createDataSourcesHandler(IlpContext tgoContext);

  /**
   * Should create the <code>DataSourcesHandler</code> that is to be used.
   */
  abstract protected RequestHandler createRequestHandler(IlpContext tgoContext);

  //////////////////////////////////////////////////////////////////////////////
  //Public API
  //////////////////////////////////////////////////////////////////////////////

  /**
   * Attempts to acknowledge the alarms provided.
   */
  public void acknowledgeAlarms(List<Object> alarmIdentifiers) {

    List<Object> alarmIdsInstances = getAlarmProvider().getAlarms(alarmIdentifiers);

    Map<String,Object> params = new HashMap<String,Object>();

    //Add the "alarm IDs" property
    params.put(IntegrationRequest.ParamKey.ALARMIDS_KEY, alarmIdsInstances);

    //Trigger the acknowledge
    getIntegrationDispatcher().dispatch(IntegrationRequest.Type.ACKNOWLEDGE_ALARMS,
        userId, params, null);
  }

  /**
   * Attempts to un-acknowledge the alarms provided.
   */
  public void unAcknowledgeAlarms(List<Object> alarmIdentifiers) {

    List<Object> alarmIdsInstances = getAlarmProvider().getAlarms(alarmIdentifiers);

    Map<String,Object> params = new HashMap<String,Object>();

    //Add the "alarm IDs" property
    params.put(IntegrationRequest.ParamKey.ALARMIDS_KEY, alarmIdsInstances);

    //Trigger the acknowledge
    getIntegrationDispatcher().dispatch(
        IntegrationRequest.Type.UNACKNOWLEDGE_ALARMS,
        userId, params, null);
  }

  /**
   * Attempts to load the data model information about the provided service on 
   * the provide data source.
   */
  public void loadServiceInformation(String serviceName, IlpDataSource dataSource) {
    try {

      // Create the parameters map
      Map<String,Object> params = new HashMap<String,Object>();

      // Add the data source to the DATASOURCE_KEY
      params.put(IntegrationRequest.ParamKey.DATASOURCE_KEY, dataSource);
      // Add the Service name to the EXTRA_KEY
      params.put(IntegrationRequest.ParamKey.EXTRA_KEY, serviceName);

      // Dispatch the request
      getIntegrationDispatcher().dispatch(
          IntegrationRequest.Type.QUERY_SERVICES_DETAIL_DATASOURCE,
          userId, params, null);

    } catch (Exception e) {
      LoggingUtils.getSampleLogger().log(Level.WARNING,
          "Could not find the information to show Service {0} in detail view with this exception: {1}",
          new Object[]{serviceName, e.getLocalizedMessage()});
    }
  }

  /**
   * The finalizer, which does the disconnection
   */
  protected void finalize() throws Throwable {
    // Terminate the data source provider
    dsHandler.terminate(iDispatcher);
    // Disconnect the dispatcher
    iDispatcher.disconnect();
  }

  //////////////////////////////////////////////////////////////////////////////
  //Accessors and Modifiers
  //////////////////////////////////////////////////////////////////////////////

  /** Access (set) the TGO context */
  public void setContext(IlpContext context) {
    tgoContext = context;
    initialize();
  }
  /** Access (set) the system identifier prefix */
  public void setSystemIdentifierPrefix(String prefix) {
    systemIdPrefix = prefix;
    initialize();
  }
  /** Access (set) the user id */
  public void setUserIdentifier(String userId) {
    this.userId = userId;
    initialize();
  }
  /** Access (set) the Request Handler */
  public void setRequestHandler(AbstractRequestHandler requestHandler) {
    this.requestHandler = requestHandler;
  }
  /** Access the system id */
  public String getSystemIdentifier() {
    return systemId;
  }
  /** Access the data source provider */
  public DataSourceProvider getDataSourceProvider() {
    return (DataSourceProvider) dsHandler;
  }
  /** Access the alarm provider */
  public AlarmProvider getAlarmProvider() {
    return (AlarmProvider) dsHandler;
  }
  /** Access the integration dispatcher */
  public IntegrationDispatcher getIntegrationDispatcher() {
    return iDispatcher;
  }
  /** Access the Request Handler */
  public RequestHandler getRequestHandler() {
    return requestHandler;
  }
  /** Access the user id */
  public String getUserIdentifier() {
    return userId;
  }
  
  //////////////////////////////////////////////////////////////////////////////
  //Private Members
  //////////////////////////////////////////////////////////////////////////////

  /**
   * This method initializes the integration modules.
   */
  private void initialize() {
    if (isInitialized) {
      return;
    }
    if (null == systemIdPrefix || null == tgoContext || null == userId) {
      return;
    }
    
    if(null == requestHandler) {
      requestHandler = createRequestHandler(tgoContext);
    }
    
    // Get the 'sample' logger
    logger = LoggingUtils.getSampleLogger();
    logger.log(Level.INFO,
        "Initializing integration provider with prefix {0}", systemIdPrefix);

    // Create integration dispatcher
    iDispatcher = new IntegrationDispatcher(logger);

    // Propagate the request handler
    iDispatcher.setRequestHandler(requestHandler);

    // Connect now
    systemId = iDispatcher.connect(systemIdPrefix);

    // Create data source provider
    dsHandler = createDataSourcesHandler(tgoContext);
    dsHandler.initialize(iDispatcher, null);

    // Subscribe alarm data source to Alarm Monitor
    Map<String,Object> params = new HashMap<String,Object>();
    params.put(IntegrationRequest.ParamKey.DATASOURCE_KEY, dsHandler.getAlarmDataSource());

    iDispatcher.dispatch(
        IntegrationRequest.Type.CONNECT_ALARM_MONITOR,
        userId, params, null);

    isInitialized = true;
  }
}