# -*- python -*-
#                           Package   : omniidl
# iface.py                  Created on: 2000/8/10
#			    Author    : David Scott (djs)
#
#    Copyright (C) 2002-2008 Apasphere Ltd
#    Copyright (C) 2000 AT&T Laboratories Cambridge
#
#  This file is part of omniidl.
#
#  omniidl is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#  02111-1307, USA.
#
# Description:
#   
#   Code associated with IDL interfaces

# $Id: iface.py 5982 2010-10-11 21:36:36Z dgrisby $
# $Log$
# Revision 1.1.6.17  2008/12/30 15:38:27  dgrisby
# Scope change broke structs defined in interfaces that use them.
#
# Revision 1.1.6.16  2008/12/29 18:03:34  dgrisby
# More C++ backend scope errors. Thanks Gellule Xg.
#
# Revision 1.1.6.15  2007/12/05 11:15:58  dgrisby
# Incorrect generated code involving ::CORBA::AbstractBase.
#
# Revision 1.1.6.14  2007/09/19 14:16:08  dgrisby
# Avoid namespace clashes if IDL defines modules named CORBA.
#
# Revision 1.1.6.13  2006/01/24 11:46:03  dgrisby
# Interfaces inheriting from a typedef caused an omniidl compiler error.
# Thanks Renzo Tomaselli.
#
# Revision 1.1.6.12  2005/11/18 18:23:06  dgrisby
# New -Wbimpl_mapping option.
#
# Revision 1.1.6.11  2005/11/14 11:02:16  dgrisby
# Local interface fixes.
#
# Revision 1.1.6.10  2005/11/09 12:22:17  dgrisby
# Local interfaces support.
#
# Revision 1.1.6.9  2005/09/19 15:36:35  dgrisby
# Refcount shortcut now throws INV_OBJREF when the servant is
# deactivated, rather than deactivating the shortcut, which could lead
# to a race condition.
#
# Revision 1.1.6.8  2005/09/05 17:22:09  dgrisby
# Reference counted local call shortcut.
#
# Revision 1.1.6.7  2005/08/16 13:51:21  dgrisby
# Problems with valuetype / abstract interface C++ mapping.
#
# Revision 1.1.6.6  2005/01/06 23:09:50  dgrisby
# Big merge from omni4_0_develop.
#
# Revision 1.1.6.5  2005/01/06 16:35:18  dgrisby
# Narrowing for abstract interfaces.
#
# Revision 1.1.6.4  2004/10/13 17:58:22  dgrisby
# Abstract interfaces support; values support interfaces; value bug fixes.
#
# Revision 1.1.6.3  2003/11/06 11:56:56  dgrisby
# Yet more valuetype. Plain valuetype and abstract valuetype are now working.
#
# Revision 1.1.6.2  2003/10/23 11:25:54  dgrisby
# More valuetype support.
#
# Revision 1.1.6.1  2003/03/23 21:02:41  dgrisby
# Start of omniORB 4.1.x development branch.
#
# Revision 1.1.4.12  2003/03/03 15:02:30  dgrisby
# -Wbvirtual_objref option went astray. Thanks Malge Nishant.
#
# Revision 1.1.4.11  2002/08/16 15:56:27  dgrisby
# Bug in generated code with evil IDL that uses the same parameter
# names as type names.
#
# Revision 1.1.4.10  2001/11/08 16:33:51  dpg1
# Local servant POA shortcut policy.
#
# Revision 1.1.4.9  2001/11/07 15:45:53  dpg1
# Faster _ptrToInterface/_ptrToObjRef in common cases.
#
# Revision 1.1.4.8  2001/08/15 10:26:10  dpg1
# New object table behaviour, correct POA semantics.
#
# Revision 1.1.4.7  2001/07/25 13:40:52  dpg1
# Suppress compiler warning about unused variable in _dispatch() for
# empty interfaces.
#
# Revision 1.1.4.6  2001/07/25 11:42:15  dpg1
# Generate correct code for operation parameters whose names clash with
# C++ keywords.
#
# Revision 1.1.4.5  2001/06/08 17:12:13  dpg1
# Merge all the bug fixes from omni3_develop.
#
# Revision 1.1.4.4  2001/01/25 13:09:11  sll
# Fixed up cxx backend to stop it from dying when a relative
# path name is given to the -p option of omniidl.
#
# Revision 1.1.4.3  2000/11/07 18:27:51  sll
# Pass environment to out_objrefcall.
#
# Revision 1.1.4.2  2000/11/03 19:30:21  sll
# Rationalise code generation. Consolidate all code that use call descriptors
# into the CallDescriptor class.
#
# Revision 1.1.4.1  2000/10/12 15:37:47  sll
# Updated from omni3_1_develop.
#
# Revision 1.1.2.2  2000/09/14 16:03:02  djs
# Remodularised C++ descriptor name generator
# Bug in listing all inherited interfaces if one is a forward
# repoID munging function now handles #pragma ID in bootstrap.idl
# Naming environments generating code now copes with new IDL AST types
# Modified type utility functions
# Minor tidying
#
# Revision 1.1.2.1  2000/08/21 11:34:34  djs
# Lots of omniidl/C++ backend changes
#

