/*
* Copyright 2014 - LAit SpA
*				 Realizzato da Icona Management srl su commessa LAit SpA
* Copyright 2015- LAit SpA
*                                                  Aggiornato da LAit SpA
*
* Concesso in licenza a norma dell'EUPL, versione 1.1 o
* successive dell'EUPL (la "Licenza")– non appena saranno
* approvate dalla Commissione europea;
* Non è possibile utilizzare l'opera salvo nel rispetto della Licenza.
* È possibile ottenere una copia della Licenza al seguente indirizzo:
*
* http://ec.europa.eu/idabc/eupl
*
* Salvo diversamente indicato dalla legge applicabile o
* concordato per iscritto, il software distribuito secondo
* i termini della Licenza è distribuito "TAL QUALE",
* SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO,
* esplicite o implicite.
* Si veda la Licenza per la lingua specifica che disciplina
* le autorizzazioni e le limitazioni secondo i termini della
* Licenza.
*/
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package it.laitspa.cpf.faces.utils;

import java.beans.FeatureDescriptor;
import java.util.Iterator;
import java.util.Set;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;

/**
 * EL non gestisce Set<T> e ho problemi con ui:repeat nell'iterazione
 * 
 * Esempio:
 * 
 * Bean{
 *  Set<Azienda> aziende
 *  ...
 *  }
 *  
 *  <ui:repeat value=#{Bean.aziende.toList}
 *  
 * }
 * 
 */

/**
 * Enables customization of variable and property resolution behavior for EL
 * expression evaluation. For example, in the EL expression
 * #{employee.lastName}, the ELResolver determines what object employee refers
 * to, and what it means to get the lastName property on that object.
 * 
 * @author Andrea
 */
public class SetToListELResolver
  extends ELResolver
{

  private static final String propertyWord = "toList";

  /**
   * When a value expression that is included in a page is parsed during an
   * initial request for the page, a ValueExpression object is created to
   * represent the expression. Then, the ValueExpression object’s getValue
   * method is invoked. This method will in turn invoke the getValue method of
   * the appropriate resolver.
   * 
   * 
   * context - The context of this evaluation. base - The base object whose
   * property value is to be returned, or null to resolve a top-level variable.
   * property - The property or variable to be resolved.
   * 
   * return - If the propertyResolved property of ELContext was set to true,
   * then the result of the variable or property resolution; otherwise
   * undefined.
   */
  @SuppressWarnings("rawtypes")
  @Override
  public Object getValue(ELContext context, Object base, Object property)
    throws NullPointerException, PropertyNotFoundException, ELException
  {

    // To evaluate an Expression, an ELContext must be provided.
    //
    if(context == null)
    {
      throw new NullPointerException("Unexpected null context.");
    }
    Object result = null;

    /*
     * I need to handle only Set + propertyWord
     */
    if(base instanceof Set)
    {
      Set mySet = (Set)base;
      if(property instanceof String)
      {
        String myProperty = (String)property;
        if(myProperty.equalsIgnoreCase(propertyWord))
        {
          result = mySet.toArray();
          /**
           * Called to indicate that a ELResolver has successfully resolved a
           * given (base, property) pair.
           * 
           * After a resolver completes resolution of an expression, it sets the
           * propertyResolved flag of the ELContext to true so that no more
           * resolvers are consulted.
           */
          context.setPropertyResolved(true);
        }
      }
    }
    return result;
  }

  /**
   * For a given base and property this method attempts to identify the most
   * general acceptable type for the corresponding property.
   */
  @SuppressWarnings("rawtypes")
  @Override
  public Class<?> getType(ELContext context, Object base, Object property)
    throws NullPointerException, PropertyNotFoundException, ELException
  {
    if(context == null)
    {
      throw new NullPointerException("Unexpected null context.");
    }
    Class result = null;

    /*
     * I need to handle only Set + propertyWord
     */
    if(base instanceof Set)
    {
      if(property instanceof String)
      {
        String myProperty = (String)property;
        if(myProperty.equalsIgnoreCase(propertyWord))
        {
          context.setPropertyResolved(true);
        }
      }
    }
    return result;
  }

  /**
   * Attempts to set the value of the given property object on the given base
   * object. We return a PropertyNotWritableException if someone try to edit our
   * variable. A similar process occurs during a postback when setValue is
   * called if the expression is an lvalue expression.
   */
  @Override
  public void setValue(ELContext context, Object base, Object property, Object value)
    throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException,
    ELException
  {
    if(base instanceof Set)
    {
      if(property instanceof String)
      {
        String myProperty = (String)property;
        if(myProperty.equalsIgnoreCase(propertyWord))
        {
          throw new PropertyNotWritableException();
        }
      }
    }
  }

  @Override
  public boolean isReadOnly(ELContext context, Object base, Object property)
    throws NullPointerException, PropertyNotFoundException, ELException
  {
    if(context == null)
    {
      throw new NullPointerException("Unexpected null context.");
    }
    boolean result = false;

    /*
     * I need to handle only Set + propertyWord
     */
    if(base instanceof Set)
    {
      if(property instanceof String)
      {
        String myProperty = (String)property;
        if(myProperty.equalsIgnoreCase(propertyWord))
        {
          result = true;
          context.setPropertyResolved(true);
        }
      }
    }
    return result;
  }

  /**
   * Returns information about the set of variables or properties that can be
   * resolved for the given base object. One use for this method is to assist
   * tools in auto-completion.
   */
  @Override
  public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
  {
    return null;
  }

  /**
   * Returns the most general type that this resolver accepts
   */
  @SuppressWarnings("rawtypes")
  @Override
  public Class<?> getCommonPropertyType(ELContext context, Object base)
  {
    if(context == null)
    {
      throw new NullPointerException("Unexpected null context.");
    }
    Class result = null;

    /*
     * I need to handle only Set + propertyWord
     */
    if(base instanceof Set)
    {
      result = Set.class;
    }
    return result;
  }

}
