/**
 *  @file   be_visitor_ccm_pre_proc.cpp
 *
 *  @author Jeff Parsons
 */
//=============================================================================

#include "be_visitor_ccm_pre_proc.h"
#include "be_visitor_context.h"
#include "be_visitor_xplicit_pre_proc.h"
#include "be_root.h"
#include "be_operation.h"
#include "be_argument.h"
#include "be_exception.h"
#include "be_structure.h"
#include "be_sequence.h"
#include "be_valuetype.h"
#include "be_module.h"
#include "be_template_module.h"
#include "be_template_module_inst.h"
#include "be_field.h"
#include "be_typedef.h"
#include "be_connector.h"
#include "be_provides.h"
#include "be_uses.h"
#include "be_publishes.h"
#include "be_emits.h"
#include "be_consumes.h"
#include "be_extended_port.h"
#include "be_porttype.h"
#include "be_eventtype.h"
#include "be_eventtype_fwd.h"
#include "be_home.h"
#include "be_finder.h"
#include "be_extern.h"

#include "ast_generator.h"

#include "utl_exceptlist.h"
#include "utl_namelist.h"
#include "utl_err.h"

#include "fe_interface_header.h"
#include "global_extern.h"
#include "nr_extern.h"

const char *LW_EXCEP_NAMES[] =
  {
    "AlreadyConnected",
    "InvalidConnection",
    "NoConnection",
    "ExceededConnectionLimit",
    "CreateFailure",
    "RemoveFailure",
    "FinderFailure"
  };

const char *ADDL_EXCEP_NAMES[] =
  {
    "InvalidKey",
    "UnknownKeyValue",
    "DuplicateKeyValue"
  };

const int N_LW_EXCEPS =
  sizeof (LW_EXCEP_NAMES) / sizeof (char *);
const int N_ADDL_EXCEPS =
  sizeof (ADDL_EXCEP_NAMES) / sizeof (char *);

be_exception *LW_EXCEPS[N_LW_EXCEPS];
be_exception *ADDL_EXCEPS[N_ADDL_EXCEPS];

be_visitor_ccm_pre_proc::be_visitor_ccm_pre_proc (
      be_visitor_context *ctx)
  : be_visitor_component_scope (ctx),
    module_id_ ("Components"),
    cookie_ (nullptr),
    already_connected_ (nullptr),
    invalid_connection_ (nullptr),
    no_connection_ (nullptr),
    exceeded_connection_limit_ (nullptr),
    create_failure_ (nullptr),
    remove_failure_ (nullptr),
    finder_failure_ (nullptr),
    invalid_key_ (nullptr),
    unknown_key_value_ (nullptr),
    duplicate_key_value_ (nullptr),
    comp_ (nullptr),
    home_ (nullptr),
    ccm_lookups_done_ (false)
{
}

be_visitor_ccm_pre_proc::~be_visitor_ccm_pre_proc ()
{
  this->module_id_.destroy ();
}

int
be_visitor_ccm_pre_proc::visit_root (be_root *node)
{
  /// Do this before traversing the tree so the traversal
  /// will pick up the implied uses nodes we add, if any.
  /// No need to check for the -GM option here - what's
  /// generated by this call depends only on the contents
  /// of the ciao_ami_recep_names_ queue.
  int const status = this->generate_ami4ccm_uses ();

  if (status == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_root - ")
                         ACE_TEXT ("generate_ami4ccm_uses() ")
                         ACE_TEXT ("failed\n")),
                        -1);
    }

  if (this->visit_scope (node) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_root - ")
                         ACE_TEXT ("visit scope failed\n")),
                        -1);
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::visit_module (be_module *node)
{
  if (this->visit_scope (node) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_module - ")
                         ACE_TEXT ("visit scope failed\n")),
                        -1);
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::visit_component (be_component *node)
{
  /// Waiting to do this until a component is seen will ensure
  /// that Components.idl is present and the lookups will
  /// succeed. The flag ensures that the lookup is done only
  /// once.
  if (!this->ccm_lookups_done_)
    {
      if (this->lookup_cookie () == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_root - ")
                             ACE_TEXT ("Components::Cookie ")
                             ACE_TEXT ("lookup failed\n")),
                            -1);
        }

      if (this->lookup_exceptions () == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_root - ")
                             ACE_TEXT ("component exception ")
                             ACE_TEXT ("lookups failed\n")),
                            -1);
        }

      this->ccm_lookups_done_ = true;
    }

  // Set working node for all port code generation.
  this->comp_ = node;

  if (this->visit_scope (node) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_component - ")
                         ACE_TEXT ("code generation for ")
                         ACE_TEXT ("scope3 failed\n")),
                        -1);
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::visit_connector (be_connector *node)
{
  return this->visit_component (node);
}