# o Keep related code in one place
# o Expose internals at a finer granularity than before (useful for
#   overriding one aspect (eg _objref class for AMI))

import string

from omniidl import idlast, idltype
from omniidl_be.cxx import types, id, call, ast, cxx, output, config, descriptor
# from omniidl_be.cxx import header
# from omniidl_be.cxx import skel
# XXX it seems that the above import fails when this file is import by
#     cxx.header.defs AND a relative patch -p argument is given to omniidl
#     Use the following import works.
import omniidl_be.cxx.skel
import omniidl_be.cxx.header


# Interface is a wrapper around an IDL interface
#  .callables():   get a list of Callable objects representing the operations
#                  and attributes
#  .inherits():    get a list of all directly inherited interfaces
#  .allInherits(): get all inherited interfaces (using a breadth first search)
#  .name():        return the IDL fully scoped name (as an id.Name)
#  .environment(): returns the IDL environment where this interface was
#                  declared
class Interface:
  """Wrapper around an IDL interface"""
  def __init__(self, node):
    self._node = node
    self._environment = id.lookup(node)
    self._node_name = id.Name(node.scopedName())

  def callables(self):
    """Return a list of Callable objects representing the combined operations
       and attributes for this interface"""
    
    if hasattr(self, "_callables"):
      return self._callables
    
    # build a list of all the Callable objects
    # The old backend processed all operations first
    # (FIXME: duplicate for the sake of easy checking)
    self._callables = []

    for c in self._node.callables():
      if isinstance(c, idlast.Operation):
        self._callables.append(call.operation(self, c))
        
    for c in self._node.callables():
      if isinstance(c, idlast.Attribute):
        self._callables = self._callables + call.read_attributes(self, c)
        if c.readonly(): continue
        self._callables = self._callables + call.write_attributes(self, c)
      
    return self._callables

  def inherits(self):
    return map(lambda x:Interface(x), self._node.fullDecl().inherits())

  def allInherits(self):
    return map(lambda x:Interface(x), ast.allInherits(self._node))

  def local(self):
    return self._node.fullDecl().local()

  def abstract(self):
    return self._node.fullDecl().abstract()

  def name(self):
    return self._node_name
    
  def environment(self):
    return self._environment
  
  
_classes = {}
_proxy_call_descriptors = {}

def instance(name):
  if _classes.has_key(name):
    return _classes[name]

  instance = eval(name)
  _classes[name] = instance
  return instance

def register_class(name, cl):
  _classes[name] = cl


# Class associated with an IDL interface.
#  .interface():   return the associated Interface object
#  .methods():     return a list of Method objects
#  .environment(): return the IDL environment associated with the interface
class Class(cxx.Class):
  def __init__(self, interface):
    assert isinstance(interface, Interface)
    cxx.Class.__init__(self, interface.name())
    
    self._interface = interface
    self._environment = interface.environment()
    self._methods = []
    self._callables = {}

  def interface(self):   return self._interface
  def methods(self):     return self._methods
  def environment(self): return self._environment


