//=============================================================================
/**
*  @file   amh_ss.cpp
*
*  amh_ss.cpp,v 1.20 2004/05/27 19:14:30 ossama Exp
*
*  Specialized interface visitor for AMH.
*
*  @author Darrell Brunsch <brunsch@cs.wustl.edu>
*/
//=============================================================================

ACE_RCSID (be_visitor_interface,
           amh_ss,
           "amh_ss.cpp,v 1.20 2004/05/27 19:14:30 ossama Exp")

be_visitor_amh_interface_ss::be_visitor_amh_interface_ss (
    be_visitor_context *ctx
  )
  : be_visitor_interface_ss (ctx)
{
}

be_visitor_amh_interface_ss::~be_visitor_amh_interface_ss (void)
{
}

int
be_visitor_amh_interface_ss::visit_operation (be_operation *node)
{
  be_visitor_amh_operation_ss visitor (this->ctx_);
  return visitor.visit_operation (node);
}

int
be_visitor_amh_interface_ss::visit_attribute (be_attribute *node)
{
  be_visitor_amh_operation_ss visitor (this->ctx_);
  return visitor.visit_attribute (node);
}

int
be_visitor_amh_interface_ss::visit_interface (be_interface *node)
{
  // Do not generate AMH classes for any sort of implied IDL.
  if (node->original_interface () != 0)
    {
      return 0;
    }

  return be_visitor_interface_ss::visit_interface (node);
}

void
be_visitor_amh_interface_ss::this_method (be_interface *node)
{
  TAO_OutStream *os = this->ctx_->stream ();

  // the _this () operation
  //const char *non_amh_name = node->full_name () + 4;
  ACE_CString non_amh_name = "";
  non_amh_name += node->client_enclosing_scope ();
  non_amh_name += node->local_name ();

  ACE_CString full_skel_name_holder =
    this->generate_full_skel_name (node);
  const char *full_skel_name = full_skel_name_holder.c_str ();

  *os << be_nl << be_nl << "// TAO_IDL - Generated from " << be_nl
      << "// " << __FILE__ << ":" << __LINE__ << be_nl << be_nl;

  *os << non_amh_name.c_str () << "*" << be_nl
      << full_skel_name
      << "::_this (ACE_ENV_SINGLE_ARG_DECL)" << be_nl
      << "{" << be_idt_nl
      << "TAO_Stub *stub = this->_create_stub (ACE_ENV_SINGLE_ARG_PARAMETER);"
      << be_nl
      << "ACE_CHECK_RETURN (0);" << be_nl << be_nl;

  *os << "CORBA::Object_ptr tmp = CORBA::Object::_nil ();" << be_nl
      << be_nl
      << "if (stub->servant_orb_var ()->orb_core ()->optimize_collocation_objects ())"
      << be_idt_nl
      << "{" << be_idt_nl
      << "ACE_NEW_RETURN (" << be_idt << be_idt_nl
      << "tmp," << be_nl
      << "CORBA::Object (stub, 1, this)," << be_nl
      << "0" << be_uidt_nl
      << ");" << be_uidt << be_uidt_nl
      << "}" << be_uidt_nl
      << "else"
      << be_idt_nl
      << "{" << be_idt_nl
      << "ACE_NEW_RETURN (" << be_idt << be_idt_nl
      << "tmp," << be_nl
      << "CORBA::Object (stub, 0, this)," << be_nl
      << "0" << be_uidt_nl
      << ");" << be_uidt << be_uidt_nl
      << "}" << be_uidt_nl << be_nl
      << "CORBA::Object_var obj = tmp;" << be_nl << be_nl;

  *os << "typedef ::" << node->name () << " STUB_SCOPED_NAME;" << be_nl
      << "return" << be_idt_nl;

  if (!node->is_abstract ())
    {
      *os << "TAO::Narrow_Utils<STUB_SCOPED_NAME>::unchecked_narrow (";
    }
  else
    {
      *os << "TAO::AbstractBase_Narrow_Utils<STUB_SCOPED_NAME>::unchecked_narrow (";
    }
  *os << be_idt << be_idt_nl
      << "obj.in ()," << be_nl
      << node->flat_client_enclosing_scope ()
      << node->base_proxy_broker_name ()
      << "_Factory_function_pointer" << be_uidt_nl
      << ");" << be_uidt << be_uidt << be_uidt_nl
      << "}";

}

void
be_visitor_amh_interface_ss::dispatch_method (be_interface *node)
{
  TAO_OutStream *os = this->ctx_->stream ();

  ACE_CString full_skel_name_holder =
    this->generate_full_skel_name (node);
  const char *full_skel_name = full_skel_name_holder.c_str ();

  *os << be_nl << be_nl << "// TAO_IDL - Generated from " << be_nl
      << "// " << __FILE__ << ":" << __LINE__ << be_nl << be_nl;

  *os << "void" << be_nl
      << full_skel_name << "::_dispatch (" << be_idt << be_idt_nl
      << "TAO_ServerRequest &req," << be_nl
      << "void *context" << be_nl
      << "ACE_ENV_ARG_DECL" << be_uidt_nl
      << ")" << be_uidt_nl
      << "{" << be_idt_nl
      << "this->asynchronous_upcall_dispatch (" << be_idt << be_idt_nl
      << "req," << be_nl
      << "context," << be_nl
      << "this" << be_nl
      << "ACE_ENV_ARG_PARAMETER" << be_uidt_nl
      << ");" << be_uidt << be_uidt_nl
      << "}";
}

