// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/Basic.h>
#include <OB/Except.h>
#include <OB/Template.h>
#include <OB/TemplateI.h>
#include <OB/Declarations.h>
#include <OB/Any.h>
#include <OB/TCKind.h>
#include <OB/TypeCode.h>
#include <OB/Context.h>
#include <OB/IOP.h>
#include <OB/Object.h>
#include <OB/IntRep.h>
#include <OB/ORB.h>
#include <OB/Object_skel.h>
#include <OB/ImplRep.h>
#include <OB/BOA.h>
#include <OB/NamedValue.h>
#include <OB/DSI.h>

// ----------------------------------------------------------------------
// External, non-inline duplicate/release for templates
// ----------------------------------------------------------------------

void
OBDuplicate(CORBA_ServerRequest_ptr p)
{
    if(p)
	p -> _OB_incRef();
}

void
OBRelease(CORBA_ServerRequest_ptr p)
{
    if(p)
	p -> _OB_decRef();
}

// ----------------------------------------------------------------------
// Template instantiations
// ----------------------------------------------------------------------

#ifndef HAVE_NO_EXPLICIT_TEMPLATES
template class OBObjVar< CORBA_ServerRequest >;
template class OBObjForSeq< CORBA_ServerRequest >;
//template class OBObjSeq< CORBA_ServerRequest >;
//template class OBSeqVar< OBObjSeq< CORBA_ServerRequest > >;
#else
#ifdef HAVE_PRAGMA_DEFINE
#pragma define(OBObjVar< CORBA_ServerRequest >)
#pragma define(OBObjForSeq< CORBA_ServerRequest >)
//#pragma define(OBObjSeq< CORBA_ServerRequest >)
//#pragma define(OBSeqVar< OBObjSeq< CORBA_ServerRequest > >)
#endif
#endif

// ----------------------------------------------------------------------
// ServerRequest private member functions
// ----------------------------------------------------------------------

void
CORBA_ServerRequest::unmarshal()
{
    if(!CORBA_is_nil(params_))
    {
	CORBA_TypeCode_var tc;
	CORBA_Any* any;

	for(CORBA_ULong i = 0 ; i < params_ -> count() ; i++)
	{
	    CORBA_NamedValue_ptr nv = params_ -> item(i);
	    if(nv -> flags() != CORBA_ARG_OUT)
	    {
		any = nv -> value();
		tc = any -> type();
		OBUnmarshalNoTypeCode(*any, coct_, swap_, tc);
	    }
	}
    }
}

void
CORBA_ServerRequest::unmarshalCtx()
{
    OBStrSeq* ctxSeq = new OBStrSeq;
    OBUnmarshal(*ctxSeq, coct_, swap_);
    ctx_ = CORBA_Context::_OB_create(ctxSeq);
}

void
CORBA_ServerRequest::marshal()
{
    CORBA_ULong count = offOut_;
    CORBA_ULong i;
    CORBA_Any* any;
    
    any = (CORBA_Any*)exception_;
    if(any)
    {
	OBMarshalCountNoTypeCode(*any, count);
    }
    else
    {
	any = (CORBA_Any*)result_;
	if(any)
	{
	    OBMarshalCountNoTypeCode(*any, count);
	}
	
	if(!CORBA_is_nil(params_))
	{
	    for(i = 0 ; i < params_ -> count() ; i++)
	    {
		CORBA_NamedValue_ptr nv = params_ -> item(i);
		if(nv -> flags() != CORBA_ARG_IN)
		{
		    any = nv -> value();
		    OBMarshalCountNoTypeCode(*any, count);
		}
	    }
	}
    }

    buf_.alloc(count);
    CORBA_Octet* oct = buf_.data + offOut_;

    any = (CORBA_Any*)exception_;
    if(any)
    {
	OBMarshalNoTypeCode(*any, oct);
    }
    else
    {
	any = (CORBA_Any*)result_;
	if(any)
	{
	    OBMarshalNoTypeCode(*any, oct);
	}

	if(!CORBA_is_nil(params_))
	{
	    for(i = 0 ; i < params_ -> count() ; i++)
	    {
		CORBA_NamedValue_ptr nv = params_ -> item(i);
		if(nv -> flags() != CORBA_ARG_IN)
		{
		    any = nv -> value();
		    OBMarshalNoTypeCode(*any, oct);
		}
	    }
	}
    }
}

// ----------------------------------------------------------------------
// ServerRequest constructor and destructor
// ----------------------------------------------------------------------

CORBA_ServerRequest::CORBA_ServerRequest(CORBA_Object_ptr object,
					 const char* name,
					 OBBuffer& buf,
					 bool swap,
					 CORBA_ULong offIn,
					 CORBA_ULong offOut)
    : object_(CORBA_Object::_duplicate(object)),
      name_(name), buf_(buf), swap_(swap), offOut_(offOut),
      coct_(buf.data + offIn)
{
}

// ----------------------------------------------------------------------
// ServerRequest public member implementation
// ----------------------------------------------------------------------

CORBA_OperationDef_ptr
CORBA_ServerRequest::op_def()
{
    CORBA_InterfaceDef_var interf = object_ -> _get_interface();
    if(CORBA_is_nil(interf))
        return CORBA_OperationDef::_nil();

    CORBA_Contained_var contained = interf -> lookup(name_);
    if(CORBA_is_nil(contained))
        return CORBA_OperationDef::_nil();

    return CORBA_OperationDef::_narrow(contained);
}

const char*
CORBA_ServerRequest::op_name()
{
    return name_;
}

CORBA_Context_ptr
CORBA_ServerRequest::ctx()
{
    unmarshalCtx();
    return ctx_;
}

void
CORBA_ServerRequest::params(CORBA_NVList_ptr parameters)
{
    params_ = parameters;
    unmarshal();
}

void
CORBA_ServerRequest::result(CORBA_Any* value)
{
    result_ = value;
}

void
CORBA_ServerRequest::exception(CORBA_Any* value)
{
    exception_ = value;
}

// ----------------------------------------------------------------------
// The DynamicSkeleton public member implementation
// ----------------------------------------------------------------------

CORBA_Boolean
CORBA_DynamicImplementation::_is_dynamic()
{
    return true;
}

OBDispatchStatus
CORBA_DynamicImplementation::_OB_dispatch(const char* _ob_op,
					  OBBuffer& _ob_buf,
					  bool _ob_sw,
					  CORBA_ULong _ob_offIn,
					  CORBA_ULong _ob_offOut)
{
    OBDispatchStatus status =
	CORBA_Object_skel::_OB_dispatch(_ob_op, _ob_buf, _ob_sw,
					_ob_offIn, _ob_offOut);

    if(status == OBDispatchStatusNoOperation)
    {
        CORBA_Object_var self = _this();
	CORBA_ServerRequest_var serverRequest =
	    new CORBA_ServerRequest(self, _ob_op, _ob_buf, _ob_sw,
				    _ob_offIn, _ob_offOut);

	invoke(serverRequest);
	serverRequest -> marshal();
	
	CORBA_Any* any;
	any = (CORBA_Any*)(serverRequest -> exception_);

	if(any)
	{
	    CORBA_TypeCode_var tc = any -> type();
	    if(tc -> _OB_isSystemException())
	    {
		const CORBA_Octet* coct = _ob_buf.data + _ob_offOut;
		OBUnmarshalSystemExceptionThrow(coct, false); // No swap here!
	    }

	    status = OBDispatchStatusExcept;
	}
	else
	    status = OBDispatchStatusOK;
    }

    return status;
}