class _objref_Method(cxx.Method):
  def __init__(self, callable, parent_class):
    assert isinstance(callable, call.Callable)
    self._callable = callable
    self._parent_class = parent_class
    self.from_Callable()

  def callable(self): return self._callable

  def from_Callable(self):
    use_out = not config.state["Impl Mapping"]
    self._from_Callable(use_out = use_out)

  def _from_Callable(self, use_out):
    # Grab the IDL environment
    ifc = self.callable().interface()
    environment = ifc.environment().enter("_objref_" + ifc.name().simple())

    # Kept as a type object because in .cc part the _return_ type
    # must be fully qualified.
    self._return_type = types.Type(self.callable().returnType())

    # Parameters are always relative, both in .hh and .cc
    (param_types, param_names) = ([], [])
    for p in self.callable().parameters():
      pType = types.Type(p.paramType())
      direction = types.direction(p)
      param_types.append(pType.op(direction, environment,
                                  use_out = use_out))

      # Special ugly case. If the IDL says something like (in foo::bar
      # bar), the parameter name may be the same as the relative type
      # name. We mangle the parameter name if this happens.

      typeBase = pType.base(environment)
      ident    = id.mapID(p.identifier())

      if typeBase == ident:
        ident = "_" + ident

      param_names.append(ident)
      
    # an operation has optional context
    if self.callable().contexts() != []:
      param_types.append("::CORBA::Context_ptr")
      param_names.append("_ctxt")

    self._arg_types = param_types
    self._arg_names = param_names
    self._name = self.callable().method_name()


class _impl_Method(_objref_Method):
  def __init__(self, callable, parent_class):
    _objref_Method.__init__(self, callable, parent_class)

  def from_Callable(self):
    self._from_Callable(use_out = 0)


class I_Helper(Class):
  def __init__(self, I):
    Class.__init__(self, I)
    self._name = self._name.suffix("_Helper")

  def hh(self, stream):
    class_sk_name = ""
    if config.state['BOA Skeletons']:
      class_sk_name = "class " + \
                      self.interface().name().prefix("_sk_").simple() + ";"

    if self.interface().abstract():
      helper_tpl = omniidl_be.cxx.header.template.abstract_interface_Helper
    elif self.interface().local():
      helper_tpl = omniidl_be.cxx.header.template.local_interface_Helper
    else:
      helper_tpl = omniidl_be.cxx.header.template.interface_Helper

    stream.out(helper_tpl,
               class_sk_name = class_sk_name,
               name = self.interface().name().simple(),
               guard = self.interface().name().guard())

  def cc(self, stream):
    stream.out(omniidl_be.cxx.skel.template.interface_Helper,
               name = self.interface().name().fullyQualify())


class I(Class):
  def __init__(self, i, other_idl):
    Class.__init__(self, i)
    self._other_idl = other_idl

  def hh(self, stream):
    if self.interface().abstract():

      for callable in self.interface().callables():
        method = _impl_Method(callable, self)
        self._methods.append(method)
        self._callables[method] = callable

      methodl = []
      for method in self.methods():
          methodl.append(method.hh(virtual = 1, pure = 1))

      inh = self.interface().inherits()
      if inh:
        inheritl = []
        for i in inh:
          iname = i.name().unambiguous(self._environment)
          inheritl.append("public virtual " + iname)
      else:
        inheritl = [ "public virtual ::CORBA::AbstractBase" ]

      stream.out(omniidl_be.cxx.header.template.abstract_interface_type,
                 name=self.interface().name().simple(),
                 Other_IDL = self._other_idl,
                 inherits = string.join(inheritl, ",\n"),
                 operations = string.join(methodl, "\n"))

    elif self.interface().local():
      abstract_base = 0
      for i in self.interface().allInherits():
        if i.abstract():
          abstract_base = 1
          break

      if abstract_base:
        abstract_narrows = omniidl_be.cxx.header.template.\
                           interface_abstract_narrows
      else:
        abstract_narrows = ""

      for callable in self.interface().callables():
        method = _impl_Method(callable, self)
        self._methods.append(method)
        self._callables[method] = callable

      # Override methods from inherited non-local interfaces
      for i in self.interface().allInherits():
        if not i.local():
          for c in i.callables():
            # Make new callable with ref to this interface instead of
            # inherited interface
            callable = call.Callable(self.interface(),
                                     c.operation_name(),
                                     c.method_name(),
                                     c.returnType(),
                                     c.parameters(),
                                     c.oneway(),
                                     c.raises(),
                                     c.contexts())

            method = _impl_Method(callable, self)
            self._methods.append(method)
            self._callables[method] = callable

      bmethodl = []
      nmethodl = []
      for method in self.methods():
          bmethodl.append(method.hh(virtual = 1, pure = 1))
          nmethodl.append(method.hh(virtual = 1, pure = 0))

      local_base = 0
      inheritl   = []
      ninheritl  = []

      for i in self.interface().inherits():
        if i.local():
          local_base = 1
          iname = i.name().unambiguous(self._environment)
          niname = i.name().prefix("_nil_").unambiguous(self._environment)
          ninheritl.append(niname)
        else:
          iname = i.name().prefix("_objref_").unambiguous(self._environment)

        inheritl.append("public virtual " + iname)

      if not local_base:
        inheritl.append("public virtual ::CORBA::LocalObject")

      if ninheritl:
        nil_inherits = string.join(ninheritl, ",\n") + ","
      else:
        nil_inherits = ""

      stream.out(omniidl_be.cxx.header.template.local_interface_type,
                 name=self.interface().name().simple(),
                 abstract_narrows = abstract_narrows,
                 Other_IDL = self._other_idl,
                 inherits = string.join(inheritl, ",\n"),
                 operations = string.join(bmethodl, "\n"),
                 nil_operations = string.join(nmethodl, "\n"),
                 nil_inherits = nil_inherits)

    else:
      abstract_base = 0
      for i in self.interface().allInherits():
        if i.abstract():
          abstract_base = 1
          break

      if abstract_base:
        abstract_narrows = omniidl_be.cxx.header.template.\
                           interface_abstract_narrows
      else:
        abstract_narrows = ""

      stream.out(omniidl_be.cxx.header.template.interface_type,
                 name=self.interface().name().simple(),
                 abstract_narrows = abstract_narrows,
                 Other_IDL = self._other_idl)



