/*
 * 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.shared;

import ilog.cpl.IlpNetwork;
import ilog.cpl.datasource.IlpDataSource;
import ilog.cpl.datasource.structure.IlpContainer;
import ilog.cpl.model.IlpAttribute;
import ilog.cpl.model.IlpClass;
import ilog.cpl.model.IlpClassManager;
import ilog.cpl.model.IlpObject;
import ilog.cpl.service.IlpContext;
import ilog.views.util.IlvResourceUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * This class provides service related utility methods. It manages the custom 
 * service classes and the mapping between Service Access Points and Services.
 * <p>
 * It is defined as a bean to be easily integrated.
 * <p>
 * Before using the API, the user must set the two data sources 
 * (services and service-network), otherwise this class will fail.
 */
public class ServicesUtils {

  // The service classes
  private IlpClass serviceManagedObjectClass = null;
  private IlpClass customerClass = null;
  private IlpClass slaClass = null;
  private IlpClass serviceClass = null;
  private IlpClass serviceAccessPointClass = null;
  private IlpClass servicePathClass = null;
  private IlpClass monitoringNEShortcutClass = null;

  // The attribute classes
  private IlpAttribute serviceAttrInServiceClass = null;
  private IlpAttribute serviceAttrInServicePathClass = null;
  private IlpAttribute serviceAttrInSAPClass = null;
  private IlpAttribute ownerIDAttrInMonitoringNEShortcutClass = null;

  // Keep reference to the data sources
  private IlpDataSource servicesDataSource;
  private IlpDataSource servicesNetworkDataSource;

  /**
   * Immediately after instantiating this class, the user
   * should set the context and data source properties.
   */
  public ServicesUtils() {
    // Does nothing
  }

  /**
   * It makes use of the given context to initialize the custom
   * service classes. 
   */
  public ServicesUtils(IlpContext context, IlpDataSource serviceTreeDS,
      IlpDataSource serviceNetworkDS) {
    setServicesDataSource(serviceTreeDS);
    setServicesNetworkDataSource(serviceNetworkDS);
  }

  /**
   * Initializes the custom classes and attributes.
   */
  private void initialize(IlpContext context) {
    if (null == customerClass) {
      IlpClassManager clsMgr = context.getClassManager();
      
      customerClass = clsMgr.getClass(MonitoringConstants.CUSTOMER_CLASS_NAME);
      
      slaClass = clsMgr.getClass(MonitoringConstants.SLA_CLASS_NAME);
      
      serviceClass = clsMgr.getClass(MonitoringConstants.SERVICE_CLASS_NAME);
      
      serviceAccessPointClass = 
        clsMgr.getClass(MonitoringConstants.SERVICE_ACCESS_POINT_CLASS_NAME);
      
      servicePathClass = clsMgr.getClass(MonitoringConstants.SERVICE_ACCESS_LINK_CLASS_NAME);

      serviceAttrInServiceClass = serviceClass.getAttribute("name");
      
      serviceAttrInSAPClass = 
        serviceAccessPointClass.getAttribute("Service");
      
      serviceAttrInServicePathClass = 
        servicePathClass.getAttribute("Service");
      
      serviceManagedObjectClass = 
        clsMgr.getClass(MonitoringConstants.SERVICE_MANAGED_OBJECT_CLASS_NAME);
      
      monitoringNEShortcutClass = 
        clsMgr.getClass(MonitoringConstants.MONITORING_NETWORK_ELEMENT_SHORTCUT_CLASS_NAME);
      
      ownerIDAttrInMonitoringNEShortcutClass = 
        monitoringNEShortcutClass.getAttribute("ownerID");
    }
  }

  /**
   * Sets the services data source
   * This method should be called only once.
   */
  public void setServicesDataSource(IlpDataSource servicesDS) {
    initialize(servicesDS.getContext());
    servicesDataSource = servicesDS;
  }
  /**
   * Return the services data source set in this bean
   */
  public IlpDataSource getServicesDataSource() {
    return servicesDataSource;
  }
  /**
   * Sets the services-network data source
   * This method should be called only once.
   */
  public void setServicesNetworkDataSource(IlpDataSource networkDS) {
    initialize(networkDS.getContext());
    servicesNetworkDataSource = networkDS;
  }
  /**
   * Return the services-network data source set in this bean
   */
  public IlpDataSource getServicesNetworkDataSource() {
    return servicesNetworkDataSource;
  }

  /**
   * Get service managed object class 
   */
  public IlpClass getServiceManagedObjectClass() {
    return serviceManagedObjectClass;
  }
  /**
   * Get customer class
   */
  public IlpClass getCustomerClass() {
    return customerClass;
  }
  /**
   * Get SLA class
   */
  public IlpClass getSlaClass() {
    return slaClass;
  }
  /**
   * Get service class
   */
  public IlpClass getServiceClass() {
    return serviceClass;
  }
  /**
   * Get SAP class
   */
  public IlpClass getServiceAccessPointClass() {
    return serviceAccessPointClass;
  }
  /**
   * Get path class
   */
  public IlpClass getServicePathClass() {
    return servicePathClass;
  }
  /**
   * Get monitoring NE shortcut class
   */
  public IlpClass getMonitoringNEShortcutClass() {
    return monitoringNEShortcutClass;
  }
  /**
   * Get service attribute in Service class
   */
  public IlpAttribute getServiceAttrInServiceClass() {
    return serviceAttrInServiceClass;
  }
  /**
   * Get service attribute in ServicePath class
   */
  public IlpAttribute getServiceAttrInServicePathClass() {
    return serviceAttrInServicePathClass;
  }
  /**
   * Get service attribute in SAP class
   */
  public IlpAttribute getServiceAttrInSAPClass() {
    return serviceAttrInSAPClass;
  }
  /**
   * Get owner ID attribute in monitoring NE shortcut class
   */
  public IlpAttribute getOwnerIDAttrInMonitoringNEShortcutClass() {
    return ownerIDAttrInMonitoringNEShortcutClass;
  }

