package jacorb.orb.portableInterceptor;

import org.omg.IOP.*;
import org.omg.CORBA.*;
import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.Parameter;

import java.util.*;

import jacorb.util.Debug;
/**
 * This class represents the type of info object,
 * that will be passed to the ClientRequestInterceptors.<br>
 * See PI Spec p.5-46ff
 *
 * @author Nicolas Noffke
 * @version $Id: ClientRequestInfoImpl.java,v 1.4 2000/08/18 13:40:45 noffke Exp $
 */

public class ClientRequestInfoImpl extends RequestInfoImpl 
  implements ClientRequestInfo  {

  //from ClientRequestInfo
  public org.omg.CORBA.Object target = null;
  public org.omg.CORBA.Object effective_target = null;
  public TaggedProfile effective_profile = null;
  public Any received_exception = null;
  public String received_exception_id = null;
  public TaggedComponent[] effective_components = null;
  public jacorb.orb.Delegate delegate = null;
  public jacorb.orb.ORB orb = null;


  public ClientRequestInfoImpl() {
    super();
  }

  public void setRequest(jacorb.orb.dii.Request request){
    
    arguments = new org.omg.Dynamic.Parameter[request.arguments.count()];
    for (int i = 0; i < arguments.length; i++){
      try{
	NamedValue value = request.arguments.item(i);
	
	ParameterMode mode = null;
	if (value.flags() == ARG_IN.value)
	  mode = ParameterMode.PARAM_IN;
	else if (value.flags() == ARG_OUT.value)
	  mode = ParameterMode.PARAM_OUT;
	else if (value.flags() == ARG_INOUT.value)
	  mode = ParameterMode.PARAM_INOUT;
	
	arguments[i] = new org.omg.Dynamic.Parameter(value.value(), mode);
      }catch (Exception e){
	Debug.output(Debug.INFORMATION | Debug.INTERCEPTOR, e);
      }
    }

    //exceptions will be set when available
  }

  /**
   * This method builds an array of ServiceContexts.
   * The last ServiceContext is a dummy object for
   * data aligning purposes.
   */
  public ServiceContext[] getRequestServiceContexts(){
    //copying manually for jdk1.1 compatibility
    ServiceContext[] _ctx = new ServiceContext[request_ctx.size() + 1];
    Enumeration _enum = request_ctx.elements(); 
    int _i = 0;
    while(_enum.hasMoreElements())
      _ctx[_i++] = (ServiceContext) _enum.nextElement();

    _ctx[_ctx.length - 1] = new ServiceContext(Integer.MAX_VALUE, new byte[0]);

    return _ctx;
  }

  // implementation of org.omg.PortableInterceptor.RequestInfoOperations interface
  public Parameter[] arguments() {
    if (! (caller_op == ClientInterceptorIterator.SEND_REQUEST) &&
	! (caller_op == ClientInterceptorIterator.RECEIVE_REPLY))
      throw new BAD_INV_ORDER("The attribute \"arguments\" is currently invalid!", 
			      10, CompletionStatus.COMPLETED_MAYBE);

    if (arguments == null)
      throw new NO_RESOURCES("Stream-based skeletons/stubs do not support this op", 
			     1, CompletionStatus.COMPLETED_MAYBE);
    else
      return arguments;
  }

  public TypeCode[] exceptions() {
    if (caller_op == ClientInterceptorIterator.SEND_POLL)
      throw new BAD_INV_ORDER("The attribute \"exceptions\" is currently invalid!", 
			      10, CompletionStatus.COMPLETED_MAYBE);

    if (exceptions == null)
      throw new NO_RESOURCES("Stream-based skeletons/stubs do not support this op", 
			     1, CompletionStatus.COMPLETED_MAYBE);
    else
      return exceptions;
  }

  public Any result() {
    if (caller_op != ClientInterceptorIterator.RECEIVE_REPLY)
      throw new BAD_INV_ORDER("The attribute \"result\" is currently invalid!", 
			      10, CompletionStatus.COMPLETED_MAYBE);

    if (result == null)
      throw new NO_RESOURCES("Stream-based skeletons/stubs do not support this op", 
			     1, CompletionStatus.COMPLETED_MAYBE);
    else
      return result;
  }

  public short sync_scope() {
    if (caller_op == ClientInterceptorIterator.SEND_POLL)
      throw new BAD_INV_ORDER("The attribute \"sync_scope\" is currently invalid!", 
			      10, CompletionStatus.COMPLETED_MAYBE);

    return org.omg.Messaging.SYNC_WITH_TRANSPORT.value;
  }
 
  public short reply_status() {
    if ((caller_op == ClientInterceptorIterator.SEND_REQUEST) ||
	(caller_op == ClientInterceptorIterator.SEND_POLL))
      throw new BAD_INV_ORDER("The attribute \"reply_status\" is currently invalid!",
			      10, CompletionStatus.COMPLETED_MAYBE);

    return reply_status;
  }

  public org.omg.CORBA.Object forward_reference() {
    if (! (caller_op != ClientInterceptorIterator.RECEIVE_OTHER) ||
	((reply_status != LOCATION_FORWARD_PERMANENT.value) &&
	 (reply_status != LOCATION_FORWARD.value)))
      throw new BAD_INV_ORDER("The attribute \"forward_reference\" is currently " + 
			      "invalid!", 10, CompletionStatus.COMPLETED_MAYBE);

    return forward_reference;
  }

  public ServiceContext get_request_service_context(int id) {
    if (caller_op == ClientInterceptorIterator.SEND_POLL)
      throw new BAD_INV_ORDER("The attribute \"operation_context\" is currently " + 
			      "invalid!", 10, CompletionStatus.COMPLETED_MAYBE);

      return super.get_request_service_context(id);
  }

  public ServiceContext get_reply_service_context(int id) {
    if ((caller_op == ClientInterceptorIterator.SEND_REQUEST) ||
	(caller_op == ClientInterceptorIterator.SEND_POLL))
      throw new BAD_INV_ORDER("The attribute \"reply_status\" is currently invalid!",
			      10, CompletionStatus.COMPLETED_MAYBE);

      return super.get_reply_service_context(id);
  }
  
  // implementation of ClientRequestInfoOperations interface
  public org.omg.CORBA.Object target() {
    return target;
  }
  
  public org.omg.CORBA.Object effective_target() {
    return effective_target;
  }

  public TaggedProfile effective_profile() {
    return effective_profile;
  }
  
  public Any received_exception() {
    if (caller_op != ClientInterceptorIterator.RECEIVE_EXCEPTION)
      throw new BAD_INV_ORDER("The attribute \"received_exception\" is currently " + 
			      "invalid!", 10, CompletionStatus.COMPLETED_MAYBE);

    return received_exception;
  }

  public String received_exception_id() {
    if (caller_op != ClientInterceptorIterator.RECEIVE_EXCEPTION)
      throw new BAD_INV_ORDER("The attribute \"received_exception_id\" is " + 
			      "currently invalid!", 10, 
			      CompletionStatus.COMPLETED_MAYBE);

    return received_exception_id;
  }
   
  public TaggedComponent get_effective_component(int id) {
    if (caller_op == ClientInterceptorIterator.SEND_POLL)
      throw new BAD_INV_ORDER("The operation \"get_effective_component\" is " + 
			      "currently invalid!", 10, 
			      CompletionStatus.COMPLETED_MAYBE);

    for(int _i = 0; _i < effective_components.length; _i++)
      if (effective_components[_i].tag == id)
	return effective_components[_i];
    
    throw new BAD_PARAM("No TaggedComponent with id " + id + " found", 
			25, CompletionStatus.COMPLETED_MAYBE); 
  }
  
  public TaggedComponent[] get_effective_components(int id) {
    if (caller_op == ClientInterceptorIterator.SEND_POLL)
      throw new BAD_INV_ORDER("The operation \"get_effective_components\" is " + 
			      "currently invalid!", 10, 
			      CompletionStatus.COMPLETED_MAYBE);

    Vector _store = new Vector();
    for(int _i = 0; _i < effective_components.length; _i++)
      if (effective_components[_i].tag == id)
	_store.addElement(effective_components[_i]);

    if (_store.size() == 0)
      throw new BAD_PARAM("No TaggedComponents with id " + id + " found", 
			  25, CompletionStatus.COMPLETED_MAYBE);
    else{
      TaggedComponent[] _result = new TaggedComponent[_store.size()];
      for (int _i = 0; _i < _result.length; _i++)
	_result[_i] = (TaggedComponent) _store.elementAt(_i);

      return _result;
    }
  }
  
  /**
   * WARNING: This method relies on the DomainService to be available.
   * Make shure that the DS is running, if you want to call this method.
   */
  public Policy get_request_policy(int type) {
    if (caller_op == ClientInterceptorIterator.SEND_POLL)
      throw new BAD_INV_ORDER("The operation \"get_request_policy\" is currently " + 
			      "invalid!", 10, CompletionStatus.COMPLETED_MAYBE);

    if (! orb.hasPolicyFactoryForType(type))
      throw new INV_POLICY("No PolicyFactory for type " + type + 
			   " has been registered!", 1, 
			   CompletionStatus.COMPLETED_MAYBE);
    try{
      return delegate.get_policy_no_intercept(target, type);
    }catch(INV_POLICY _e){
      _e.minor = 1;
      throw _e;
    }
  }
 
  public void add_request_service_context(ServiceContext service_context, 
					  boolean replace) {

    if (caller_op != ClientInterceptorIterator.SEND_REQUEST)
      throw new BAD_INV_ORDER("The operation \"add_request_service_context\" is " + 
			      "currently invalid!", 10, 
			      CompletionStatus.COMPLETED_MAYBE);

    Integer _id = new Integer(service_context.context_id);

    if (! replace && request_ctx.containsKey(_id))
      throw new BAD_INV_ORDER("The ServiceContext with id " + _id.toString() 
			      + " has already been set!", 11, 
			      CompletionStatus.COMPLETED_MAYBE);

    request_ctx.put(_id, service_context);
  }
} // ClientRequestInfoImpl