class _objref_I(Class):
  def __init__(self, I):
    Class.__init__(self, I)
    self._name = self._name.prefix("_objref_")

    # In abstract interfaces, signatures are like _impl classes, not
    # normal _objref classes.
    if self.interface().abstract():
      cls = _impl_Method
    else:
      cls = _objref_Method

    for callable in self.interface().callables():
      method = cls(callable, self)
      self._methods.append(method)
      self._callables[method] = callable


  def hh(self, stream):
    # build the inheritance list

    objref_inherits = []

    inh = self.interface().inherits()
    if inh:
      for i in inh:
        objref_inherited_name = i.name().prefix("_objref_")
        uname = objref_inherited_name.unambiguous(self._environment)
        objref_inherits.append("public virtual " + uname)
    else:
      if self.interface().abstract():
        objref_inherits = [ "public virtual ::CORBA::_omni_AbstractBaseObjref",
                            "public virtual omniObjRef" ]
      else:
        objref_inherits = [ "public virtual ::CORBA::Object",
                            "public virtual omniObjRef" ]

    if self.interface().abstract():
      objref_inherits.append("public virtual " +
                             self.interface().name().simple())

    methods = []
    for method in self.methods():
      if config.state['Virtual Objref Methods']:
        methods.append(method.hh(virtual = 1, pure = 0))
      else:
        methods.append(method.hh())

    if config.state['Shortcut']:
      shortcut = output.StringStream()
      shortcut.out(omniidl_be.cxx.header.template.interface_shortcut,
                   name = self.interface().name().simple())
      shortcut = str(shortcut)
      init_shortcut = ": _shortcut(0)"
    else:
      shortcut = ""
      init_shortcut = ""

    stream.out(omniidl_be.cxx.header.template.interface_objref,
               name = self.interface().name().simple(),
               inherits = string.join(objref_inherits, ",\n"),
               operations = string.join(methods, "\n"),
               shortcut = shortcut,
               init_shortcut = init_shortcut)

  def cc(self, stream):

    def _ptrToObjRef_ptr(self = self, stream = stream):
      has_abstract = self.interface().abstract()

      for i in self.interface().allInherits():
        if i.abstract(): has_abstract = 1

        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_ptr,
                   inherits_fqname = i.name().fullyQualify())

      if has_abstract:
        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_ptr,
                   inherits_fqname = "CORBA::AbstractBase")

    def _ptrToObjRef_str(self = self, stream = stream):
      has_abstract = self.interface().abstract()

      for i in self.interface().allInherits():
        if i.abstract(): has_abstract = 1

        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_str,
                   inherits_fqname = i.name().fullyQualify())

      if has_abstract:
        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_str,
                   inherits_fqname = "CORBA::AbstractBase")

    # build the inherits list
    
    inherits_str_list = []
    for i in self.interface().inherits():
      objref_name = i.name().prefix("_objref_")

      objref_str = objref_name.unambiguous(self._environment)

      if objref_name.needFlatName(self._environment):
        objref_str = objref_name.flatName()

      this_inherits_str = objref_str + "(ior, id)"
      inherits_str_list.append(this_inherits_str)

    inherits_str = string.join(inherits_str_list, ",\n")
    if inherits_str:
      comma = ","
    else:
      comma = ""

    if config.state['Shortcut']:
      inherits_str  = inherits_str + ","
      init_shortcut = "_shortcut(0)"
    else:
      init_shortcut = ""

    if config.state['Shortcut'] == 2:
      release_shortcut = omniidl_be.cxx.skel.template.\
                         interface_release_refcount_shortcut
    else:
      release_shortcut = ""

    stream.out(omniidl_be.cxx.skel.template.interface_objref,
               name = self.interface().name().fullyQualify(),
               fq_objref_name = self.name().fullyQualify(),
               objref_name = self.name().simple(),
               inherits_str = inherits_str,
               comma = comma,
               _ptrToObjRef_ptr = _ptrToObjRef_ptr,
               _ptrToObjRef_str = _ptrToObjRef_str,
               init_shortcut = init_shortcut,
               release_shortcut = release_shortcut)

    shortcut_mode = config.state['Shortcut']

    if shortcut_mode:
      inherited = output.StringStream()
      for i in self.interface().inherits():
        objref_name = i.name().prefix("_objref_")

        objref_str = objref_name.unambiguous(self._environment)

        if objref_name.needFlatName(self._environment):
          objref_str = objref_name.flatName()

        inherited.out(omniidl_be.cxx.skel.template.interface_shortcut_inh,
                      parent=objref_str)

      if shortcut_mode == 1:
        tmpl = omniidl_be.cxx.skel.template.interface_shortcut
      else:
        tmpl = omniidl_be.cxx.skel.template.interface_shortcut_refcount
        
      stream.out(tmpl,
                 name = self.interface().name().fullyQualify(),
                 basename = self.interface().name().simple(),
                 fq_objref_name = self.name().fullyQualify(),
                 inherited = str(inherited))
      
    for method in self.methods():
      callable = self._callables[method]

      # signature is a text string form of the complete operation signature
      signature = callable.signature()

      # we only need one descriptor for each _signature_ (not operation)
      if _proxy_call_descriptors.has_key(signature):
        call_descriptor = _proxy_call_descriptors[signature]
      else:
        call_descriptor = call.CallDescriptor(signature,callable)
        call_descriptor.out_desc(stream)
        _proxy_call_descriptors[signature] = call_descriptor

      # produce a localcall function
      node_name = self.interface().name()
      localcall_fn = descriptor.local_callback_fn(node_name,
                                                  callable.operation_name(),
                                                  signature)
      call_descriptor.out_localcall(stream,node_name,callable.method_name(),
                                    localcall_fn)

      # produce member function for this operation/attribute.
      body = output.StringStream()

      argnames = method.arg_names()

      if config.state['Shortcut']:
        if method.return_type().kind() != idltype.tk_void:
          callreturn = "return "
          voidreturn = ""
        else:
          callreturn = ""
          voidreturn = " return;"

        objref_class = method.parent_class()
        interface = objref_class.interface()
        implname = interface.name().prefix("_impl_").unambiguous(self._environment)

        if config.state['Shortcut'] == 2:
          tmpl = omniidl_be.cxx.skel.template.\
                 interface_operation_shortcut_refcount
        else:
          tmpl = omniidl_be.cxx.skel.template.\
                 interface_operation_shortcut
        
        body.out(tmpl,
                 impl_type = implname,
                 callreturn = callreturn,
                 voidreturn = voidreturn,
                 args = string.join(argnames, ", "),
                 name = method.name())


      intf_env = self._environment.enter("_objref_" +
                                         self.interface().name().simple())

      call_descriptor.out_objrefcall(body,
                                     callable.operation_name(),
                                     argnames,
                                     localcall_fn,
                                     intf_env)
      method.cc(stream, body)


