package jacorb.orb.portableInterceptor;

import org.omg.PortableInterceptor.*;
import jacorb.orb.SystemExceptionHelper;
/**
 * This class iterates over an array of
 * ServerRequestInterceptors.
 *
 * @author Nicolas Noffke
 * @version $Id: ServerInterceptorEnumeration.java,v 1.1 2000/03/30 12:20:42 noffke Exp $
 */

public class ServerInterceptorEnumeration{
  public static final short RECEIVE_REQUEST_SERVICE_CONTEXTS = 0;
  public static final short RECEIVE_REQUEST = 1;
  public static final short SEND_REPLY = 2;
  public static final short SEND_EXCEPTION = 3;
  public static final short SEND_OTHER = 4;

  private ServerRequestInterceptor[] interceptors = null;
  private int index = 0;
  private int increment = 1;
  private boolean reversed = false;
  private boolean forward = true;

  public ServerInterceptorEnumeration(ServerRequestInterceptor[] interceptors,
				      boolean forward) {
    if (forward){
      index = 0;
      increment = 1;
    }
    else{
      index = interceptors.length - 1;;
      increment = -1;
    }

    this.forward = forward;
    this.interceptors = interceptors;
  }

  /**
   * Reverses the direction in which the list is traversed.
   * The element returned by the next call to nextElement()
   * is the one previous to that returned by the last 
   * call to nextElement(). <br>
   * The direction can only be reversed one time and only if 
   * the starting direction was "forward".
   */
  private void reverseDirection(){
    if (! reversed && forward){
      increment *= -1;
      index += (2 * increment);      
     
      reversed = true;
    }
  }

  /**
   * Tests, if there are more elements available.
   */
  private boolean hasMoreElements() {
    return (index >= 0) && (index < interceptors.length);
  }
  
  /**
   * Returns the next element in the enumeration
   */
  private ServerRequestInterceptor nextElement() {
    ServerRequestInterceptor _tmp = interceptors[index];
    index += increment;
    return _tmp;
  }

  /**
   * Iterates over the enumeration, i.e. calls "op" on
   * nextElement() until !hasMoreElements().
   */
  public void iterate(ServerRequestInfoImpl info, short op)
    throws ForwardRequest{

    //set sending_exception right
    info.update();

    Exception _interceptor_ex = null;
    info.caller_op = op;

    while(hasMoreElements()){
      try{
	ServerRequestInterceptor _intercept = nextElement();
	jacorb.util.Debug.output(2, "Invoking SI " + _intercept.name());
	switch (op) {
	case RECEIVE_REQUEST_SERVICE_CONTEXTS :
	  _intercept.receive_request_service_contexts(info);
	  break;
	case RECEIVE_REQUEST :
	  _intercept.receive_request(info);
	  break;
	case SEND_REPLY :
	  _intercept.send_reply(info);
	  break;
	case SEND_EXCEPTION :
	  _intercept.send_exception(info);
	  break;
	case SEND_OTHER :
	  _intercept.send_other(info);
	  break;
	}
      }catch (ForwardRequest _fwd){
	jacorb.util.Debug.output(2, _fwd);
	reverseDirection();
	op = SEND_OTHER;
	
	if (_fwd.permanent)
	  info.reply_status = LOCATION_FORWARD_PERMANENT.value;
	else
	  info.reply_status = LOCATION_FORWARD.value;

	info.forward_reference = _fwd.forward;

	_interceptor_ex = _fwd;
      }catch (org.omg.CORBA.SystemException _sysex){
	jacorb.util.Debug.output(2, _sysex);
	reverseDirection();
	op = SEND_EXCEPTION;
	_interceptor_ex = _sysex;

	SystemExceptionHelper.insert(info.sending_exception, _sysex);
      }catch (Throwable th){
	jacorb.util.Debug.output(1, "ClientInterceptorEnumeration: Caught a " + th);
      }

      info.caller_op = op;
    }

    //propagate last exception upwards
    if (_interceptor_ex != null)
      if (_interceptor_ex instanceof ForwardRequest)
	throw (ForwardRequest) _interceptor_ex;
      else
	throw (org.omg.CORBA.SystemException) _interceptor_ex;
  }
} // ServerInterceptorEnumeration
