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

import ilog.cpl.model.IlpObject;
import ilog.cpl.model.IlpRepresentationObject;
import ilog.views.faces.dhtml.event.FacesMenuActionEvent;
import ilog.views.faces.dhtml.event.FacesViewActionEvent;
import ilog.views.util.servlet.model.IlvMenuItem;

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

import monitoring.shared.LoggingUtils;
import monitoring.web.AbstractSampleContext;
import monitoring.web.action.SharedActionProvider;
import monitoring.web.oss.AbstractIntegrationProvider;
import monitoring.web.utils.Lock;


/**
 * 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 {

  /**
   * The separator that is used to separate the identifier of the alarm and the 
   * flag that detamines that this is an acknowledge or an unacknowledge menu item. 
   */
  public static final String SEPARATOR = "_";

  /**
   * Id of an Acknowledge contextual menu item. 
   */
  public static final String ACKNOWLEDGE = "ACKNOWLEDGE";

  /**
   * Id of an UnAcknowledge contextual menu item. 
   */
  public static final String UNACKNOWLEDGE = "UNACKNOWLEDGE";

  /**
   * The sample context.
   */
  protected AbstractSampleContext sampleContext;

  /**
   * This method is invoked by the ServerClientActionListener, as configured 
   * in AbstractContextualMenuFactory. This action listener is capable of invoking both a 
   * client and server action at the same time.
   * 
   * The implementation acknowledges 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 processAlarmStateUpdate(FacesViewActionEvent event) throws Exception {

    Lock waitLock = sampleContext.COMPLETION_LOCK;
    
    synchronized (waitLock) {
      
      try {
        int currentModule = sampleContext.getActionProviders().getSharedActions().getCurrentModule();
        Object jsfLock = null;
        if (currentModule == SharedActionProvider.NETWORK_MODULE) {
          jsfLock = sampleContext.getControls().getNetworkControls().getNetworkNetworkView().getNetwork().getManagerView().getRegion();
        } else if (currentModule == SharedActionProvider.INVENTORY_MODULE) {
          jsfLock = sampleContext.getControls().getEquipmentControls().getInventoryEquipmentView().getEquipment().getManagerView().getRegion();
        } else if (currentModule == SharedActionProvider.SERVICE_MODULE) {
          jsfLock = sampleContext.getControls().getNetworkControls().getServiceNetworkView().getNetwork().getManagerView().getRegion();
        }
        synchronized(jsfLock) {

          //Trigger waiting scheme 
          waitLock.executingTask = true;
    
          //////////////////////////////////////////////////////////////////////////
          //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 weas selected
          updateObjectState(businessObject, menuItemId);
    
          //Here we wait just for little bit to give time for the 
          //alarm notifications to be broadcasted, otherwise 
          //the upcoming client side request, generates an image
          //that does not yet contain the latest state on the network
          Thread.sleep(300);
          //////////////////////////////////////////////////////////////////////////
        }
      } catch (Exception e) {
        LoggingUtils.getSampleLogger().log(
            Level.SEVERE,
            "Could not properly process alarm update with this exception:"
            + e.getLocalizedMessage());
      } finally {        
        //Shutdown waiting scheme 
        waitLock.executingTask = false;        
      }        
    }
  }

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

  public AbstractSampleContext getSampleContext() {
    return sampleContext;
  }
  public void setApplicationContext(AbstractSampleContext sampleContext) {
    this.sampleContext = sampleContext;
  }
  
  //////////////////////////////////////////////////////////////////////////////
  //Private Methods
  //////////////////////////////////////////////////////////////////////////////

  /**
   * Updates the obejcts state of the provided business object, according 
   * to the provided action ID.
   */
  private void updateObjectState(IlpObject businessObject, String menuItemId) {

    if (menuItemId != null) {

      AbstractIntegrationProvider integrationProvider 
      = sampleContext.getIntegrationProvider();

      List<Object> alarmIdentifier = new ArrayList<Object>(1);

      alarmIdentifier.add(getAlarmIdFromMenuItemId(menuItemId));

      if (isAcknowledgeMenuItem(menuItemId)) {
        integrationProvider.acknowledgeAlarms(alarmIdentifier);
      } else {
        integrationProvider.unAcknowledgeAlarms(alarmIdentifier);
      }
    }
  }

  /**
   * Extracts the alarm object identifier from the menu item identifier.
   */
  private String getAlarmIdFromMenuItemId(String menuItemId) {

    int indexOfSeparator = menuItemId.indexOf(SEPARATOR);

    if (indexOfSeparator > -1) {
      return menuItemId.substring(indexOfSeparator + 1);
    } else {
      LoggingUtils.getSampleLogger().log(
          Level.WARNING,
          "The menu item identifier {0} is not of the properly built ",
          menuItemId);

      return menuItemId;
    }

  }
  
  /**
   * Checks if the provided menu identifier is of an acknowledge menu item.
   */
  private boolean isAcknowledgeMenuItem(String menuItemId) {
    return (menuItemId != null && menuItemId.indexOf(UNACKNOWLEDGE) == -1);
  }
}