class _nil_I(Class):
  def __init__(self, I):
    Class.__init__(self, I)
    self._name = self._name.prefix("_nil_")

    for callable in self.interface().callables():
      method = _impl_Method(callable, self)
      self._methods.append(method)
      self._callables[method] = callable

    for i in self.interface().allInherits():
      if not i.local():
        for c in i.callables():
          # Make new callable with ref to this interface instead of
          # inherited interface
          callable = call.Callable(self.interface(),
                                   c.operation_name(),
                                   c.method_name(),
                                   c.returnType(),
                                   c.parameters(),
                                   c.oneway(),
                                   c.raises(),
                                   c.contexts())

          method = _impl_Method(callable, self)
          self._methods.append(method)
          self._callables[method] = callable

  def hh(self, stream):
    pass

  def cc(self, stream):

    def _ptrToObjRef_ptr(self = self, stream = stream):
      has_abstract = 0

      for i in self.interface().allInherits():
        if i.abstract(): has_abstract = 1

        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_ptr,
                   inherits_fqname = i.name().fullyQualify())

      stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_ptr,
                 inherits_fqname = "CORBA::LocalObject")

      if has_abstract:
        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_ptr,
                   inherits_fqname = "CORBA::AbstractBase")

    def _ptrToObjRef_str(self = self, stream = stream):
      has_abstract = 0

      for i in self.interface().allInherits():
        if i.abstract(): has_abstract = 1

        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_str,
                   inherits_fqname = i.name().fullyQualify())

      stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_str,
                 inherits_fqname = "CORBA::LocalObject")

      if has_abstract:
        stream.out(omniidl_be.cxx.skel.template.interface_objref_repoID_str,
                   inherits_fqname = "CORBA::AbstractBase")

    stream.out(omniidl_be.cxx.skel.template.local_interface_objref,
               name = self.interface().name().fullyQualify(),
               sname = self.interface().name().simple(),
               fq_nil_name = self.name().fullyQualify(),
               nil_name = self.name().simple(),
               _ptrToObjRef_ptr = _ptrToObjRef_ptr,
               _ptrToObjRef_str = _ptrToObjRef_str)

    for method in self.methods():
      callable = self._callables[method]

      # signature is a text string form of the complete operation signature
      signature = callable.signature()

      # produce member function for this operation/attribute.
      body = output.StringStream()

      argnames = method.arg_names()

      body.out(omniidl_be.cxx.skel.template.local_interface_nil_operation)

      if not method.return_type().void():
        body.out(omniidl_be.cxx.skel.template.local_interface_nil_dummy_return,
                 method = method.name(),
                 args   = string.join(method.arg_names(),", "))
      
      method.cc(stream, body)
      stream.out("\n")