void
be_visitor_amh_interface_ss::generate_send_reply (TAO_OutStream * os)
{
  *os << be_nl << be_nl
      << "_tao_server_request.tao_send_reply ();";
}


int
be_visitor_amh_interface_ss::generate_amh_classes (be_interface *)
{
  // No AMH classes for the AMH classes... :-)
  return 0;
}

int
be_visitor_amh_interface_ss::generate_proxy_classes (be_interface *)
{
  // No Proxy or ProxyBrokers for the AMH classes
  return 0;
}

// ****************************************************************

class TAO_IDL_Downcast_Implementation_Worker
  : public TAO_IDL_Inheritance_Hierarchy_Worker
{
public:
  TAO_IDL_Downcast_Implementation_Worker ();

  virtual int emit (be_interface *base,
                    TAO_OutStream *os,
                    be_interface *derived);
};

TAO_IDL_Downcast_Implementation_Worker::
TAO_IDL_Downcast_Implementation_Worker (void)
{
}

int
TAO_IDL_Downcast_Implementation_Worker::
emit (be_interface * /* derived */,
      TAO_OutStream *os,
      be_interface *base)
{
  // @@ This whole thing would be more efficient if we could pass the
  // ACE_CString to compute_full_name, after all it uses that
  // internally.
  ACE_CString amh_name ("POA_");

  // @@ The following code is *NOT* exception-safe.
  char *buf = 0;
  base->compute_full_name ("AMH_", "", buf);
  amh_name += buf;
  delete[] buf;

  *os << "if (ACE_OS::strcmp (logical_type_id, \""
      << base->repoID () << "\") == 0)" << be_idt_nl
      << "return static_cast<"
      << amh_name.c_str () << "*> (this);" << be_uidt_nl;

  return 0;
}

int
be_visitor_amh_interface_ss::generate_downcast_implementation (be_interface *node,
                                                               TAO_OutStream *os)
{
  // Make sure the queues are empty.
  node->get_insert_queue ().reset ();
  node->get_del_queue ().reset ();


  // Insert ourselves in the queue.
  if (node->get_insert_queue ().enqueue_tail (node) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         "(%N:%l) be_interface::traverse_inheritance_graph - "
                         "error generating entries\n"),
                        -1);
    }

  TAO_IDL_Downcast_Implementation_Worker worker;
  return node->traverse_inheritance_graph (worker, os);
}

// ****************************************************************

class TAO_IDL_Copy_Ctor_Worker
  : public TAO_IDL_Inheritance_Hierarchy_Worker
{
public:
  TAO_IDL_Copy_Ctor_Worker (void);

  virtual int emit (be_interface *base,
                    TAO_OutStream *os,
                    be_interface *derived);
};

TAO_IDL_Copy_Ctor_Worker::
TAO_IDL_Copy_Ctor_Worker (void)
{
}

int
TAO_IDL_Copy_Ctor_Worker::
emit (be_interface *derived,
      TAO_OutStream *os,
      be_interface *base)
{
  if (derived == base)
    {
      return 0;
    }

  *os << "," << be_idt_nl;

  if (base->is_nested ())
    {
      be_decl *scope;
      scope = be_scope::narrow_from_scope (base->defined_in ())->decl ();

      *os << "ACE_NESTED_CLASS (POA_" << scope->name () << ", AMH_"
          << base->local_name () << ") (rhs)";
    }
  else
    {
      // @@ This whole thing would be more efficient if we could pass the
      // ACE_CString to compute_full_name, after all it uses that
      // internally.
      ACE_CString amh_name ("POA_");

      // @@ The following code is *NOT* exception-safe.
      char *buf = 0;
      base->compute_full_name ("AMH_", "", buf);
      amh_name += buf;
      delete[] buf;

      *os << amh_name.c_str () << " (rhs)";
    }

  *os << be_uidt;

  return 0;
}

int
be_visitor_amh_interface_ss::generate_copy_ctor (be_interface *node,
                                                 TAO_OutStream *os)
{
  // Make sure the queues are empty.
  node->get_insert_queue ().reset ();
  node->get_del_queue ().reset ();


  // Insert ourselves in the queue.
  if (node->get_insert_queue ().enqueue_tail (node) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         "(%N:%l) be_interface::traverse_inheritance_graph - "
                         "error generating entries\n"),
                        -1);
    }

  TAO_IDL_Copy_Ctor_Worker worker;
  return node->traverse_inheritance_graph (worker, os);
}

// ****************************************************************

ACE_CString
be_visitor_amh_interface_ss::generate_flat_name (be_interface *node)
{
  // @@ The following code is *NOT* exception-safe.
  char *buf = 0;
  node->compute_flat_name ("AMH_", "", buf);

  // @@ This whole thing would be more efficient if we could pass the
  // ACE_CString to compute_flat_name, after all it uses that
  // internally.
  ACE_CString result (buf);
  delete[] buf;

  return result;
}

ACE_CString
be_visitor_amh_interface_ss::generate_local_name (be_interface *node)
{
  ACE_CString local_name = "AMH_";
  local_name += node->local_name ();
  return local_name;
}

ACE_CString
be_visitor_amh_interface_ss::generate_full_skel_name (be_interface *node)
{
  // @@ This whole thing would be more efficient if we could pass the
  // ACE_CString to compute_full_name, after all it uses that
  // internally.
  ACE_CString result ("POA_");

  // @@ The following code is *NOT* exception-safe.
  char *buf = 0;
  node->compute_full_name ("AMH_", "", buf);
  result += buf;
  delete[] buf;

  return result;
}
