/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included  with this distribution in
 * the LICENSE.APL file.
 */

package org.apache.log4j.varia;

import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;

/**
  This is an abstract base class for filters that want to exactly
  configure the return values for a match and no match. Subclasses
  must implement the canMatch and match methods, both of return boolean values.
  
  Subclasses should implement the canMatch method so that it
  returns <code>true</code> if the filter can perform the matching code
  (ie it was configured correctly), and return <code>false</code> if it
  cannot.  If the return value is true, then the match method
  will be called. Otherwise, the value of {@link cantMatchReturnValue}
  will be returned.
  
  If the return value for match method is <code>true</code>, the value of
  matchReturnValue is returned as the result of the {@link Filter#decide} method.
  If the return value for match is <code>false</code>,
  then the noMatchReturnValue is returned.
  
  By default, the matchReturnValue is set to {@link Filter#ACCEPT},
  noMatchReturnValue is set to {@link Filter#DENY}, and cantMatchReturnValue is
  set to {@link Filter#NEUTRAL}. But this can be changed via property setters.
  For example, setting the matchReturnValue to Filter.NEUTRAL
  will allow the LoggingEvent to continue to the next filter instead of
  being immediately accepted.
  
  @author Mark Womack
*/
public abstract class GenericMatchFilter extends Filter {

  /**
    The return value if the filter matches.
    Default value is {@link Filter#ACCEPT}. */
  protected int matchReturnValue = Filter.ACCEPT;

  /**
    The return value if the filter does not match.
    Default value is {@link Filter#DENY}. */
  protected int noMatchReturnValue = Filter.DENY;

  /**
    The return value if the filter cannot perform the match.
    Default value is {@link Filter#NEUTRAL}. */
  protected int cantMatchReturnValue = Filter.NEUTRAL;
  
  /**
    Used to translate the string version of the return value to
    the appropriate constant value defined by {@link Filter}.
    Valid values are "accept", "deny", and "neutral". */
  protected
  int calcFilterReturnValue(String value) {
    if ("accept".equalsIgnoreCase(value))
      return Filter.ACCEPT;
    else if ("deny".equalsIgnoreCase(value))
      return Filter.DENY;
    else
      return Filter.NEUTRAL;
  }
  
  /**
    Sets the value that will be returned when the filter matches. */
  public
  void setMatchReturnValue(String value) {
    matchReturnValue = calcFilterReturnValue(value);
  }
  
  /**
    Sets the value that will be returned when the filter does not match. */
  public
  void setNoMatchReturnValue(String value) {
    noMatchReturnValue = calcFilterReturnValue(value);
  }
  
  /**
    Sets the value that will be returned when the filter cannot perform
    a match. */
  public
  void setCantReturnValue(String value) {
    cantMatchReturnValue = calcFilterReturnValue(value);
  }
  
  /**
    Abstract method that must be implemented by subclasses. Returns <code>true</code>
    if the filter can perform a match, <code>false</code> otherwise. */
  protected
  abstract
  boolean canMatch();
    
  /**
    Abstract method that must be implemented by subclasses. Returns <code>true</code>
    if the filter matches, <code>false</code> otherwise. */
  protected
  abstract
  boolean match(LoggingEvent event);  

  /**
    Return the decision of this filter.
   
    If the result from canMatch method is <code>false</code>, the value of
    cantMatchReturnValue is returned. Otherwise, if the result from the match
    method is true, the value of matchReturnValue is returned. if the result from
    match is <code>false</code> it returns the value of noMatchReturnValue. */
  public
  int decide(LoggingEvent event) {
    if (canMatch()) {
      if (match(event)) {
        return matchReturnValue;
      }
      else {
        return noMatchReturnValue;
      }
    }
    else
      return cantMatchReturnValue;
  }
}