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

import ilog.cpl.model.IlpClass;
import ilog.cpl.model.IlpClassManager;
import ilog.cpl.util.IlpFilter;
import ilog.tgo.model.IltCard;
import ilog.tgo.model.IltCardCarrier;
import ilog.tgo.model.IltEmptySlot;
import ilog.tgo.model.IltGroup;
import ilog.tgo.model.IltLed;
import ilog.tgo.model.IltLinearGroup;
import ilog.tgo.model.IltLink;
import ilog.tgo.model.IltNetworkElement;
import ilog.tgo.model.IltObject;
import ilog.tgo.model.IltOffPageConnector;
import ilog.tgo.model.IltPolyGroup;
import ilog.tgo.model.IltPort;
import ilog.tgo.model.IltRectGroup;
import ilog.tgo.model.IltShelf;

import java.util.logging.Level;

import javax.faces.event.ValueChangeEvent;

import monitoring.shared.LoggingUtils;
import monitoring.shared.MonitoringConstants;
import monitoring.web.controls.TableControls;
import monitoring.web.model.integration.IntegratedDataModelProvider;
import monitoring.web.model.integration.filters.AlarmOnTypeFilter;
import monitoring.web.model.integration.filters.OriginFilter;
import monitoring.web.model.integration.filters.TypeFilter;
import monitoring.web.utils.Lock;

import org.apache.myfaces.trinidad.component.UIXSwitcher;

/**
 * Action provider that holds the table related actions.
 */
public class TableActionProvider extends BaseActionProvider {

  /**
   * Method called when the user changes the filter in the alarms table. 
   */
  public void updateAlarmsTableFilter(ValueChangeEvent event) {
    Object newValue = event.getNewValue();

    //When switching tabs the newValue is null. We do not need to process that case 
    if (newValue != null) {
      setFilterOnAlarmsTable(newValue.toString());
    }
  }

  /**
   * Method called when the user changes the filter in the network module's managed 
   * object table. 
   */
  public void updateNetworkObjectsTableFilter(ValueChangeEvent event) {    
    Object newValue = event.getNewValue();

    //When switching tabs the newValue is null. We do not need to process that case 
    if (newValue != null) {
      setFilterOnNetworkObjectsTable(newValue.toString());
    }
  }

  /**
   * Method called when the user changes the filter in the service module's managed 
   * object table. 
   */
  public void updateServiceObjectsTableFilter(ValueChangeEvent event) {
    Object newValue = event.getNewValue();

    //See updateAlarmsTableFilter for details 
    if (newValue != null) {
      setFilterOnServiceObjectsTable(newValue.toString());
    }    
  }

  /**
   * Method called when the user changes the filter in the inventory module's managed 
   * object table. 
   */
  public void updateInventoryObjectsTableFilter(ValueChangeEvent event) {
    Object newValue = event.getNewValue();

    //See updateAlarmsTableFilter for details 
    if (newValue != null) {
      setFilterOnInventoryObjectsTable(newValue.toString());
    }
  }

  /**
   * Initializes the network module's managed objects table control and its table model provider.
   */
  public void initializeNetworkObjectsTable() {

    IntegratedDataModelProvider modelProvider = getDataStructures().getDataModels().getNetworkObjectsTableModelProvider();

    //1- Set the appropriate filter on the model provider
    modelProvider.setFilter(new OriginFilter());

    //2- Configure the filter with the default settings
    TableControls tableControls = sampleContext.getControls().getTableControls();
    setFilterOnNetworkObjectsTable(tableControls.getDefaultNetworkObjectsFilter());
  }

  /**
   * Initializes the service module's managed objects table control and its table model provider.
   */
  public void initializeServiceObjectsTable() {

    IntegratedDataModelProvider modelProvider = 
      getDataStructures().getDataModels().getServiceObjectsTableModelProvider();

    //1- Set the appropriate filter on the model provider
    modelProvider.setFilter(new OriginFilter());

    //2- Configure the filter with the default settings
    TableControls tableControls = 
      sampleContext.getControls().getTableControls();

    setFilterOnServiceObjectsTable(tableControls.getDefaultServiceObjectsFilter());
  }