int
be_visitor_ccm_pre_proc::visit_provides (be_provides *node)
{
  if (node->provides_type ()->is_local ())
    {
      return 0;
    }

  if (!be_global->gen_lwccm ())
    {
      // If this facet comes from a porttype, the instantiated
      // port/mirrorport name is prefixed to the facet name.
      ACE_CString prefix ("provide_");
      prefix += this->ctx_->port_prefix ();

      AST_Operation *provides_op = nullptr;
      UTL_ScopedName *op_name =
        this->create_scoped_name (prefix.c_str (),
                                  node->local_name ()->get_string (),
                                  nullptr,
                                  comp_);
      ACE_NEW_RETURN (provides_op,
                      be_operation (node->provides_type (),
                                    AST_Operation::OP_noflags,
                                    nullptr,
                                    0,
                                    0),
                      -1);

      provides_op->set_defined_in (comp_);
      provides_op->set_imported (comp_->imported ());
      provides_op->set_name (op_name);

      if (nullptr == comp_->be_add_operation (provides_op))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_provides - ")
                             ACE_TEXT ("be_add_operation() failed\n")),
                            -1);
        }
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::visit_uses (be_uses *node)
{
  if (node->uses_type ()->is_local ())
    {
      return 0;
    }

  if (!be_global->gen_lwccm ())
    {
      if (node->is_multiple ())
        {
          if (this->gen_connect_multiple (node) == -1)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 ACE_TEXT ("be_visitor_ccm_pre_proc::")
                                 ACE_TEXT ("visit_uses - ")
                                 ACE_TEXT ("gen_connect_multiple failed\n")),
                                -1);
            }

          if (this->gen_disconnect_multiple (node) == -1)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 ACE_TEXT ("be_visitor_ccm_pre_proc::")
                                 ACE_TEXT ("visit_uses - ")
                                 ACE_TEXT ("gen_disconnect_multiple failed\n")),
                                -1);
            }

          if (this->gen_get_connection_multiple (node) == -1)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 ACE_TEXT ("be_visitor_ccm_pre_proc::")
                                 ACE_TEXT ("visit_uses - ")
                                 ACE_TEXT ("gen_get_connection_single failed\n")),
                                -1);
            }
        }
      else
        {
          if (this->gen_connect_single (node) == -1)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 ACE_TEXT ("be_visitor_ccm_pre_proc::")
                                 ACE_TEXT ("visit_uses - ")
                                 ACE_TEXT ("gen_connect_single failed\n")),
                                -1);
            }

          if (this->gen_disconnect_single (node) == -1)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 ACE_TEXT ("be_visitor_ccm_pre_proc::")
                                 ACE_TEXT ("visit_uses - ")
                                 ACE_TEXT ("gen_disconnect_single failed\n")),
                                -1);
            }

          if (this->gen_get_connection_single (node) == -1)
            {
              ACE_ERROR_RETURN ((LM_ERROR,
                                 ACE_TEXT ("be_visitor_ccm_pre_proc::")
                                 ACE_TEXT ("visit_uses - ")
                                 ACE_TEXT ("gen_get_connection_single failed\n")),
                                -1);
            }
        }
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::visit_publishes (be_publishes *node)
{
  if (!be_global->gen_noeventccm ())
    {
      if (this->gen_subscribe (node) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_publishes - ")
                             ACE_TEXT ("gen_subscribe failed\n")),
                            -1);
        }

      if (this->gen_unsubscribe (node) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_publishes - ")
                             ACE_TEXT ("gen_unsubscribe failed\n")),
                            -1);
        }
    }
  return 0;
}

int
be_visitor_ccm_pre_proc::visit_emits (be_emits *node)
{
  if (!be_global->gen_noeventccm ())
    {
      if (this->gen_emits_connect (node) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_emits - ")
                             ACE_TEXT ("gen_emits_connect failed\n")),
                            -1);
        }

      if (this->gen_emits_disconnect (node) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_emits - ")
                             ACE_TEXT ("gen_emits_disconnect failed\n")),
                            -1);
        }
    }
  return 0;
}

int
be_visitor_ccm_pre_proc::visit_consumes (be_consumes *node)
{
  if (!be_global->gen_noeventccm ())
    {
      if (this->gen_get_consumer (node) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_comsumes - ")
                             ACE_TEXT ("gen_get_consumer failed\n")),
                            -1);
        }
     }
   return 0;
}

int
be_visitor_ccm_pre_proc::visit_home (be_home *node)
{
  AST_Interface *xplicit = this->create_explicit (node);

  if (xplicit == nullptr)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_home - code generation ")
                         ACE_TEXT ("for explicit interface failed\n")),
                        -1);
    }

  AST_Interface *implicit = this->create_implicit (node);

  if (implicit == nullptr)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_home - code generation ")
                         ACE_TEXT ("for implicit interface failed\n")),
                        -1);
    }

  if (this->gen_implicit_ops (node, implicit) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_home - ")
                         ACE_TEXT ("code generation for primary key ")
                         ACE_TEXT ("operations failed\n")),
                        -1);
    }

  if (this->create_equivalent (node, xplicit, implicit) == nullptr)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("visit_home - code generation ")
                         ACE_TEXT ("for equivalent interface failed\n")),
                        -1);
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::visit_eventtype (be_eventtype *node)
{
  if (!be_global->gen_noeventccm ())
    {
      if (node->ccm_pre_proc_gen ())
        {
          return 0;
        }

      if (this->create_event_consumer (node) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("visit_eventtype - code generation ")
                             ACE_TEXT ("for consumer failed\n")),
                            -1);
        }

      node->ccm_pre_proc_gen (true);
    }
  return 0;
}

int
be_visitor_ccm_pre_proc::visit_eventtype_fwd (be_eventtype_fwd *node)
{
  be_eventtype *fd =
    dynamic_cast<be_eventtype*> (node->full_definition ());

  return this->visit_eventtype (fd);
}

