package hirondelle.web4j.action;

import java.util.logging.*;
import java.util.regex.Pattern;

import hirondelle.web4j.request.RequestParameter;
import hirondelle.web4j.request.RequestParser;
import hirondelle.web4j.util.Util;
import hirondelle.web4j.model.AppException;

/**
 <b>Template</b> for search screens.

 <P>Here, a search action has the following :  
 <ul>
  <li>it uses a form that allows the user to input search criteria
  <li>the form must have <tt>GET</tt> as its method, not <tt>POST</tt>
  <li>the underlying database operation is a <tt>SELECT</tt>, and does not edit the database in any way
 </ul>

 <P>Search operations never require a redirect operation (since they do not edit the database).

 <P>Search operations have an interesting property : if you build a Model Object to validate and represent 
  user input into the search form, then its <tt>getXXX</tt> methods can usually be made package-private, instead 
  of <tt>public</tt>. The reason is that such Model Objects are usually not used by JSPs directly. 
  If desired, such methods can safely return <tt>String</tt> instead of 
  {@link hirondelle.web4j.security.SafeText}. (The Model Objects themselves cannot be made package-private, since
  the {@link hirondelle.web4j.model.ModelFromRequest} class works only with <tt>public</tt> classes.)
*/
public abstract class ActionTemplateSearch extends ActionImpl {
  
  /**
  Constructor.
  
  @param aForward renders the result of the search
  @param aRequestParser passed to the superclass constructor.
  */
  protected ActionTemplateSearch(ResponsePage aForward, RequestParser aRequestParser){
    super(aForward, aRequestParser);
  }

  /**
  The operations supported by this template.
  
  <P>The supported operations are :
  <ul>
  <li> {@link Operation#Show}
  <li> {@link Operation#Search}
  </ul>
  
  The source of the <tt>Operation</tt> is described by {@link ActionImpl#getOperation()}.
  */
  public static final RequestParameter SUPPORTED_OPERATION = RequestParameter.withRegexCheck(
    "Operation", Pattern.compile("(" + Operation.Show + "|" + Operation.Search +  ")") 
  );
  
  /**
  <b>Template</b> method.
  
  <P>In order to clearly understand the operation of this method, here is the 
  core of its implementation, with all abstract methods in <em>italics</em> :
  <PRE>
    if (Operation.Show == getOperation() ){
      //default forward
    }
    else if ( Operation.Search == getOperation() ){
      <em>validateUserInput();</em>
      if( ! hasErrors() ){
        <em>listSearchResults();</em>
        if ( ! hasErrors() ){
          fLogger.fine("List executed successfully.");
        }
      }
    }
  </PRE>
  */
  @Override public ResponsePage execute() throws AppException {
    if (Operation.Show == getOperation() ){
      //default forward
    }
    else if ( Operation.Search == getOperation() ){
      fLogger.fine("'Search' Operation.");
      validateUserInput();
      if( ! hasErrors() ){
        fLogger.fine("Passes validation.");
        listSearchResults();
        if ( ! hasErrors() ){
          fLogger.fine("List executed successfully.");
        }
      }
    }
    else {
      throw new AssertionError("Unexpected value for Operation : " + getOperation());
    }
    return getResponsePage();
  }

  /**
  Validate items input by the user into a form.
  
  <P>The form is used to define the criteria for the search (if any).
  
  <P>Applies only for {@link Operation#Search}. If an error occurs, then 
  <tt>addError</tt> must be called.
  */
  protected abstract void validateUserInput() throws AppException;

  /**
  Query the database, and place the results (usually) into request scope.
  */
  protected abstract void listSearchResults() throws AppException;

  // PRIVATE //
  private static final Logger fLogger = Util.getLogger(ActionTemplateSearch.class);
}