  /**
   * Initializes the inventory module's managed objects table control and its table model provider.
   */
  public void initializeInventoryObjectsTable() {

    IntegratedDataModelProvider modelProvider = 
      getDataStructures().getDataModels().getInventoryObjectsTableModelProvider();

    //1- Set the appropriate filter on the model provider
    modelProvider.setFilter(new OriginFilter());

    //2- Configure the filter with the default settings
    TableControls tableControls = 
      sampleContext.getControls().getTableControls();

    setFilterOnInventoryObjectsTable(tableControls.getDefaultInventoryObjectsFilter());
  }

  /**
   * Initializes the alarms table control and its table model provider.
   */
  public void initializeAlarmsTable() {

    //1- Set the appropriate filter on it
    getDataStructures().getDataModels().getAlarmsTableModelProvider()
    .setFilter(new AlarmOnTypeFilter());

    //2- Configure the filter with the default settings
    TableControls tableControls = 
      sampleContext.getControls().getTableControls();

    setFilterOnAlarmsTable(tableControls.getDefaultAlarmsFilter());
  }

  /**
   * Applies the provided filter to the network module's managed objects table.
   */
  public void setFilterOnNetworkObjectsTable(String filterId) {

    //1- Find the model provider
    setFilterOnIntegratedModelProvider(filterId, getDataStructures()
        .getDataModels().getNetworkObjectsTableModelProvider());

    //2- Update the visible table
    switchToNetworkTableForFilter(filterId);
  }

  /**
   * Applies the provided filter to the service module's managed objects table.
   */
  public void setFilterOnServiceObjectsTable(String filterId) {

    //1- Find the model provider
    setFilterOnIntegratedModelProvider(filterId, getDataStructures()
        .getDataModels().getServiceObjectsTableModelProvider());

    //2- Update the visible table
    switchToServiceTableForFilter(filterId);
  }

  /**
   * Applies the provided filter to the inventory module's managed objects table.
   */
  public void setFilterOnInventoryObjectsTable(String filterId) {

    //1- Find the model provider
    setFilterOnIntegratedModelProvider(filterId, getDataStructures().
        getDataModels().getInventoryObjectsTableModelProvider());

    //2- Update the visible table
    switchToInventoryTableForFilter(filterId);
  }

  /**
   * Applies the provided filter to the alarms table.
   */
  public void setFilterOnAlarmsTable(String filterId) {

    //1- Update the model provider
    setFilterOnIntegratedModelProvider(filterId, getDataStructures()
        .getDataModels().getAlarmsTableModelProvider());
  }

  /**
   * Shows and handles the logistics behind showing the network module's tables.
   */
  public String showNetworkTables() {

    //Update to show to proper set of tables.
    //No need to update tabs as there are none for this. 
    //The visibility is determined by which module is 
    //currently being shown
    showModuleTables(0);
    return null;
  }

  /**
   * Shows and handles the logistics behind showing the inventory module's tables.
   */
  public String showInventoryTables() {

    //Update to show to proper set of tables.
    //No need to update tabs as there are none for this. 
    //The visibility is determined by which module is 
    //currently being shown
    showModuleTables(1);
    return null;
  }

  /**
   * Shows and handles the logistics behind showing the service module's tables.
   */
  public String showServiceTables() {
    //Update to show to proper set of tables.
    //No need to update tabs as there are none for this. 
    //The visibility is determined by which module is 
    //currently being shown
    showModuleTables(2);
    return null;
  }

  /**
   * Shows and handles the logistics behind showing the network module's alarm table.
   */
  public String showNetworkAlarmsTable() {

    //The Alarms table is at index 0
    switchToNetworkTable(0);

    return null;
  }

  /**
   * Shows and handles the logistics behind showing the network module's managed objects table.
   */
  public String showNetworkObjectsTable() {

    //The Objects table is at index 1
    switchToNetworkTable(1);

    return null;
  }

  /**
   * Shows and handles the logistics behind showing the inventory module's alarm table.
   */
  public String showInventoryAlarmsTable() {

    //The Alarms table is at index 0
    switchToInventoryTable(0);

    return null;
  }

  /**
   * Shows and handles the logistics behind showing the inventory module's managed object table.
   */
  public String showInventoryObjectsTable() {

    //The Objects table is at index 1
    switchToInventoryTable(1);

    return null;
  }