class _pof_I(Class):
  def __init__(self, I):
    Class.__init__(self, I)
    self._name = self._name.prefix("_pof_")

  def hh(self, stream):
    stream.out(omniidl_be.cxx.header.template.interface_pof,
               name = self.interface().name().simple())

  def cc(self, stream):
    inherits = output.StringStream()
    for i in self.interface().allInherits():
      ancestor = i.name().fullyQualify()
      inherits.out(omniidl_be.cxx.skel.template.interface_pof_repoID, inherited = ancestor)

    node_name = self.interface().name()
    objref_name = node_name.prefix("_objref_")
    pof_name = node_name.prefix("_pof_")
    stream.out(omniidl_be.cxx.skel.template.interface_pof,
               pof_name = pof_name.fullyQualify(),
               objref_fqname = objref_name.fullyQualify(),
               name = node_name.fullyQualify(),
               uname = pof_name.simple(),
               Other_repoIDs = inherits,
               idname = node_name.guard())
    

class _impl_I(Class):
  def __init__(self, I):
    Class.__init__(self, I)
    self._name = self._name.prefix("_impl_")

    for callable in self.interface().callables():
      method = _impl_Method(callable, self)
      self._methods.append(method)
      self._callables[method] = callable

  def hh(self, stream):
    # build the inheritance list
    environment = self._environment
    impl_inherits = []
    inherit_abstract = 0
    
    for i in self.interface().inherits():
      if i.abstract():
        inherit_abstract = 1

      impl_inherited_name = i.name().prefix("_impl_")
      uname = impl_inherited_name.unambiguous(environment)
      impl_inherits.append("public virtual " + uname)

    # if already inheriting, the base class will be present
    # (transitivity of the inherits-from relation)
    if self.interface().inherits() == []:
      impl_inherits   = [ "public virtual omniServant" ]

    methods = []
    for method in self.methods():
        methods.append(method.hh(virtual = 1, pure = 1))

    if self.interface().abstract():
      abstract = omniidl_be.cxx.header.template.interface_impl_abstract
    elif inherit_abstract:
      abstract = omniidl_be.cxx.header.template.interface_impl_not_abstract
    else:
      abstract = ""
        
    stream.out(omniidl_be.cxx.header.template.interface_impl,
               name = self.interface().name().simple(),
               inherits = string.join(impl_inherits, ",\n"),
               operations = string.join(methods, "\n"),
               abstract = abstract)

  def cc(self, stream):

    # Function to write the _impl_I::dispatch method
    def dispatch(self = self, stream = stream):
      # first check if method is from this interface
      dispatched = []
      for method in self.methods():
        callable = self._callables[method]
        operation_name = callable.operation_name()
        if operation_name not in dispatched:
          signature = callable.signature()
          call_descriptor = _proxy_call_descriptors[signature]
          localcall_fn = descriptor.local_callback_fn(self.interface().name(),
                                                      operation_name,signature)
          call_descriptor.out_implcall(stream,operation_name,localcall_fn)
          dispatched.append(operation_name)

      # next call dispatch methods of superclasses
      for i in self.interface().inherits():
        inherited_name = i.name().prefix("_impl_")
        impl_inherits = inherited_name.simple()
        # The MSVC workaround might be needed here again
        if inherited_name.needFlatName(self._environment):
          impl_inherits = inherited_name.flatName()
        stream.out(omniidl_be.cxx.skel.template.interface_impl_inherit_dispatch,
                   impl_inherited_name = impl_inherits)

    # For each of the inherited interfaces, check their repoId strings
    def _ptrToInterface_ptr(self = self, stream = stream):
      for i in self.interface().allInherits():
        inherited_name = i.name()
        impl_inherited_name = inherited_name.prefix("_impl_")

        # HERE: using the fully scoped name may fail on old MSVC
        # versions, but it is required by newer MSVC versions.
        # Marvellous.
        inherited_str      = inherited_name.fullyQualify()
        impl_inherited_str = impl_inherited_name.fullyQualify()

        stream.out(omniidl_be.cxx.skel.template.interface_impl_repoID_ptr,
                   inherited_name = inherited_str,
                   impl_inherited_name = impl_inherited_str)

    def _ptrToInterface_str(self = self, stream = stream):
      for i in self.interface().allInherits():
        inherited_name = i.name()
        impl_inherited_name = inherited_name.prefix("_impl_")

        inherited_str      = inherited_name.fullyQualify()
        impl_inherited_str = impl_inherited_name.fullyQualify()

        stream.out(omniidl_be.cxx.skel.template.interface_impl_repoID_str,
                   inherited_name = inherited_str,
                   impl_inherited_name = impl_inherited_str)

    node_name = self.interface().name()
    impl_name = node_name.prefix("_impl_")
    if self.methods():
      getopname = "const char* op = _handle.operation_name();"
    else:
      getopname = ""

    stream.out(omniidl_be.cxx.skel.template.interface_impl,
               impl_fqname = impl_name.fullyQualify(),
               uname = node_name.simple(),
               getopname = getopname,
               dispatch = dispatch,
               impl_name = impl_name.unambiguous(self._environment),
               _ptrToInterface_ptr = _ptrToInterface_ptr,
               _ptrToInterface_str = _ptrToInterface_str,
               name = node_name.fullyQualify())

    if not self.interface().abstract():
      # Are we derived from an abstract interface?
      inherit_abstract = 0
      for i in self.interface().inherits():
        if i.abstract():
          inherit_abstract = 1
          break
      if inherit_abstract:
        stream.out(omniidl_be.cxx.skel.template.interface_impl_not_abstract,
                   impl_fqname = impl_name.fullyQualify())
          

class _sk_I(Class):
  def __init__(self, I):
    Class.__init__(self, I)

  def hh(self, stream):
    # build the inheritance list
    environment = self._environment
    sk_inherits = []
    for i in self.interface().inherits():
      sk_inherited_name = i.name().prefix("_sk_")
      uname = sk_inherited_name.unambiguous(environment)
      sk_inherits.append("public virtual " + uname)

    # if already inheriting, the base class will be present
    # (transitivity of the inherits-from relation)
    if self.interface().inherits() == []:
      sk_inherits   = [ "public virtual omniOrbBoaServant" ]

    stream.out(omniidl_be.cxx.header.template.interface_sk,
               name = self.interface().name().simple(),
               inherits = string.join(sk_inherits, ",\n"))