int
be_visitor_ccm_pre_proc::gen_implicit_ops (be_home *node,
                                           AST_Interface *implicit)
{
  if (this->gen_create (node, implicit) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_implicit_ops - ")
                         ACE_TEXT ("gen_create failed\n")),
                        -1);
    }

  AST_Type *pk = node->primary_key ();

  if (pk == nullptr)
    {
      return 0;
    }

  if (!be_global->gen_lwccm ())
    {
      if (this->gen_find_by_primary_key (node, implicit) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("gen_implicit_ops - ")
                             ACE_TEXT ("gen_find_by_primary_key failed\n")),
                            -1);
        }
    }

  if (this->gen_remove (node, implicit) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_implicit_ops - ")
                         ACE_TEXT ("gen_remove failed\n")),
                        -1);
    }

  if (!be_global->gen_lwccm ())
    {
      if (this->gen_get_primary_key (node, implicit) == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc::")
                             ACE_TEXT ("gen_implicit_ops - ")
                             ACE_TEXT ("gen_get_primary_key failed\n")),
                            -1);
        }
    }

  return 0;
}

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

int
be_visitor_ccm_pre_proc::gen_connect_single (be_uses *node)
{
  // If this facet comes from a porttype, the instantiated
  // port/mirrorport name is prefixed to the receptacle name.
  ACE_CString prefix ("connect_");
  prefix += this->ctx_->port_prefix ();

  UTL_ScopedName *op_full_name =
    this->create_scoped_name (prefix.c_str (),
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (be_global->void_type (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  op->set_name (op_full_name);
  Identifier arg_id ("conxn");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  be_argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               node->uses_type (),
                               &arg_name),
                  -1);
  arg_id.destroy ();
  op->be_add_argument (arg);

  UTL_ExceptList *tail = nullptr;
  ACE_NEW_RETURN (tail,
                  UTL_ExceptList (this->invalid_connection_,
                                  nullptr),
                  -1);
  UTL_ExceptList *connect_single = nullptr;
  ACE_NEW_RETURN (connect_single,
                  UTL_ExceptList (this->already_connected_,
                                  tail),
                 -1);
  op->be_add_exceptions (connect_single);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_disconnect_single (be_uses *node)
{
  // If this facet comes from a porttype, the instantiated
  // port/mirrorport name is prefixed to the receptacle name.
  ACE_CString prefix ("disconnect_");
  prefix += this->ctx_->port_prefix ();

  UTL_ScopedName *op_full_name =
    this->create_scoped_name (prefix.c_str (),
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (node->uses_type (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_full_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  UTL_ExceptList *disconnect_single = nullptr;
  ACE_NEW_RETURN (disconnect_single,
                  UTL_ExceptList (this->no_connection_,
                                  nullptr),
                 -1);
  op->be_add_exceptions (disconnect_single);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_get_connection_single (be_uses *node)
{
  // If this facet comes from a porttype, the instantiated
  // port/mirrorport name is prefixed to the receptacle name.
  ACE_CString prefix ("get_connection_");
  prefix += this->ctx_->port_prefix ();

  UTL_ScopedName *op_full_name =
    this->create_scoped_name (prefix.c_str (),
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (node->uses_type (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_full_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_connect_multiple (be_uses *node)
{
  // If this facet comes from a porttype, the instantiated
  // port/mirrorport name is prefixed to the receptacle name.
  ACE_CString prefix ("connect_");
  prefix += this->ctx_->port_prefix ();

  UTL_ScopedName *op_full_name =
    this->create_scoped_name (prefix.c_str (),
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);

  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (this->cookie_,
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_full_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  Identifier arg_id ("connection");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  be_argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               node->uses_type (),
                               &arg_name),
                  -1);
  arg_id.destroy ();
  op->be_add_argument (arg);
  UTL_ExceptList *tail = nullptr;
  ACE_NEW_RETURN (tail,
                  UTL_ExceptList (this->invalid_connection_,
                                  nullptr),
                  -1);
  UTL_ExceptList *connect_multiple = nullptr;
  ACE_NEW_RETURN (connect_multiple,
                  UTL_ExceptList (this->exceeded_connection_limit_,
                                  tail),
                 -1);
  op->be_add_exceptions (connect_multiple);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_disconnect_multiple (be_uses *node)
{
  // If this facet comes from a porttype, the instantiated
  // port/mirrorport name is prefixed to the receptacle name.
  ACE_CString prefix ("disconnect_");
  prefix += this->ctx_->port_prefix ();

  UTL_ScopedName *op_full_name =
    this->create_scoped_name (prefix.c_str (),
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (node->uses_type (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_full_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  Identifier arg_id ("ck");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  be_argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               this->cookie_,
                               &arg_name),
                  -1);
  arg_id.destroy ();
  op->be_add_argument (arg);
  UTL_ExceptList *disconnect_multiple = nullptr;
  ACE_NEW_RETURN (disconnect_multiple,
                  UTL_ExceptList (this->invalid_connection_,
                                  nullptr),
                 -1);
  op->be_add_exceptions (disconnect_multiple);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_get_connection_multiple (be_uses *node)
{
  // If this facet comes from a porttype, the instantiated
  // port/mirrorport name is prefixed to the receptacle name.
  ACE_CString prefix ("get_connections_");
  prefix += this->ctx_->port_prefix ();

  UTL_ScopedName *op_full_name =
    this->create_scoped_name (prefix.c_str (),
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);

  // Look up the implied IDL typedef created in the front end.
  // It will be the return type of the created operation. The
  // sequence was originally created with the port prefix (if
  // any) in its name, so we must use it here.
  ACE_CString connections_string (this->ctx_->port_prefix ());
  connections_string += node->local_name ()->get_string ();
  connections_string += "Connections";
  Identifier connections_id (connections_string.c_str ());
  UTL_ScopedName connections_name (&connections_id,
                                   nullptr);
  AST_Decl *d = comp_->lookup_by_name (&connections_name,
                                       true);
  be_typedef *td = dynamic_cast<be_typedef*> (d);
  connections_id.destroy ();

  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (td,
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_full_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_push_op (be_eventtype *node,
                                      AST_Interface *consumer)
{
  if (!be_global->gen_noeventccm ())
    {
      UTL_ScopedName *op_full_name =
        this->create_scoped_name ("push_",
                                  node->local_name (),
                                  nullptr,
                                  consumer);
      be_operation *push_op = nullptr;
      ACE_NEW_RETURN (push_op,
                      be_operation (be_global->void_type (),
                                    AST_Operation::OP_noflags,
                                    nullptr,
                                    false,
                                    false),
                      -1);
      push_op->set_defined_in (consumer);
      push_op->set_imported (node->imported ());
      push_op->set_name (op_full_name);
      ACE_CString arg_string ("the_",
                              nullptr,
                              false);
      arg_string += node->local_name ();
      Identifier arg_id (arg_string.fast_rep ());
      UTL_ScopedName arg_name (&arg_id,
                               nullptr);
      be_argument *arg = nullptr;
      ACE_NEW_RETURN (arg,
                      be_argument (AST_Argument::dir_IN,
                                   node,
                                   &arg_name),
                      -1);
      arg_id.destroy ();
      push_op->be_add_argument (arg);

      if (nullptr == consumer->be_add_operation (push_op))
        {
          return -1;
        }
     }
  return 0;
}

int
be_visitor_ccm_pre_proc::gen_subscribe (be_publishes *node)
{
  if ((be_global->gen_lwccm ()) ||(be_global->gen_noeventccm ()))
    {
      return 0;
    }

  UTL_ScopedName *op_name =
    this->create_scoped_name ("subscribe_",
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (this->cookie_,
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  op->set_name (op_name);

  AST_Interface *i = this->lookup_consumer (node);

  if (i == nullptr)
    {
      op->destroy ();
      delete op;
      op = nullptr;

      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_subscribe - ")
                         ACE_TEXT ("consumer lookup failed\n")),
                        -1);
    }

  Identifier arg_id ("consumer");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  be_argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               i,
                               &arg_name),
                  -1);
  op->be_add_argument (arg);
  UTL_ExceptList *subscribe = nullptr;
  ACE_NEW_RETURN (subscribe,
                  UTL_ExceptList (this->exceeded_connection_limit_,
                                  nullptr),
                  -1);
  op->be_add_exceptions (subscribe);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_unsubscribe (be_publishes *node)
{
  if (be_global->gen_lwccm () ||be_global->gen_noeventccm ())
    {
      return 0;
    }

  AST_Interface *i = this->lookup_consumer (node);

  if (i == nullptr)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_unsubscribe - ")
                         ACE_TEXT ("consumer lookup failed\n")),
                        -1);
    }

  UTL_ScopedName *op_name =
    this->create_scoped_name ("unsubscribe_",
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (i,
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  op->set_name (op_name);
  Identifier arg_id ("ck");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  be_argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               this->cookie_,
                               &arg_name),
                  -1);
  op->be_add_argument (arg);
  UTL_ExceptList *unsubscribe = nullptr;
  ACE_NEW_RETURN (unsubscribe,
                  UTL_ExceptList (this->invalid_connection_,
                                  nullptr),
                  -1);
  op->be_add_exceptions (unsubscribe);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_emits_connect (be_emits *node)
{
  if ((be_global->gen_lwccm ()) ||(be_global->gen_noeventccm ()))
    {
      return 0;
    }

  UTL_ScopedName *op_name =
    this->create_scoped_name ("connect_",
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (be_global->void_type (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  AST_Interface *i = this->lookup_consumer (node);

  if (i == nullptr)
    {
      op->destroy ();
      delete op;
      op = nullptr;

      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_emits_connect - ")
                         ACE_TEXT ("consumer lookup failed\n")),
                        -1);
    }

  Identifier arg_id ("consumer");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  be_argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               i,
                               &arg_name),
                  -1);
  op->be_add_argument (arg);
  UTL_ExceptList *emits_connect = nullptr;
  ACE_NEW_RETURN (emits_connect,
                  UTL_ExceptList (this->already_connected_,
                                  nullptr),
                  -1);
  op->be_add_exceptions (emits_connect);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_emits_disconnect (be_emits *node)
{
  if ((be_global->gen_lwccm ()) ||(be_global->gen_noeventccm ()))
    {
      return 0;
    }

  AST_Interface *i = this->lookup_consumer (node);

  if (i == nullptr)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_emits_disconnect - ")
                         ACE_TEXT ("consumer lookup failed\n")),
                        -1);
    }

  UTL_ScopedName *op_name =
    this->create_scoped_name ("disconnect_",
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (i,
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());
  UTL_ExceptList *emits_disconnect = nullptr;
  ACE_NEW_RETURN (emits_disconnect,
                  UTL_ExceptList (this->no_connection_,
                                  nullptr),
                  -1);
  op->be_add_exceptions (emits_disconnect);

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_get_consumer (be_consumes *node)
{
  if (be_global->gen_lwccm () || be_global->gen_noeventccm ())
    {
      return 0;
    }

  AST_Interface *i = this->lookup_consumer (node);

  if (i == nullptr)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_get_consumer - ")
                         ACE_TEXT ("consumer lookup failed\n")),
                        -1);
    }

  UTL_ScopedName *op_name =
    this->create_scoped_name ("get_consumer_",
                              node->local_name ()->get_string (),
                              nullptr,
                              comp_);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (i,
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  op->set_defined_in (comp_);
  op->set_imported (comp_->imported ());

  if (nullptr == comp_->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_create (be_home *node,
                                     AST_Interface *implicit)
{
  UTL_ScopedName *op_name = this->create_scoped_name (nullptr,
                                                      "create",
                                                      nullptr,
                                                      implicit);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (node->managed_component (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  AST_Type *pk = node->primary_key ();
  UTL_ExceptList *exceps = nullptr;
  ACE_NEW_RETURN (exceps,
                  UTL_ExceptList (this->create_failure_,
                                  nullptr),
                  -1);

  if (pk != nullptr && !be_global->gen_lwccm ())
    {
      Identifier arg_id ("key");
      UTL_ScopedName arg_name (&arg_id,
                               nullptr);
      AST_Argument *arg = nullptr;
      ACE_NEW_RETURN (arg,
                      be_argument (AST_Argument::dir_IN,
                                   pk,
                                   &arg_name),
                      -1);
      arg_id.destroy ();
      op->be_add_argument (arg);

      UTL_ExceptList *tail = nullptr;
      ACE_NEW_RETURN (tail,
                      UTL_ExceptList (this->invalid_key_,
                                      nullptr),
                      -1);
      UTL_ExceptList *middle = nullptr;
      ACE_NEW_RETURN (middle,
                      UTL_ExceptList (this->duplicate_key_value_,
                                      tail),
                      -1);
      exceps->nconc (middle);
    }

  op->be_add_exceptions (exceps);
  op->set_defined_in (implicit);
  op->set_imported (node->imported ());

  if (nullptr == implicit->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_find_by_primary_key (be_home *node,
                                                  AST_Interface *implicit)
{
  UTL_ScopedName *op_name = this->create_scoped_name (nullptr,
                                                      "find_by_primary_key",
                                                      nullptr,
                                                      implicit);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (node->managed_component (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  AST_Type *pk = node->primary_key ();
  Identifier arg_id ("key");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  AST_Argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               pk,
                               &arg_name),
                  -1);
  arg_id.destroy ();
  op->be_add_argument (arg);

  UTL_ExceptList *tail = nullptr;
  UTL_ExceptList *middle = nullptr;

  if (!be_global->gen_lwccm ())
    {
      ACE_NEW_RETURN (tail,
                      UTL_ExceptList (this->invalid_key_,
                                      nullptr),
                      -1);
      ACE_NEW_RETURN (middle,
                      UTL_ExceptList (this->unknown_key_value_,
                                      tail),
                      -1);
    }

  UTL_ExceptList *exceps = nullptr;
  ACE_NEW_RETURN (exceps,
                  UTL_ExceptList (this->finder_failure_,
                                  middle),
                  -1);
  op->be_add_exceptions (exceps);
  op->set_defined_in (implicit);
  op->set_imported (node->imported ());

  if (nullptr == implicit->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_remove (be_home *node,
                                     AST_Interface *implicit)
{
  UTL_ScopedName *op_name = this->create_scoped_name (nullptr,
                                                      "remove",
                                                      nullptr,
                                                      implicit);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (be_global->void_type (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  AST_Type *pk = node->primary_key ();
  Identifier arg_id ("key");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  AST_Argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               pk,
                               &arg_name),
                  -1);
  arg_id.destroy ();
  op->be_add_argument (arg);

  UTL_ExceptList *tail = nullptr;
  UTL_ExceptList *middle = nullptr;

  if (!be_global->gen_lwccm ())
    {
      ACE_NEW_RETURN (tail,
                      UTL_ExceptList (this->invalid_key_,
                                      nullptr),
                      -1);
      ACE_NEW_RETURN (middle,
                      UTL_ExceptList (this->unknown_key_value_,
                                      tail),
                      -1);
    }

  UTL_ExceptList *exceps = nullptr;
  ACE_NEW_RETURN (exceps,
                  UTL_ExceptList (this->remove_failure_,
                                  middle),
                  -1);
  op->be_add_exceptions (exceps);
  op->set_defined_in (implicit);
  op->set_imported (node->imported ());

  if (nullptr == implicit->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_get_primary_key (be_home *node,
                                              AST_Interface *implicit)
{
  UTL_ScopedName *op_name = this->create_scoped_name (nullptr,
                                                      "get_primary_key",
                                                      nullptr,
                                                      implicit);
  be_operation *op = nullptr;
  ACE_NEW_RETURN (op,
                  be_operation (node->primary_key (),
                                AST_Operation::OP_noflags,
                                nullptr,
                                0,
                                0),
                  -1);
  op->set_name (op_name);
  Identifier arg_id ("comp");
  UTL_ScopedName arg_name (&arg_id,
                           nullptr);
  AST_Argument *arg = nullptr;
  ACE_NEW_RETURN (arg,
                  be_argument (AST_Argument::dir_IN,
                               node->managed_component (),
                               &arg_name),
                  -1);
  arg_id.destroy ();
  op->be_add_argument (arg);
  op->set_defined_in (implicit);
  op->set_imported (node->imported ());

  if (nullptr == implicit->be_add_operation (op))
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::gen_extended_port (be_porttype *pt)
{
  if (this->visit_scope (pt) == -1)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("gen_extended_port - ")
                         ACE_TEXT ("visit_scope for porttype failed\n")),
                        -1);
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::lookup_cookie ()
{
  if (this->cookie_ == nullptr)
    {
      Identifier local_id ("Cookie");
      UTL_ScopedName local_name (&local_id,
                                 nullptr);
      UTL_ScopedName cookie_name (&this->module_id_,
                                  &local_name);
      AST_Decl *d =
        idl_global->root ()->lookup_by_name (&cookie_name,
                                             true);
      local_id.destroy ();

      if (d == nullptr)
        {
          idl_global->err ()->lookup_error (&cookie_name);
          return -1;
        }

      this->cookie_ = dynamic_cast<be_valuetype*> (d);

      if (this->cookie_ == nullptr)
        {
          idl_global->err ()->valuetype_expected (d);
          return -1;
        }
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::lookup_exceptions ()
{
  int status = 0;

  for (int i = 0; i < N_LW_EXCEPS; ++i)
    {
      status = this->lookup_one_exception (LW_EXCEP_NAMES[i],
                                           LW_EXCEPS[i]);

      if (status == -1)
        {
          return -1;
        }
    }

  this->already_connected_          = LW_EXCEPS[0];
  this->invalid_connection_         = LW_EXCEPS[1];
  this->no_connection_              = LW_EXCEPS[2];
  this->exceeded_connection_limit_  = LW_EXCEPS[3];
  this->create_failure_             = LW_EXCEPS[4];
  this->remove_failure_             = LW_EXCEPS[5];
  this->finder_failure_             = LW_EXCEPS[6];

  if (!be_global->gen_lwccm ())
    {
      for (int j = 0; j < N_ADDL_EXCEPS; ++j)
        {
          status = this->lookup_one_exception (ADDL_EXCEP_NAMES[j],
                                               ADDL_EXCEPS[j]);

          if (status == -1)
            {
              return -1;
            }
        }

      this->invalid_key_                = ADDL_EXCEPS[0];
      this->unknown_key_value_          = ADDL_EXCEPS[1];
      this->duplicate_key_value_        = ADDL_EXCEPS[2];
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::lookup_one_exception (const char *name,
                                               be_exception *&result)
{
  Identifier id (name);
  UTL_ScopedName local_name (&id,
                             nullptr);
  UTL_ScopedName scoped_name (&this->module_id_,
                              &local_name);
  AST_Decl *d =
    idl_global->root ()->lookup_by_name (&scoped_name,
                                         true);
  id.destroy ();

  if (d == nullptr)
    {
      idl_global->err ()->lookup_error (&scoped_name);
      return -1;
    }

  result = dynamic_cast<be_exception*> (d);

  if (result == nullptr)
    {
      return -1;
    }

  return 0;
}

int
be_visitor_ccm_pre_proc::create_event_consumer (be_eventtype *node)
{
  UTL_Scope *s = node->defined_in ();

  UTL_ScopedName *consumer_name =
    this->create_scoped_name (nullptr,
                              node->local_name (),
                              "Consumer",
                              ScopeAsDecl (node->defined_in ()));

  /// We need to create event consumers even for forward
  /// declared eventtypes. Since forward declarations can
  /// appear any number of times, we need to check that this
  /// event consumer hasn't already been created.
  if (s->lookup_by_name (consumer_name, true) != nullptr)
    {
      return 0;
    }

  AST_Interface *event_consumer = nullptr;
  AST_Module *m = dynamic_cast<AST_Module*> (s);

  // We're at global scope here so we need to fool the scope stack
  // for a minute so the correct repo id can be calculated at
  // interface construction time.
  idl_global->scopes ().push (s);

  Identifier parent_id ("EventConsumerBase");
  UTL_ScopedName parent_local_name (&parent_id,
                                    nullptr);
  UTL_ScopedName parent_full_name (&this->module_id_,
                                   &parent_local_name);
  UTL_NameList parent_list (&parent_full_name,
                            nullptr);
  FE_InterfaceHeader header (consumer_name,
                             &parent_list,
                             false,
                             false,
                             true);
  ACE_NEW_RETURN (event_consumer,
                  be_interface (header.name (),
                                header.inherits (),
                                header.n_inherits (),
                                header.inherits_flat (),
                                header.n_inherits_flat (),
                                false,
                                false),
                  -1);
  parent_id.destroy ();

  // Back to reality.
  idl_global->scopes ().pop ();

  event_consumer->set_defined_in (s);
  event_consumer->set_imported (node->imported ());
  event_consumer->set_name (consumer_name);
  be_interface *bec =
    dynamic_cast<be_interface*> (event_consumer);
  bec->original_interface (node);

  // Set repo id to 0, so it will be recomputed on the next access,
  // and set the prefix to the eventtype's prefix. All this is
  // necessary in case the eventtype's prefix was modified after
  // its declaration. We assume 'implied IDL' means that the
  // derived event consumer interface should have the same prefix.
  event_consumer->repoID (nullptr);
  event_consumer->prefix (const_cast<char*> (node->prefix ()));

  dynamic_cast<be_type*> (event_consumer)->gen_fwd_helper_name ();
  m->be_add_interface (event_consumer);
  return this->gen_push_op (node,
                            event_consumer);
}

AST_Interface *
be_visitor_ccm_pre_proc::lookup_consumer (be_field *node)
{
  AST_Type *impl = node->field_type ();
  ACE_CString rettype_string (impl->local_name ()->get_string ());
  rettype_string += "Consumer";
  Identifier rettype_id (rettype_string.fast_rep ());
  AST_Decl *d =
    impl->defined_in ()->lookup_by_name_local (&rettype_id, false);
  rettype_id.destroy ();

  if (d == nullptr)
    {
      return nullptr;
    }

  AST_Interface *i = dynamic_cast<AST_Interface*> (d);

  if (i == nullptr)
    {
      idl_global->err ()->interface_expected (d);
      return nullptr;
    }

  return i;
}

AST_Interface *
be_visitor_ccm_pre_proc::create_explicit (be_home *node)
{
  be_visitor_xplicit_pre_proc v (this->ctx_);

  if (v.visit_home (node) != 0)
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("be_visitor_ccm_pre_proc::")
                         ACE_TEXT ("create_explicit - ")
                         ACE_TEXT ("home xplicit visitor failed\n")),
                        0);
    }

  return v.xplicit ();
}

AST_Interface *
be_visitor_ccm_pre_proc::create_implicit (be_home *node)
{
  Identifier *parent_id = nullptr;
  ACE_NEW_RETURN (parent_id,
                  Identifier ("KeylessCCMHome"),
                  nullptr);

  UTL_ScopedName *parent_local_name = nullptr;
  ACE_NEW_RETURN (parent_local_name,
                  UTL_ScopedName (parent_id, nullptr),
                  nullptr);

  UTL_ScopedName *parent_full_name = nullptr;
  ACE_NEW_RETURN (parent_full_name,
                  UTL_ScopedName (this->module_id_.copy (),
                                  parent_local_name),
                  nullptr);

  UTL_NameList parent_list (parent_full_name, nullptr);

  UTL_NameList *parent_list_ptr = nullptr;

  if (node->primary_key () == nullptr)
    {
      parent_list_ptr = &parent_list;
    }

  FE_InterfaceHeader header (nullptr,
                             parent_list_ptr,
                             false,
                             false,
                             true);

  // We're at global scope here so we need to fool the scope stack
  // for a minute so the correct repo id can be calculated at
  // interface construction time.
  idl_global->scopes ().push (node->defined_in ());

  UTL_ScopedName *implicit_name =
    this->create_scoped_name (nullptr,
                              node->local_name (),
                              "Implicit",
                              ScopeAsDecl (node->defined_in ()));

  be_interface *i = nullptr;
  ACE_NEW_RETURN (i,
                  be_interface (implicit_name,
                                header.inherits (),
                                header.n_inherits (),
                                header.inherits_flat (),
                                header.n_inherits_flat (),
                                false,
                                false),
                  nullptr);

  // Back to reality.
  idl_global->scopes ().pop ();

  header.destroy ();
  parent_list.destroy ();

  // So we can generate the proper typecode.
  i->home_equiv (true);

  i->set_name (implicit_name);
  i->set_defined_in (node->defined_in ());
  i->set_imported (node->imported ());

  i->gen_fwd_helper_name ();
  i->original_interface (node);
  AST_Module *m = dynamic_cast<AST_Module*> (node->defined_in ());
  m->be_add_interface (i);

  return i;
}

AST_Interface *
be_visitor_ccm_pre_proc::create_equivalent (be_home *node,
                                            AST_Interface *xplicit,
                                            AST_Interface *implicit)
{
  UTL_Scope *s = node->defined_in ();
  UTL_ScopedName *equiv_name =
    this->create_scoped_name (nullptr,
                              node->local_name (),
                              nullptr,
                              ScopeAsDecl (s));
  UTL_NameList tail (implicit->name (),
                     nullptr);
  UTL_NameList parent_list (xplicit->name (),
                            &tail);
  FE_InterfaceHeader header (nullptr,
                             &parent_list,
                             false,
                             false,
                             true);

  // We're at global scope here so we need to fool the scope stack
  // for a minute so the correct repo id can be calculated at
  // interface construction time.
  idl_global->scopes ().push (node->defined_in ());

  be_interface *retval = nullptr;
  ACE_NEW_RETURN (retval,
                  be_interface (equiv_name,
                                header.inherits (),
                                header.n_inherits (),
                                header.inherits_flat (),
                                header.n_inherits_flat (),
                                false,
                                false),
                  nullptr);

  // Back to reality.
  idl_global->scopes ().pop ();

  // So we can generate the proper typecode.
  retval->home_equiv (true);

  retval->set_name (equiv_name);
  retval->set_defined_in (s);
  retval->set_imported (node->imported ());
  retval->gen_fwd_helper_name ();
  retval->original_interface (node);

  UTL_ScopedName *unmangled_name =
    static_cast<UTL_ScopedName *> (node->name ()->copy ());
  UTL_ScopedName *mangled_name =
    this->create_scoped_name (nullptr,
                              node->local_name (),
                              "_tao_home_name_extension",
                              ScopeAsDecl (s));
  node->set_name (mangled_name);
  AST_Module *m = dynamic_cast<AST_Module*> (s);

  /// Calling be_add_interface() here calls add_to_referenced(),
  /// which will give a redef error.
  m->add_to_scope (retval);

  node->set_name (unmangled_name);
  return retval;
}

UTL_ScopedName *
be_visitor_ccm_pre_proc::create_scoped_name (const char *prefix,
                                             const char *local_name,
                                             const char *suffix,
                                             AST_Decl *parent)
{
  ACE_CString local_string (prefix,
                            nullptr,
                            false);
  local_string += local_name;
  local_string += suffix;
  Identifier *local_id = nullptr;
  ACE_NEW_RETURN (local_id,
                  Identifier (local_string.fast_rep ()),
                  nullptr);
  UTL_ScopedName *last_segment = nullptr;
  ACE_NEW_RETURN (last_segment,
                  UTL_ScopedName (local_id,
                                  nullptr),
                  nullptr);
  UTL_ScopedName *full_name =
    static_cast<UTL_ScopedName *> (parent->name ()->copy ());
  full_name->nconc (last_segment);
  return full_name;
}

UTL_NameList *
be_visitor_ccm_pre_proc::compute_inheritance (be_home *node)
{
  UTL_NameList *retval = nullptr;

  if (node->base_home () == nullptr)
    {
      Identifier *local_id = nullptr;
      ACE_NEW_RETURN (local_id,
                      Identifier ("CCMHome"),
                      nullptr);
      UTL_ScopedName *local_name = nullptr;
      ACE_NEW_RETURN (local_name,
                      UTL_ScopedName (local_id,
                                      nullptr),
                      nullptr);
      UTL_ScopedName *full_name = nullptr;
      ACE_NEW_RETURN (full_name,
                      UTL_ScopedName (this->module_id_.copy (),
                                      local_name),
                      nullptr);
      ACE_NEW_RETURN (retval,
                      UTL_NameList (full_name,
                                    nullptr),
                      nullptr);
    }
  else
    {
      ACE_CString new_local (
          node->base_home ()->local_name ()->get_string ()
        );
      new_local += "Explicit";
      UTL_ScopedName *parent_name =
        static_cast<UTL_ScopedName *> (node->base_home ()->name ()->copy ());
      parent_name->last_component ()->replace_string (new_local.c_str ());
      ACE_NEW_RETURN (retval,
                      UTL_NameList (parent_name,
                                    nullptr),
                      nullptr);
    }

  long n_supports = node->n_inherits ();
  UTL_ScopedName *supported_name = nullptr;
  UTL_NameList *conc_value = nullptr;

  for (long i = 0; i < n_supports; ++i)
    {
      supported_name =
        static_cast<UTL_ScopedName *> (node->inherits ()[i]->name ()->copy ());
      ACE_NEW_RETURN (conc_value,
                      UTL_NameList (supported_name,
                                    nullptr),
                      nullptr);
      retval->nconc (conc_value);
    }

  return retval;
}

int
be_visitor_ccm_pre_proc::generate_ami4ccm_uses ()
{
  /// The interfaces in the list below are from this IDL file,
  /// which then must be processed with the -GC option, so we
  /// know we'll get here - a good place to generate the *A.idl
  /// file containing the local interfaces and connector
  /// associated with each interface in the list.

  ACE_Unbounded_Queue<char *> &ccm_ami_receps =
    idl_global->ciao_ami_recep_names ();

  /// If the queue is empty, we're done.
  if (ccm_ami_receps.size () == 0)
    {
      return 0;
    }

  for (ACE_Unbounded_Queue<char *>::CONST_ITERATOR i (
         ccm_ami_receps);
       ! i.done ();
       i.advance ())
    {
      char **item = nullptr;
      i.next (item);

      UTL_ScopedName *sn =
        FE_Utils::string_to_scoped_name (*item);

      UTL_Scope *s =
        idl_global->scopes ().top_non_null ();

      AST_Decl *d = s->lookup_by_name (sn, true);

      if (d == nullptr)
        {
          idl_global->err ()->lookup_error (sn);

          sn->destroy ();
          delete sn;
          sn = nullptr;

          continue;
        }

      sn->destroy ();
      delete sn;
      sn = nullptr;

      be_uses *u = dynamic_cast<be_uses*> (d);

      if (u == nullptr)
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("be_visitor_ccm_pre_proc")
                             ACE_TEXT ("::generate_ami4ccm_uses - ")
                             ACE_TEXT ("narrow to receptacle ")
                             ACE_TEXT ("failed\n")),
                            -1);
        }

      be_interface *iface =
        dynamic_cast<be_interface*> (u->uses_type ());

      /// The real AMI_xxx exists only in the *A.idl file, so
      /// we create a dummy as the uses type for the implied
      /// receptacle created below, but only if it hasn't
      /// already been created for this uses type.

      be_interface *ami_iface =
        dynamic_cast<be_interface*> (iface->ami4ccm_uses ());

      if (ami_iface == nullptr)
        {
          ACE_CString iname ("AMI4CCM_");

          iname += iface->local_name ();
          Identifier itmp_id (iname.c_str ());
          UTL_ScopedName itmp_sn (&itmp_id, nullptr);

          s = iface->defined_in ();
          idl_global->scopes ().push (s);
          ACE_NEW_RETURN (ami_iface,
                          be_interface (&itmp_sn,
                                        nullptr,
                                        0,
                                        nullptr,
                                        0,
                                        true,
                                        false),
                           -1);

          idl_global->scopes ().pop ();

          /// Make it imported so it doesn't trigger
          /// any unwanted code generation.
          ami_iface->set_imported (true);

          s->add_to_scope (ami_iface);
          iface->ami4ccm_uses (ami_iface);
        }

      /// Now create the receptacle, passing in
      /// the local interface created above as the
      /// uses type. We don't generate anything
      /// in the main IDL file from the interface's
      /// contents, so it's ok that it's empty.

      ACE_CString uname ("sendc_");
      uname += u->local_name ()->get_string ();
      Identifier utmp_id (uname.c_str ());
      UTL_ScopedName utmp_sn (&utmp_id, nullptr);

      s = u->defined_in ();
      idl_global->scopes ().push (s);
      be_uses *ami_uses = nullptr;
      ACE_NEW_RETURN (ami_uses,
                      be_uses (&utmp_sn,
                               ami_iface,
                               u->is_multiple ()),
                      -1);

      s->add_to_scope (ami_uses);
      idl_global->scopes ().pop ();

      if (u->is_multiple ())
        {
        /*
      AST_Type *t = u->uses_type ();
      ACE_CString fname (t->file_name ());
      char *dummy = 0;
      char *path = ACE_OS::realpath (fname.c_str (), dummy);
      ACE_DEBUG ((LM_DEBUG, "utype file: %s\n", path));
        */
          // Grammar ensures this narrowing will never be 0.
          AST_Component *c =
            dynamic_cast<AST_Component*> (s);
          FE_Utils::create_uses_multiple_stuff (c, ami_uses);
        }
    }

  return 0;
}