  /**
   * Shows and handles the logistics behind showing the service module's alarm table.
   */
  public String showServiceAlarmsTable() {

    //The Objects table is at index 0
    switchToServiceTable(0);

    return null;
  }

  /**
   * Shows and handles the logistics behind showing the service module's managed object table.
   */
  public String showServiceObjectsTable() {

    //The Objects table is at index 1
    switchToServiceTable(1);

    return null;
  }

  //////////////////////////////////////////////////////////////////////////////
  //Private Methods
  //////////////////////////////////////////////////////////////////////////////

  private void switchToNetworkTableForFilter(String filterId) {

    //1- Find the index for the filter
    int tableIndex = getIndexOfFacetForFilterId(filterId);

    //Show proper table
    showNetworkTableForFilter(tableIndex);
  }

  private void switchToServiceTableForFilter(String filterId) {

    //1- Find the index for the filter
    int tableIndex = getIndexOfFacetForFilterId(filterId);

    //Show proper table
    showServiceTableForFilter(tableIndex);
  }

  private void switchToInventoryTableForFilter(String filterId) {

    //1- Find the index for the filter
    int tableIndex = getIndexOfFacetForFilterId(filterId);

    //Show proper table
    showInventoryTableForFilter(tableIndex);
  }

  private int getIndexOfFacetForFilterId(String filterId) {

    int index = 0;

    if (TableControls.NETWORK_OBJECT_TABLE_FILTER_ALL_OBJECTS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_LINKS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_POLYGONAL_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_LINEAR_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_RECTANGULAR_GROUPS_ID.equals(filterId)
        || TableControls.SERVICE_OBJECT_TABLE_FILTER_ALL_OBJECTS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_ALL_OBJECTS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_CARDS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_EMPTY_SLOTS_ID.equals(filterId)) {

      index = 0;
    } else if (TableControls.NETWORK_OBJECT_TABLE_FILTER_NETWORK_ELEMENTS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_OFF_PAGE_CONNECTORS_ID.equals(filterId)
        || TableControls.SERVICE_OBJECT_TABLE_FILTER_CUSTOMERS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_LEDS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_PORTS_ID.equals(filterId)) {
      index = 1;
    } else if (TableControls.SERVICE_OBJECT_TABLE_FILTER_SLAS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_CARD_CARRIERS_ID.equals(filterId)) {
      index = 2;
    } else if (TableControls.SERVICE_OBJECT_TABLE_FILTER_SERVICES_ID.equals(filterId)) {
      index = 3;
    }

    return index;
  }

  private String switchToNetworkTable(int targetTabIndex) {
    
    Lock waitLock = sampleContext.COMPLETION_LOCK;
    
    synchronized (waitLock) {
      
      try {
        //Trigger waiting scheme 
        waitLock.executingTask = true;

        //////////////////////////////////////////////////////////////////////////
        //Update tab
        setSelectedTab(targetTabIndex, getControls().getTableControls()
            .getNetworkTableTabs());

        //Show proper table
        showNetworkTable(targetTabIndex);

        try {
          //This operation takes awhile to get digested by the runtime
          //So we give it some chewing time...
          Thread.sleep(750);  
        } catch (Exception e) {
        }
        //////////////////////////////////////////////////////////////////////////

      } catch (Exception e) {
        LoggingUtils.getSampleLogger().log(
            Level.SEVERE,
            "Could not properly switch to the network table with this exception:"
            + e.getLocalizedMessage());
      } finally {        
        //Shutdown waiting scheme 
        waitLock.executingTask = false;        
      }        
    }
    return null;
  }

  private String switchToInventoryTable(int targetTabIndex) {
    
    Lock waitLock = sampleContext.COMPLETION_LOCK;

    synchronized (waitLock) {
      try {
        //Trigger waiting scheme 
        waitLock.executingTask = true;

        //////////////////////////////////////////////////////////////////////////      
        //Update tab
        setSelectedTab(targetTabIndex, getControls().getTableControls()
            .getInventoryTableTabs());

        //Show proper table
        showInventoryTable(targetTabIndex);
        //////////////////////////////////////////////////////////////////////////
      
      } catch (Exception e) {
        LoggingUtils.getSampleLogger().log(
            Level.SEVERE,
            "Could not properly switch to the inventory table with this exception:"
            + e.getLocalizedMessage());
      } finally {        
        //Shutdown waiting scheme 
        waitLock.executingTask = false;        
      }        
    }
    return null;
  }

