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

import ilog.cpl.datasource.IlpDefaultDataSource;
import ilog.tgo.datasource.IltDefaultDataSource;
import ilog.tgo.faces.service.IltFacesDefaultContext;
import ilog.views.IlvRect;
import integration.DataSourceProvider;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import monitoring.shared.LoggingUtils;
import monitoring.shared.ServicesUtils;
import monitoring.web.AbstractSampleContext;
import monitoring.web.model.integration.beans.TGOObjectHierarchical;
import monitoring.web.oss.AbstractIntegrationProvider;

import org.apache.myfaces.trinidad.model.ChildPropertyTreeModel;
import org.apache.myfaces.trinidad.model.TreeModel;


/**
 * Provides utility methods for web applications.
 */
public class WebUtils {

  /**
   * Identifier of the AbstractIntegrationProvider managed bean. This identifier needs 
   * to be in synch with faces-config.xml. 
   */
  public static final String INTEGRATION_PROVIDER_IDENTIFIER = "integrationProvider";

  /**
   * Identifier of the AbstractSampleContext managed bean. This identifier needs 
   * to be in synch with faces-config.xml. 
   */
  public static final String SAMPLE_CONTEXT_IDENTIFIER = "sampleContext";

  /**
   * Identifier of the DataSourceProvider managed bean. This identifier needs 
   * to be in synch with faces-config.xml.
   */
  public static final String DATASOURCE_PROVIDER_IDENTIFIER = "dataSourceProvider";

  /**
   * Identifier of the TGO context managed bean. This identifier needs 
   * to be in synch with faces-config.xml.
   */
  public static final String TGO_CONTEXT_IDENTIFIER = "tgoContext";

  /**
   * Identifier of the ServiceUtils managed bean. This identifier needs 
   * to be in synch with faces-config.xml.
   */
  public static final String SERVICES_UTILS_IDENTIFIER = "servicesUtils";

  /**
   * Identifier used to indicate that the network data source is the target data source.
   */
  public static final String NETWORK_DATASOURCE_IDENTIFIER = "network-datasource";
  /**
   * Identifier used to indicate that the inventory data source is the target data source.
   */
  public static final String INVENTORY_DATASOURCE_IDENTIFIER = "inventory-datasource";
  /**
   * Identifier used to indicate that the services data source is the target data source.
   */
  public static final String SERVICES_DATASOURCE_IDENTIFIER = "services-datasource";
  /**
   * Identifier used to indicate that the data source used in the service network view is the target data source.
   */
  public static final String SERVICES_NETWORK_DATASOURCE_IDENTIFIER = "services-network-datasource";
  /**
   * Identifier used to indicate that the data source used in the service details view is the target data source.
   */
  public static final String SERVICE_DATASOURCE_IDENTIFIER = "service-datasource";
  /**
   * Identifier used to indicate that the alarm data source is the target data source.
   */
  public static final String ALARMS_DATASOURCE_IDENTIFIER = "alarm-datasource";

  /**
   * The setting used to identify the network module's network's contextual menu class name.
   */
  public static final String NETWORK_NETWORK_CONTEXTUAL_MENU_CLASS_NAME_SETTING = 
    "networkNetworkContextualMenuFactoryClassName";
  
  /**
   * The name of the resource bundle that contains some of the sample settings.
   */
  public static final String SAMPLE_SETTINGS_RESOURCE_BUNDLE_NAME = "SampleSettings";
  
  /**
   * The number of web users.
   */
  private static int numberOfWebUsers = 0;

  /**
   * No need to make this available.
   */
  private WebUtils() {
  }

  /**
   * Returns a managed bean from the Managed Bean facility in the provided 
   * FacesContext.
   *  
   * @param beanIdentifier the identifier of the managed bean.
   * 
   * @return returns the corresponding object instance, 
   * or null if no such instance can be identified.
   */
  public static Object getManagedBean(String beanIdentifier, FacesContext facesContext) {
    //We have to be careful here as when the application is being 
    //removed from the session the FacesContext can be null
    if(facesContext != null) {
        return facesContext.getApplication().getVariableResolver()
        .resolveVariable(facesContext, beanIdentifier);
    } else {
      LoggingUtils.getSampleLogger().log(Level.WARNING, 
          "Could get bean {0} as the FacesContext is null", 
          new Object[] {beanIdentifier});
    }
    return null;
  }

  /**
   * Returns a managed bean from the Managed Bean facility in the current 
   * FacesContext.
   *  
   * @param beanIdentifier the identifier of the managed bean.
   * 
   * @return returns the corresponding object instance, 
   * or null if no such instance can be identified.
   */
  public static Object getManagedBean(String beanIdentifier) {
    return getManagedBean(beanIdentifier, FacesContext.getCurrentInstance());
  }
  
  /**
   * Returns the <code>ServletContext</code> for the current FacesContext.
   */
  public static ServletContext getServletContext() {
    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
    return (ServletContext)externalContext.getContext();
  }
  
  /**
   * Returns the TGO context managed bean in the current FacesContext.
   */
  public static IltFacesDefaultContext getTGOContext() {
    return (IltFacesDefaultContext) getManagedBean(TGO_CONTEXT_IDENTIFIER);
  }

