/*
 * 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.datasource.IlpAbstractHierarchyAdapter;
import ilog.cpl.datasource.IlpDataSource;
import ilog.cpl.datasource.structure.IlpChild;
import ilog.cpl.graphic.IlpGraphicComponent;
import ilog.cpl.model.IlpObject;
import ilog.cpl.service.IlpContext;
import ilog.views.util.IlvResourceUtil;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import monitoring.shared.LoggingUtils;


/**
 * Base class for classes that provide a "drill-down" mechanism within this sample.
 */
public abstract class AbstractDrillDownManager {

  //The target graphic component 
  protected IlpGraphicComponent component;

  //The current root being displayed
  protected IlpObject currentRoot;

  //Flag to determine is a current drilldown is taking place
  protected boolean inDrillDown;

  //The datasource that contains the hierarchical information
  protected IlpDataSource treeDataSource;

  //Support for bean properties
  protected PropertyChangeSupport propertyChangeSupport;

  //Property that is used to indicate changes in the current root
  public static final String CURRENT_ROOT = "currentRoot";

  public AbstractDrillDownManager() {
    this.currentRoot = null;
    this.inDrillDown = false;
    propertyChangeSupport = new PropertyChangeSupport(this);
  }

  //////////////////////////////////////////////////////////////////////////////
  //Subclasses
  //////////////////////////////////////////////////////////////////////////////
  /**
   * 
   * Should ensure that the provided object is visible 
   * in the target graphic component.
   */
  abstract protected void ensureObjectIsVisibleInComponent(IlpObject object);

  /**
   * Should ensure that the graphic component is made visible.
   */
  abstract protected void ensureComponentIsVisible();

  /**
   * Should select the provide obejct in the graphic component.
   */
  abstract protected void selectObjectInComponent(IlpObject object);

  /**
   * Should return the <code>IlpAbstractHierarchyAdapter</code> for the 
   * underlying graphic component. 
   */
  abstract protected IlpAbstractHierarchyAdapter getAdapter();

  /**
   * Should drilldown onto the provided object such that its details are shown. 
   * @param obj
   */
  abstract protected void showDetails(IlpObject obj);

  /**
   * Returns the graphic component.
   */
  public IlpGraphicComponent getComponent() {
    return component;
  }

  /**
   * Sets the graphic component.
   */
  protected void setComponent(IlpGraphicComponent component) {
    this.component = component;
  }

  /**
   * Returns the tree datasource.
   */
  public IlpDataSource getTreeDataSource() {
    return treeDataSource;
  }

  /**
   * Sets the tree datasource.
   */
  public void setTreeDataSource(IlpDataSource treeDataSource) {
    this.treeDataSource = treeDataSource;
  }
  /**
   * Returns the TGO context.
   */
  public IlpContext getContext() {
    return getComponent().getContext();
  }

  /**
   * Set the parent object of the objects currently being displayed.
   * This method is protected because it should not be invoked directly.
   */
  protected void setCurrentRoot(IlpObject root) {
    if (this.currentRoot != root) {
      IlpObject oldRoot = this.currentRoot;
      this.currentRoot = root;
      propertyChangeSupport.firePropertyChange(CURRENT_ROOT, oldRoot,
          root);
    }
  }

  /**
   * Resets the origins by showing only objects that have no parents.
   */
  protected void resetOrigins() {
    Logger log = LoggingUtils.getSampleLogger();
    if (getCurrentRoot() != null) {
      getAdapter().resetOrigins();
      String msg=IlvResourceUtil.getServerLocaleString(AbstractDrillDownManager.class,"Resetorigins");
      log.log(Level.FINER,msg);
      setCurrentRoot(null);
    } else{
      String msg=IlvResourceUtil.getServerLocaleString(AbstractDrillDownManager.class,"AlreadyShowingRootObjects");
      log.log(Level.FINER,msg);
    }
  }

  /**
   * Shows the details of the provided object.
   */
  public void show(IlpObject ilpObj) {
    Logger log = LoggingUtils.getSampleLogger();
    String msg=IlvResourceUtil.getServerLocaleString(AbstractDrillDownManager.class,"Askedtoshow");
    log.log(Level.FINE,msg, ilpObj.getIdentifier());
    inDrillDown = true;
    showDetails(ilpObj);
    inDrillDown = false;
  }

  /**
   * Get the parent object of the objects currently being displayed.
   */
  public IlpObject getCurrentRoot() {
    return this.currentRoot;
  }

  /**
   * Checks if the provided object ID is a root in the adapter of the underlying 
   * graphic component.
   */
  public boolean isOrigin(Object objId) {
    return getOrigins().contains(objId);
  }

  /**
   * Returns true if the given object is a root object.
   */
  public boolean isRootObject(IlpObject obj) {
    IlpChild childItf = getTreeDataSource().getChildInterface(obj);
    return ((childItf == null) || (childItf.getParent(obj) == null));
  }

  /**
   * Sets the List of object IDs as the root objects in the underlying 
   * graphic component. 
   */
  protected void setOrigins(List<Object> originList, boolean showOrigins) {
    getAdapter().setOrigins(originList, showOrigins);
  }

  /**
   * Returns the roots in the adapter of the underlying graphic component.
   */
  protected List<Object> getOrigins() {
    return getAdapter().getOrigins();
  }

  //////////////////////////////////////////////////////////////////////////////
  //Property change
  //////////////////////////////////////////////////////////////////////////////

  /**
   * Add a property change listener
   * @param listener Listener
   */
  public void addPropertyChangeListener(PropertyChangeListener listener) {
    this.propertyChangeSupport.addPropertyChangeListener(listener);
  }

  /**
   * Add a property change listener interested only in the given property.
   * 
   * @param propertyName Property name
   * @param listener     Listener
   */
  public void addPropertyChangeListener(String propertyName,
      PropertyChangeListener listener) {
    this.propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
  }

  /**
   * Remove the given property change listener
   * @param listener Listener
   */
  public void removePropertyChangeListener(PropertyChangeListener listener) {
    this.propertyChangeSupport.removePropertyChangeListener(listener);
  }

  /**
   * Remove the given property change listener
   * @param propertyName Property
   * @param listener     Listener
   */
  public void removePropertyChangeListener(String propertyName,
      PropertyChangeListener listener) {
    this.propertyChangeSupport.removePropertyChangeListener(propertyName,
        listener);
  }
}