  private String switchToServiceTable(int targetTabIndex) {

    Lock waitLock = sampleContext.COMPLETION_LOCK;

    synchronized (waitLock) {
      
      try {
        //Trigger waiting scheme 
        waitLock.executingTask = true;

        //////////////////////////////////////////////////////////////////////////      
        //Update tab
        setSelectedTab(targetTabIndex, getControls().getTableControls()
            .getServiceTableTabs());

        //Show proper table
        showServiceTable(targetTabIndex);
        //////////////////////////////////////////////////////////////////////////

      } catch (Exception e) {
        LoggingUtils.getSampleLogger().log(
            Level.SEVERE,
            "Could not properly switch to the service table with this exception:"
            + e.getLocalizedMessage());
      } finally {        
        //Shutdown waiting scheme 
        waitLock.executingTask = false;        
      }        
    }
    return null;
  }

  private void showNetworkTableForFilter(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getNetworkObjectsTablesSwitcherFacetName(index);

    UIXSwitcher switcher = tableControls.getNetworkObjectsTablesSwitcher();

    //When the sample is first started this switcher is not yet ready
    //This isnot a problem as it knows where to find the default facet
    if (switcher != null) {
      switcher.setFacetName(selectedFacetName);
    }
  }

  private void showInventoryTableForFilter(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getInventoryObjectsTablesSwitcherFacetName(index);

    UIXSwitcher switcher = tableControls.getInventoryObjectsTablesSwitcher();

    //When the sample is first started this switcher is not yet ready
    //This isnot a problem as it knows where to find the default facet
    if (switcher != null) {
      switcher.setFacetName(selectedFacetName);
    }
  }

  private void showServiceTableForFilter(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getServiceObjectsTablesSwitcherFacetName(index);

    UIXSwitcher switcher = tableControls.getServiceObjectsTablesSwitcher();

    //When the sample is first started this switcher is not yet ready
    //This isnot a problem as it knows where to find the default facet
    if (switcher != null) {
      switcher.setFacetName(selectedFacetName);
    }
  }

  private void showNetworkTable(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getNetworkTableSwitcherFacetName(index);

    tableControls.getNetworkTableSwitcher().setFacetName(selectedFacetName);
  }

  private void showInventoryTable(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getInventoryTableSwitcherFacetName(index);

    tableControls.getInventoryTableSwitcher().setFacetName(
        selectedFacetName);
  }

  private void showServiceTable(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getServiceTableSwitcherFacetName(index);
    tableControls.getServiceTableSwitcher().setFacetName(selectedFacetName);
  }

  private void showModuleTables(int index) {
    TableControls tableControls = getControls().getTableControls();
    String selectedFacetName = 
      tableControls.getTableSwitcherFacetName(index);
    tableControls.getTableSwitcher().setFacetName(selectedFacetName);
  }