  /**
   * Returns the AbstractSampleContext managed bean in the current FacesContext.
   */
  public static AbstractSampleContext getSampleContext() {
    return (AbstractSampleContext) getManagedBean(SAMPLE_CONTEXT_IDENTIFIER);
  }

  /**
   * Returns the AbstractIntegrationProvider managed bean in the current FacesContext.
   */
  public static AbstractIntegrationProvider getIntegrationProvider() {
    return (AbstractIntegrationProvider) getManagedBean(INTEGRATION_PROVIDER_IDENTIFIER);
  }

  /**
   * Returns the DataSourceProvider managed bean in the current FacesContext.
   */
  public static DataSourceProvider getDataSourceProvider() {
    return getIntegrationProvider().getDataSourceProvider();
  }

  /**
   * Returns the ServicesUtils managed bean in the current FacesContext.
   */
  public static ServicesUtils getServicesUtils() {
    return (ServicesUtils) getManagedBean(SERVICES_UTILS_IDENTIFIER);
  }

  /**
   * Looks up a TGO datasource with given indetifier from the integration library.
   * 
   * @param dataSourceIndentifer    
   * @return
   */
  public static IlpDefaultDataSource lookupDataSource(
      String dataSourceIndentifer) {

    DataSourceProvider dataSourceProvider = getDataSourceProvider();

    IlpDefaultDataSource dataSource = null;

    if (NETWORK_DATASOURCE_IDENTIFIER.equals(dataSourceIndentifer)) {
      dataSource = dataSourceProvider.getNetworkDataSource();
    } else if (SERVICES_DATASOURCE_IDENTIFIER.equals(dataSourceIndentifer)) {
      dataSource = dataSourceProvider.getServicesDataSource();
    } else if (SERVICES_NETWORK_DATASOURCE_IDENTIFIER.equals(dataSourceIndentifer)) {
      dataSource = dataSourceProvider.getServicesNetworkDataSource();
    } else if (SERVICE_DATASOURCE_IDENTIFIER.equals(dataSourceIndentifer)) {
      dataSource = new IltDefaultDataSource(getTGOContext());
    } else if (INVENTORY_DATASOURCE_IDENTIFIER.equals(dataSourceIndentifer)) {
      dataSource = dataSourceProvider.getInventoryDataSource();
    } else if (ALARMS_DATASOURCE_IDENTIFIER.equals(dataSourceIndentifer)) {
      dataSource = dataSourceProvider.getAlarmDataSource();
    }

    return dataSource;
  }

  /**
   * Creates a TreeModel from a List TGOObjectHierarchical instances.
   *  
   * @param objects a List TGOObjectHierarchical instances
   * @return a TreeModel
   */
  public static TreeModel createTreeDataModelFromList(List<TGOObjectHierarchical> objects) {
    return new ChildPropertyTreeModel(objects,
        TGOObjectHierarchical.BRANCHING_PROPERTY_NAME);
  }

  /**
   * Returns all the fields defined in the provided <code>type</code> that is of the provided
   * <code>attributeType</code>.
   */
  public static Object[] getFieldsOfType(Class<?> type, Class<?> attributeType) {
    Object[] fields = null;

    int i = 0;
    Field[] allFields = type.getFields();
    try {
      List<Object> fieldsList = new ArrayList<Object>(allFields.length);
      for (i = 0; i < allFields.length; i++) {

        Object fieldItself = allFields[i].get(null);

        if (fieldItself.getClass().isAssignableFrom(attributeType)) {
          fieldsList.add(fieldItself);          
        }
      }
      fields = fieldsList.toArray();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return fields;    
  }

  /**
   * Executes the provided <code>Runnable</code> is a separate thread. 
   * <p>
   * The <code>toString</code> value of this <code>Runnable</code> is used as 
   * the thread name.
   */
  public static void executeAsynchronously (Runnable runnable) {
    try {
      Thread thread = new Thread(runnable, "Asynch Executor - " + runnable.toString());
      thread.start();
    } catch (Exception e) {
      LoggingUtils.getSampleLogger().warning("Could not execute task asynchournously '" + 
          runnable.toString() + "' with this exception: " + e.getLocalizedMessage());
    }
  }
  
  /**
   * Returns the next available user identifier.
   */
  public static String getNextWebUserIdentifier() {
    return "web-user-" + numberOfWebUsers++;
  }
  
  /**
   * Returns the value of the provided setting.
   */
  public static String getSampleSetting(String setting) {
    ResourceBundle sampleSettings = ResourceBundle.getBundle(SAMPLE_SETTINGS_RESOURCE_BUNDLE_NAME);
    return sampleSettings.getString(setting);
  }  
  
  /**
   * Returns a String that contains the x, y width and height of the given 
   * IlvRect separated by commas.
   * 
   * @param rect
   */
  public static String getStringForRect(IlvRect rect) {
      return (rect == null) ? 
          null :
            rect.x + "," + rect.y + "," + rect.width+"," + rect.height; 
  }
  
  /**
   * Returns <code>true</code> if the application is stil live, and false 
   * if the user session has expired.
   */
  public static boolean isApplicationLive() {
    return FacesContext.getCurrentInstance() != null;
  }
}