package jacorb.orb.portableInterceptor;

import org.omg.PortableInterceptor.*;
import jacorb.orb.SystemExceptionHelper;

/**
 * This class is an iterator over an array
 * of ClientRequestInterceptors.
 *
 * @author Nicolas Noffke
 * @version  $Id: ClientInterceptorEnumeration.java,v 1.1 2000/03/30 12:20:37 noffke Exp $
 */

public class ClientInterceptorEnumeration{
  public static final short SEND_REQUEST = 0;
  public static final short SEND_POLL = 1;
  public static final short RECEIVE_REPLY = 2;
  public static final short RECEIVE_EXCEPTION = 3;
  public static final short RECEIVE_OTHER = 4;

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

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

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

  /**
   * 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 ClientRequestInterceptor nextElement() {
    ClientRequestInterceptor _tmp = interceptors[index];
    index += increment;
    return _tmp;
  }

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

    Exception _interceptor_ex = null;
    info.caller_op = op;

    while(hasMoreElements()){
      try{
	ClientRequestInterceptor _intercept = nextElement();
	jacorb.util.Debug.output(2, "Invoking CI " + _intercept.name());
	switch (op) {
	case SEND_REQUEST :
	  _intercept.send_request(info);
	  break;
	case SEND_POLL :
	  _intercept.send_poll(info);
	  break;
	case RECEIVE_REPLY :
	  _intercept.receive_reply(info);
	  break;
	case RECEIVE_EXCEPTION :
	  _intercept.receive_exception(info);
	  break;
	case RECEIVE_OTHER :
	  _intercept.receive_other(info);
	}
      }catch (ForwardRequest _fwd){
	jacorb.util.Debug.output(2, _fwd);
	reverseDirection();
	op = RECEIVE_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 = RECEIVE_EXCEPTION;
	_interceptor_ex = _sysex;

	SystemExceptionHelper.insert(info.received_exception, _sysex);
	
	try{
	  info.received_exception_id = SystemExceptionHelper.type(_sysex).id();
	}catch(org.omg.CORBA.TypeCodePackage.BadKind _bk){
	  jacorb.util.Debug.output(2, _bk);
	}
      }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;
  }
} // ClientInterceptorEnumeration
