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

import ilog.cpl.IlpEquipment;
import ilog.cpl.datasource.IlpAbstractHierarchyAdapter;
import ilog.cpl.datasource.IlpDataSource;
import ilog.cpl.datasource.structure.IlpChild;
import ilog.cpl.model.IlpObject;
import ilog.tgo.model.IltCardItem;
import ilog.tgo.model.IltShelf;
import ilog.tgo.model.IltShelfItem;
import ilog.views.util.IlvResourceUtil;

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

import monitoring.shared.CommonUtils;
import monitoring.shared.LoggingUtils;


/**
 * Implementation of the "drill-down" mechanism for an <code>IlpEquipment</code>.
 */
public class EquipmentDrillDownManager extends AbstractDrillDownManager {

  /**
   * <code>IlpEquipment</code> implementation.
   * 
   * @see monitoring.shared.drilldown.AbstractDrillDownManager#getAdapter()
   */
  protected IlpAbstractHierarchyAdapter getAdapter() {
    return getEquipment().getAdapter();
  }

  /**
   * <code>IlpEquipment</code> implementation.
   * 
   * @see monitoring.shared.drilldown.AbstractDrillDownManager#ensureComponentIsVisible()
   */
  protected void ensureComponentIsVisible() {
    getEquipment().getView().ensureVisible();
  }

  /**
   * <code>IlpEquipment</code> implementation.
   * 
   * @see monitoring.shared.drilldown.AbstractDrillDownManager#ensureObjectIsVisibleInComponent(ilog.cpl.model.IlpObject)
   */
  protected void ensureObjectIsVisibleInComponent(IlpObject object) {
    getEquipment().ensureVisible(object);
  }

  /**
   * <code>IlpEquipment</code> implementation.
   * 
   * @see monitoring.shared.drilldown.AbstractDrillDownManager#selectObjectInComponent(ilog.cpl.model.IlpObject)
   */
  protected void selectObjectInComponent(IlpObject object) {
    getEquipment().getSelectionModel().setSelectedObject(object);
  }
  
  /**
   * <code>IlpEquipment</code> implementation.
   * 
   * @see monitoring.shared.drilldown.AbstractDrillDownManager#showDetails(ilog.cpl.model.IlpObject)
   */
  public void showDetails(IlpObject obj) {
    Logger log = LoggingUtils.getSampleLogger();
    if (obj == null) {
      String msg=IlvResourceUtil.getServerLocaleString(EquipmentDrillDownManager.class,"showEquipmentDetailsForNullObject");
      log.log(Level.FINE,msg);
      clearEquipmentDetails();
      return;
    }
    String msg=IlvResourceUtil.getServerLocaleString(EquipmentDrillDownManager.class,"showEquipmentDetailsForObject");
    log.log(Level.FINE,
        msg,
        new Object[]{obj.getIdentifier(), obj.getClass().getName()});

    if (hasEquipmentDetails(obj)) {
      // if equipment details are available, drill down in the equipment
      // component.
      // Second parameter is null, as there is no contained object to select
      setEquipmentRootObject(obj, null);
    } else if (isEquipmentDetail(obj)) {
      // Else if this is an equipment item, show the parent equipment
      // Second obj parameter is needed to have it selected and centered
      showParentEquipment(obj, obj);
    } else {
      // if not equipment related, clear equipment component
      clearEquipmentDetails();
    }
  }

  /** 
   * Sets the provided <code>IlpEquipment</code> as the underlying graphic component.
   */
  public void setComponent(IlpEquipment equipment) {
    super.setComponent(equipment);
  }
  
  /**
   * Returns the underlying <code>IlpEquipment</code>. 
   */
  private IlpEquipment getEquipment() {
    return (IlpEquipment) component;
  }

  /**
   * Return if the given object has equipment details to be displayed.
   * 
   * @param obj Business object
   * @return <code>true</code> if object has equipment details
   */
  public boolean hasEquipmentDetails(IlpObject obj) {
    return 
    CommonUtils.getMonitoringNetworkElementClass(getContext()).isAssignableFrom(obj.getIlpClass());
  }

  /**
   * Return if the given object is a detail of an equipment.
   * 
   * @param obj Business object
   * @return <code>true</code> if the given object is an equipment object
   */
  public boolean isEquipmentDetail(IlpObject obj) {
    return 
    (IltShelf.GetIlpClass().isAssignableFrom(obj.getIlpClass()) || 
        obj.getIlpClass().isSubClassOf(IltShelfItem.GetIlpClass()) || 
        obj.getIlpClass().isSubClassOf(IltCardItem.GetIlpClass()));
  }

  /**
   * Sets the root object and ensures that detail object is selected 
   * and made visible.  
   */
  protected void setEquipmentRootObject(IlpObject parent, IlpObject detailObj) {
    if (getCurrentRoot() != parent) {
      setEquipmentOrigin(parent.getIdentifier());
      setCurrentRoot(parent);
    }

    //Select the given contained object, and make sure it is visible
    selectObjectInComponent(detailObj);

    if (detailObj != null) {
      ensureComponentIsVisible();
    }
  }

  /**
   * Sets the parent of the provided object as the root and ensures that the provided
   * detail object is selected and made visible.
   */
  protected void showParentEquipment(IlpObject obj, IlpObject detailObj) {
    
    // Should only be called for objects with a parent
    IlpDataSource ds = getTreeDataSource();
    IlpChild childItf = ds.getChildInterface(obj);
    IlpObject parent = ds.getObject(childItf.getParent(obj));

    if (hasEquipmentDetails(parent)) {
      // Display the parent
      setEquipmentRootObject(parent, detailObj);
    } else if (isEquipmentDetail(parent)) {
      // recursively try the next higher level
      showParentEquipment(parent, detailObj);
    } else {
      // This should never happen....
      clearEquipmentDetails();
    }
  }

  /**
   * Clean the component displaying equipment details.
   */
  public void clearEquipmentDetails() {
    Logger log = LoggingUtils.getSampleLogger();
    if (!getAdapter().isShowingOrigin() || 
        !Collections.EMPTY_LIST.equals(getOrigins())) {
      setOrigins(Collections.emptyList(), true);
      setCurrentRoot(null);
      String msg=IlvResourceUtil.getServerLocaleString(EquipmentDrillDownManager.class,"ClearedEquipmentComponentOrigins");
      log.log(Level.FINER, msg);
    } else{
      String msg=IlvResourceUtil.getServerLocaleString(EquipmentDrillDownManager.class,"EquipmentComponentAlreadyEmpty");
      log.log(Level.FINER,msg);
    }
  }

  /**
   * Sets the origin in the equipment component.
   */
  protected void setEquipmentOrigin(Object objId) {
    List<Object> originList = new ArrayList<Object>();
    originList.add(objId);
    if (!originList.equals(getOrigins())) {
      // Second parameter is false, as we do not want to show the
      // origins themselves, only their children
      setOrigins(originList, false);
      Logger log = LoggingUtils.getSampleLogger();
      String msg=IlvResourceUtil.getServerLocaleString(EquipmentDrillDownManager.class,"SetEquipmentComponentOrigin");
      log.log(Level.FINER, msg, objId);
    }
  }
}