  private IlpClass getTypeForFilterId(String filterId) {

    IlpClassManager classManager = 
      getSampleContext().getTgoContext().getClassManager();

    //Default to showing all objects 
    IlpClass type = IltObject.GetIlpClass();

    if (TableControls.NETWORK_OBJECT_TABLE_FILTER_ALL_OBJECTS_ID.equals(filterId)
        || TableControls.INVENTORY_OBJECT_TABLE_FILTER_ALL_OBJECTS_ID.equals(filterId)) {
      type = IltObject.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_ALL_OBJECTS_ID.equals(filterId)) {
      //See AlarmOnTypeFilter for details  
      type = null;
    } else if (TableControls.ALARM_TABLE_FILTER_ON_NETWORK_ELEMENTS_ID.equals(filterId)
        || (TableControls.NETWORK_OBJECT_TABLE_FILTER_NETWORK_ELEMENTS_ID.equals(filterId))) {
      type = IltNetworkElement.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_GROUPS_ID.equals(filterId)) {
      type = IltGroup.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_LINEAR_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_LINEAR_GROUPS_ID.equals(filterId)) {
      type = IltLinearGroup.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_POLYGONAL_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_POLYGONAL_GROUPS_ID.equals(filterId)) {
      type = IltPolyGroup.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_RECTANGULAR_GROUPS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_RECTANGULAR_GROUPS_ID.equals(filterId)) {
      type = IltRectGroup.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_OFF_PAGE_CONNECTORS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_OFF_PAGE_CONNECTORS_ID.equals(filterId)) {
      type = IltOffPageConnector.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_LINKS_ID.equals(filterId)
        || TableControls.NETWORK_OBJECT_TABLE_FILTER_LINKS_ID.equals(filterId)) {
      type = IltLink.GetIlpClass();
    } else if (TableControls.ALARM_TABLE_FILTER_ON_SERVICES_ID.equals(filterId)
        || TableControls.SERVICE_OBJECT_TABLE_FILTER_SERVICES_ID.equals(filterId)) {
      type = classManager.getClass(MonitoringConstants.SERVICE_CLASS_NAME);
    } else if (TableControls.ALARM_TABLE_FILTER_ON_CUSTOMERS_ID.equals(filterId)
        || TableControls.SERVICE_OBJECT_TABLE_FILTER_CUSTOMERS_ID.equals(filterId)) {
      type = classManager.getClass(MonitoringConstants.CUSTOMER_CLASS_NAME);
    } else if (TableControls.ALARM_TABLE_FILTER_ON_SLAS_ID.equals(filterId)
        || TableControls.SERVICE_OBJECT_TABLE_FILTER_SLAS_ID.equals(filterId)) {
      type = classManager.getClass(MonitoringConstants.SLA_CLASS_NAME);
    } else if (TableControls.ALARM_TABLE_FILTER_ON_SERVICE_ACCESS_POINTS_ID.equals(filterId)) {
      type = classManager.getClass(MonitoringConstants.SERVICE_ACCESS_POINT_CLASS_NAME);
    } else if (TableControls.ALARM_TABLE_FILTER_ON_SERVICE_PATHS_ID.equals(filterId)) {
      type = classManager.getClass(MonitoringConstants.SERVICE_ACCESS_LINK_CLASS_NAME);
    } else if (TableControls.ALARM_TABLE_FILTER_ON_ALL_SERVICES_ID.equals(filterId)
        || TableControls.SERVICE_OBJECT_TABLE_FILTER_ALL_OBJECTS_ID.equals(filterId)) {
      type = classManager.getClass(MonitoringConstants.SERVICE_MANAGED_OBJECT_CLASS_NAME);
    } else if (TableControls.INVENTORY_OBJECT_TABLE_FILTER_SHELVES_ID.equals(filterId)) {
      type = IltShelf.GetIlpClass();
    } else if (TableControls.INVENTORY_OBJECT_TABLE_FILTER_CARD_CARRIERS_ID.equals(filterId)) {
      type = IltCardCarrier.GetIlpClass();
    } else if (TableControls.INVENTORY_OBJECT_TABLE_FILTER_CARDS_ID.equals(filterId)) {
      type = IltCard.GetIlpClass();
    } else if (TableControls.INVENTORY_OBJECT_TABLE_FILTER_EMPTY_SLOTS_ID.equals(filterId)) {
      type = IltEmptySlot.GetIlpClass();
    } else if (TableControls.INVENTORY_OBJECT_TABLE_FILTER_LEDS_ID.equals(filterId)) {
      type = IltLed.GetIlpClass();
    } else if (TableControls.INVENTORY_OBJECT_TABLE_FILTER_PORTS_ID.equals(filterId)) {
      type = IltPort.GetIlpClass();
    }
    return type;
  }

  private void setFilterOnIntegratedModelProvider(String filterId,
      IntegratedDataModelProvider modelProvider) {

    //1- Update the filter on the model provider 
    IlpFilter filter = modelProvider.getFilter();

    if (filter instanceof TypeFilter) {
      TypeFilter typeFilter = (TypeFilter) filter;

      IlpClass type = getTypeForFilterId(filterId);
      typeFilter.setType(type);

      //3- Refresh the model
      modelProvider.refreshModel();
    }
  }
}