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

import ilog.tgo.model.IltAlarm;
import ilog.tgo.model.IltCard;
import ilog.tgo.model.IltObjectState;

import ilog.cpl.IlpEquipment;
import ilog.cpl.datasource.IlpDataSource;
import ilog.cpl.datasource.structure.IlpChild;
import ilog.cpl.model.IlpAttribute;
import ilog.cpl.model.IlpObject;
import ilog.cpl.model.IlpRepresentationObject;

import ilog.views.faces.IlvFacesPageIdUtil;
import ilog.views.faces.dhtml.event.FacesMenuActionEvent;
import ilog.views.faces.dhtml.event.FacesViewActionEvent;
import ilog.views.util.servlet.model.IlvMenuItem;

/**
 * This class defines the method binding used along with the
 * ServerClientActionListener listener in a pop-up menu. It handles 
 * the alarms management of the currently active object in the 
 * Equipment View. Note that the active object is the object right 
 * below the mouse pointer when the pop-up menu is triggered, not 
 * necessarily the selected one. 
 * 
 * The alarm items in the pop-up menu are built with this special 
 * action listener (ServerClientActionListener that is capable of 
 * triggering both client and server actions, the server action is 
 * invoked through a method binding, which is implemented by this class.  
 *
 * This menu action is preferred over the regular action listener
 * (normally an extension of FacesViewActionListener) to improve the 
 * responsiveness by avoiding a full page refresh, which is needed when 
 * the FacesViewActionListener has to be configured with JSF_CONTEXT
 * invocation context. 
 */
public class AlarmStateActionListener {
  
  private static final String ADD = "add"; 
  private static final String REMOVE = "remove"; 
  private static final String REMOVE_ALL = "remove_all"; 
  
  private static final String MINOR = "minor"; 
  private static final String MAJOR = "major"; 
  private static final String WARNING = "warning";   
  
  /**
   * Id of Add Major alarm menu item. 
   */
  public static final String ADD_MAJOR_ID = ADD + "-" + MAJOR; 
  /**
   * Id of Add Minor alarm menu item. 
   */
  public static final String ADD_MINOR_ID = ADD + "-" + MINOR; 
  /**
   * Id of Add Warning alarm menu item. 
   */
  public static final String ADD_WARNING_ID = ADD + "-" + WARNING; 
  
  /**
   * Id of Remove Major alarm menu item. 
   */
  public static final String REMOVE_MAJOR_ID = REMOVE + "-" + MAJOR; 
  /**
   * Id of Remove Minor alarm menu item. 
   */
  public static final String REMOVE_MINOR_ID = REMOVE + "-" + MINOR; 
  /**
   * Id of Remove Warning alarm menu item. 
   */
  public static final String REMOVE_WARNING_ID = REMOVE + "-" + WARNING; 
  
  /**
   * Id of Remove All alarm menu item. 
   */
  public static final String REMOVE_ALL_ID = REMOVE_ALL; 
  
  /**
   * This method is invoked by the ServerClientActionListener, as configured 
   * in PopupMenuFactory. This action listener is capable of invoking both a 
   * client and server action at the same time.
   * 
   * The implementation adds or removes alarms from the object in the 
   * FacesViewActionObject depending on the menu item ID (as defined in this 
   * class) of the IlvMenuItem carried by the event.
   *
   * @param event The event object.
   */
  public void menuAction(FacesViewActionEvent event) throws Exception {
    //Get the active object
    IlpRepresentationObject representationObject = (IlpRepresentationObject)event.getObject();
    IlpObject businessObject = representationObject.getIlpObject(); 
    
    //Get the menu item 
    IlvMenuItem menuItem = ((FacesMenuActionEvent)event).getSelectedMenuItem();
    
    //Get the menuitem id
    String menuItemId = menuItem.getId();
    
    //Update the state of the object that was selected
    updateObjectState(businessObject, menuItemId);
    
    //Now propagate the state upwards...    
    if(businessObject instanceof IltCard) {
      
      //Get the IltNetworkElement that holds this card
      IlpObject networkElement = getNetworkElement(businessObject);

      //Update the state of the IltNetworkElement only if we found it
      if(networkElement != null) {
        updateObjectState(networkElement, menuItemId);
      }
    }
  }
  
  /**
   * Returns the IlpRepresentationObject of the IltNetworkElement that 
   * contains the provided IlpObject. It may return null, if it cannot 
   * find such IltNetworkElement.
   */
  private IlpObject getNetworkElement(IlpObject object) {
    // Get the data source
    IlpDataSource dataSource = getDataSource();

    //Find the parent which should be a shelf 
    IlpChild childInterface = dataSource.getChildInterface(object);
    
    if(childInterface == null) {
      return null;
    }
    
    //Find the shelf ID
    Object shelfIndentifier = childInterface.getParent(object);
    
    if(shelfIndentifier == null) {
      return null;
    }
    
    //Find the parent of the shelf that should be an IltNetworkElement
    childInterface = dataSource.getChildInterface(shelfIndentifier);
    
    if(childInterface == null) {
      return null;
    }
    
    //Find the shelf business object
    IlpObject shelfBusinessObject = dataSource.getObject(shelfIndentifier);
    
    //Find the ID if the network element
    Object networkElementIdentifier = childInterface.getParent(shelfBusinessObject);
    
    if(networkElementIdentifier == null) {
      return null;
    }
    
    //Return the network element representation object 
    return dataSource.getObject(networkElementIdentifier);
  }
  
  /**
   * Updates the obejcts state of the provided business object, according 
   * to the provided action ID.
   */
  private void updateObjectState(IlpObject businessObject, String actionId) {
    
    if(actionId != null) {
      
      IlpAttribute attrib = businessObject.getAttributeGroup().getAttribute("objectState");
      IltObjectState objectState = (IltObjectState)businessObject.getAttributeValue(attrib);
      
      if (null != objectState) {
        
        IltAlarm.State alarmState = ((IltAlarm.State)objectState.getAlarmState());
        
        //If we need to remove all, then just do it
        if(AlarmStateActionListener.REMOVE_ALL_ID.equals(actionId)) {
          alarmState.removeAllAlarms();          
        } else {
          
          IltAlarm.Severity severity = getSeverityForId(actionId);
         
          //Either we add it  
          if(actionId.indexOf(AlarmStateActionListener.ADD) != -1){
            alarmState.addNewAlarm(severity);
          } 
          //Or remove it
          else if(actionId.indexOf(AlarmStateActionListener.REMOVE) != -1){
            alarmState.removeNewAlarm(severity);
          } //Nothing else          
        }        
      }
    }
  }
  
  /**
   * Return the IltAlarm.Severity instance for the provided menu item ID 
   * as defined in this class.  
   */
  private IltAlarm.Severity getSeverityForId(String id) {
    if(id.indexOf(AlarmStateActionListener.MAJOR) != -1) {
      return IltAlarm.Severity.Major;
    } else if(id.indexOf(AlarmStateActionListener.MINOR) != -1) {
      return IltAlarm.Severity.Minor;
    } else if(id.indexOf(AlarmStateActionListener.WARNING) != -1) {
      return IltAlarm.Severity.Warning;
    }    
    return IltAlarm.Severity.Unknown;
  }
  
  /**
   * Return the data source associated with the components 
   */
  private IlpDataSource getDataSource() {
    // Retrieve the IlpEquipment component from the session
    return ((IlpEquipment)IlvFacesPageIdUtil.getSessionAttributeWithPageId("equipment")).getDataSource();
  }
}