text: from new import instance
  import FFIConstants
  
  WrapperClassMap = {}
  
  DowncastMap = {}
  
  # For testing, you can turn verbose and debug on
  # FFIConstants.notify.setInfo(1)
  # FFIConstants.notify.setDebug(1)
  
  # Uncomment the notify statements if you need to debug,
  # otherwise leave them commented out to prevent runtime
  # overhead of calling them
  
  
  
  # Register a python class in the type map if it is a typed object
  # The type map is used for upcasting and downcasting through
  # the panda inheritance chain
  def registerInTypeMap(pythonClass):
      from pandac import TypedObject
      if issubclass(pythonClass, TypedObject.TypedObject):
          typeIndex = pythonClass.getClassType().getIndex()
          WrapperClassMap[typeIndex] = pythonClass
  
  
  def funcToMethod(func, clas, method_name=None):
      """Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method.
      The new method is accessible to any instance immediately."""
      func.im_class=clas
      func.im_func=func
      func.im_self=None
      if not method_name:
          clas.__dict__[method_name]=func
      else:
          clas.__dict__[func.__name__]=func
  
  
  def FFIInstance(classdef, this = 0, userManagesMemory = 0):
      answer = instance(classdef)
      answer.this = this
      answer.userManagesMemory = userManagesMemory
      return answer
  
  class FFIExternalObject:
      def __init__(self, *_args):
          # By default, we do not manage our own memory
          self.userManagesMemory = 0
          # Start with a null this pointer
          self.this = 0
  
      def destructor(self):
          # Base destructor in case you do not define one
          pass
  
      def getLineage(self, thisClass, targetBaseClass):
          # Recursively determine the path in the heirarchy tree from thisClass
          # to the targetBaseClass
          return self.getLineageInternal(thisClass, targetBaseClass, [thisClass])
  
      def getLineageInternal(self, thisClass, targetBaseClass, chain):
          # Recursively determine the path in the heirarchy tree from thisClass
          # to the targetBaseClass
          #FFIConstants.notify.debug('getLineageInternal: checking %s to %s'
          #                          % (thisClass.__name__, targetBaseClass.__name__))
          if (targetBaseClass in thisClass.__bases__):
              # Found a link
              return chain + [targetBaseClass]
          elif (len(thisClass.__bases__) == 0):
              # No possible links
              return 0
          else:
              # recurse
              for base in thisClass.__bases__:
                  res = self.getLineageInternal(base, targetBaseClass, chain+[base])
                  if res:
                      # FFIConstants.notify.debug('getLineageInternal: found path: ' + repr(res))
                      return res
              # Not found anywhere
              return 0
  
      def getDowncastFunctions(self, thisClass, baseClass):
          #FFIConstants.notify.debug(
          #    'getDowncastFunctions: Looking for downcast function from %s to %s'
          #    % (baseClass.__name__, thisClass.__name__))
          lineage = self.getLineage(thisClass, baseClass)
          # Start with an empty list of downcast functions
          downcastFunctionList = []
  
          # If it could not find the baseClass anywhere in the lineage,
          # return empty
          if not lineage:
              return []
  
          # Walk along the lineage looking for downcast functions from
          # class to class+1.  Start at the top and work downwards.
          top = len(lineage) - 1
          for i in range(top):
              toClass = lineage[top - i - 1]
              fromClass = lineage[top - i]
              downcastFuncName = ('downcastTo' + toClass.__name__
                                  + 'From' + fromClass.__name__)
              # Look over this classes global modules dictionaries
              # for the downcast function name
              for globmod in toClass.__CModuleDowncasts__:
                  func = globmod.__dict__.get(downcastFuncName)
                  if func:
                      #FFIConstants.notify.debug(
                      #    'getDowncastFunctions: Found downcast function %s in %s'
                      #    % (downcastFuncName, globmod.__name__))
                      downcastFunctionList.append(func)
          return downcastFunctionList
  
      def lookUpNewType(self, typeHandle, rootType):
          # We tried to downcast to an unknown type.  Try to figure out
          # the lowest type we *do* know, so we can downcast to that
          # type instead.
          if typeHandle.getNumParentClasses() == 0:
              # This type has no parents!  That shouldn't happen.
              FFIConstants.notify.warning("Unknown class type: %s has no parents!" % (typeHandle.getName()))
              return None
  
          parentType = typeHandle.getParentTowards(rootType, self)
          parentIndex = parentType.getIndex()
          parentWrapperClass = WrapperClassMap.get(parentIndex)
          if parentWrapperClass == None:
              parentWrapperClass = self.lookUpNewType(parentType, rootType)
  
          if parentWrapperClass != None:
              # If the parent class is known, then record that this
              # class is a derivation of that parent class.
              WrapperClassMap[typeHandle.getIndex()] = parentWrapperClass
  
          return parentWrapperClass
  
      def setPointer(self):
          # See what type it really is and downcast to that type (if necessary)
          # Look up the TypeHandle in the dict. get() returns None if it is not there
          index = self.getTypeIndex()
          exactWrapperClass = WrapperClassMap.get(index)
          if exactWrapperClass == None:
              # This is an unknown class type.  Perhaps it derives from
              # a class type we know.
              exactWrapperClass = self.lookUpNewType(self.getType(), self.getClassType())
  
          # We do not need to downcast if we already have the same class
          if (exactWrapperClass and (exactWrapperClass != self.__class__)):
              # Create a new wrapper class instance
              #exactObject = exactWrapperClass(None)
              exactObject = FFIInstance(exactWrapperClass)
              # Get the downcast pointer that has had all the downcast
              # funcs called
              downcastObject = self.downcast(exactWrapperClass)
              exactObject.this = downcastObject.this
              exactObject.userManagesMemory = downcastObject.userManagesMemory
              # Make sure the original downcast object does not get
              # garbage collected so that the exactObject will not get
              # gc'd thereby transferring ownership of the object to
              # this new exactObject
              downcastObject.userManagesMemory = 0
              return exactObject
          else:
              return self
  
      def downcast(self, toClass):
          fromClass = self.__class__
          #FFIConstants.notify.debug('downcast: downcasting from %s to %s' % \
          #    (fromClass.__name__, toClass.__name__))
  
          # Check the cache to see if we have looked this up before
          downcastChain = DowncastMap.get((fromClass, toClass))
          if downcastChain == None:
              downcastChain = self.getDowncastFunctions(toClass, fromClass)
              #FFIConstants.notify.debug('downcast: computed downcast chain: ' + repr(downcastChain))
              # Store it for next time
              DowncastMap[(fromClass, toClass)] = downcastChain
          newObject = self
          for downcastFunc in downcastChain:
              #FFIConstants.notify.debug('downcast: downcasting %s using %s' % \
              #                         (newObject.__class__.__name__, downcastFunc))
              newObject = downcastFunc(newObject)
          return newObject
  
      def compareTo(self, other):
          # By default, we compare the C++ pointers
          # Some classes will override the compareTo operator with their own
          # logic in C++ (like vectors and matrices for instance)
          try:
              if self.this < other.this:
                  return -1
              if self.this > other.this:
                  return 1
              else:
                  return 0
          except:
              return 1
  
      def __cmp__(self, other):
          # Only use the C++ compareTo if they are the same class
          if isinstance(other, self.__class__):
              return self.compareTo(other)
          # Otherwise, they must not be the same
          # Just do a basic python id compare
          else:
              return cmp(id(self), id(other))
  
      def __repr__(self):
          # Lots of Panda classes have an output function defined that takes an Ostream
          # We create a LineStream for the output function to write to, then we extract
          # the string out of it and return it as our str
          try:
              from pandac import LineStream
              lineStream = LineStream.LineStream()
              self.output(lineStream)
              baseRepr = lineStream.getLine()
          except AssertionError, e:
              raise AssertionError, e
          except:
              baseRepr = ('[' + self.__class__.__name__ + ' at: ' + repr(self.this) + ']')
          # In any case, return the baseRepr
          return baseRepr
  
      def __str__(self):
          # This is a more complete version of printing which shows the object type
          # and pointer, plus the output from write() or output() whichever is defined
          # Print this info for all objects
          baseRepr = ('[' + self.__class__.__name__ + ' at: ' + repr(self.this) + ']')
          # Lots of Panda classes have an write or output function defined that takes an Ostream
          # We create a LineStream for the write or output function to write to, then we extract
          # the string out of it and return it as our repr
          from pandac import LineStream
          lineStream = LineStream.LineStream()
          try:
              # First try the write function, that is the better one
              self.write(lineStream)
              while lineStream.isTextAvailable():
                  baseRepr = baseRepr + '\n' + lineStream.getLine()
          except AssertionError, e:
              raise AssertionError, e
          except:
              try:
                  # Sometimes write insists on a seconds parameter.
                  self.write(lineStream, 0)
                  while lineStream.isTextAvailable():
                      baseRepr = baseRepr + '\n' + lineStream.getLine()
              except AssertionError, e:
                  raise AssertionError, e
              except:
                  try:
                      # Ok, no write function, lets try output then
                      self.output(lineStream)
                      while lineStream.isTextAvailable():
                          baseRepr = baseRepr + '\n' + lineStream.getLine()
                  except AssertionError, e:
                      raise AssertionError, e
                  except:
                      pass
          # In any case, return the baseRepr
          return baseRepr
  
      def __hash__(self):
          return self.this
  
  
  
  
  
  