  /**
   * Get the name of the service to which the given object is associated.
   */
  public String getServiceName(IlpObject ilpObj) {
    if (null == ilpObj) {
      return null;
    }
    IlpClass ilpClass = ilpObj.getIlpClass();
    if (servicePathClass.isAssignableFrom(ilpClass)) {
      return 
      ilpObj.getAttributeValue(serviceAttrInServicePathClass).toString();
    } else if (serviceClass.isAssignableFrom(ilpClass)) {
      return 
      ilpObj.getAttributeValue(serviceAttrInServiceClass).toString();
    } else if (serviceAccessPointClass.isAssignableFrom(ilpClass)) {
      return ilpObj.getAttributeValue(serviceAttrInSAPClass).toString();
    }
    return null;
  }

  /**
   * This convenience method retrieves the service corresponding
   * with the given service access point or link. 
   * 
   * It is used to identify the node in the service tree that
   * corresponds with the currently selected service access point
   * or link.
   */
  public IlpObject getServiceTreeNode(IlpObject networkNode) {
    if (null == networkNode) {
      return null;
    }
    return 
    getServicesDataSource().getObject(networkNode.getAttributeValue(serviceAttrInSAPClass));
  }

  /**
   * This convenience method retrieves a list of service access
   * points and links corresponding with the given service,
   * customer or SLA.
   * <p>
   * It is used to identify the service access points/links from
   * a selected node in the services tree.
   */
  public List<IlpObject> getServiceNetworkNodes(IlpObject treeNode) {
    Logger log = LoggingUtils.getSampleLogger();
    String msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"GettingServiceNetworkNodes");
    log.log(Level.FINE, msg);
    if (null == treeNode) {
      msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"Nulltreenode");
      log.log(Level.WARNING, msg);
      return Collections.emptyList();
    }
    List<IlpObject> ret = new ArrayList<IlpObject>();
    if (customerClass.isAssignableFrom(treeNode.getIlpClass())
        || slaClass.isAssignableFrom(treeNode.getIlpClass())) {
      // For customers or SLAs, call this method recursively on all children
      IlpContainer contItf = getServicesDataSource()
      .getContainerInterface(treeNode.getIdentifier());
      Collection<Object> children = null;
      if (null != contItf) {
        children = contItf.getChildren(treeNode);
      }
      if (null != children) {
        msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"Lookingforchildren");
        log.log(Level.FINER, msg, treeNode.getIdentifier());
        for (Object obj : children) {
          ret.addAll(getServiceNetworkNodes(getServicesDataSource().getObject(obj)));
        }
      } else {
        msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"hasNoChildren");
        log.log(Level.FINER, msg, treeNode.getIdentifier());
      }
    } else if (serviceClass.isAssignableFrom(treeNode.getIlpClass())) {
      // For service objects, iterate over all the objects in the network and 
      // find those that have the same service name
      String serviceName = getServiceName(treeNode);
      msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"GatheringNodesForService");
      log.log(Level.FINER, msg, serviceName);
      for (IlpObject networkObj : getServicesNetworkDataSource().getObjects()) {
        String serviceNameInNetworkObj = getServiceName(networkObj);
        if (serviceName.equals(serviceNameInNetworkObj)) {
          ret.add(networkObj);
        }
      }
    }
    return ret;
  }

  /**
   * Clears the highlighting on a given network component.
   */
  public void clearHighlightsInNetwork(IlpNetwork network) {
    Logger log = LoggingUtils.getSampleLogger();
    // Select objects which should be highlighted
    for (IlpObject networkObj : getServicesNetworkDataSource().getObjects()) {
      if (getServicePathClass().isAssignableFrom(networkObj.getIlpClass()) || 
          getServiceAccessPointClass().isAssignableFrom(networkObj.getIlpClass())) {
        String msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"UnhighlightingObject");
        log.log(Level.FINEST, msg, networkObj.getIdentifier());
        network.removePseudoClass(networkObj, "highlight");
      }
    }
  }

  /**
   * Highlight the corresponding network nodes of a given service tree node. 
   */
  public void highlightInNetwork(IlpNetwork network, IlpObject ilpObj) {
    Logger log = LoggingUtils.getSampleLogger();

    for (IlpObject networkObj : getServiceNetworkNodes(ilpObj)) {
      String msg=IlvResourceUtil.getServerLocaleString(ServicesUtils.class,"HighlightingObject");
      log.log(Level.FINER, msg, networkObj.getIdentifier());
      network.addPseudoClass(networkObj, "highlight");
    }
  }
}