########################################
# The contents of this file are subject to the MLX PUBLIC LICENSE version
# 1.0 (the "License"); you may not use this file except in
# compliance with the License.
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
# the License for the specific language governing rights and limitations
# under the License.
# 
# The Original Source Code is "compClust", released 2003 September 03.
# 
# The Original Source Code was developed by the California Institute of
# Technology (Caltech).  Portions created by Caltech are Copyright (C)
# 2002-2003 California Institute of Technology. All Rights Reserved.
########################################
#
#        Author: Diane Trout
# Last Modified: $Date: 2004/01/16 23:25:29 $
#

"""Provides an interface to enable a class to support mixins.

By inheriting from the Mixin class, one can dynamically add
an additional base class to the list of base classes.

In this implementation of the mixin idea the member functions of the mixin
class are dynamicallly added to the class instance. This keeps the
initial class object uncontaminated by these mixin classes and thus
allows different mixins to be added.
"""

import types
from Functor import Functor

class Mixin:
  def addMixin(self, mixin):
    """Add any items in the mixin class to the current instance
    """
    # save what class (and it's functions) that were added to this instance
    self.__dict__.setdefault('__mixin__', {})[mixin] = []
    # go ahead and copy over any functions
    for mixItem in mixin.__dict__.keys():
      if not(self.__dict__.has_key(mixItem)):
        self.__mixin__[mixin].append(mixItem)
        if type(mixin.__dict__[mixItem]) == types.FunctionType:
          self.__dict__[mixItem] = Functor(mixin.__dict__[mixItem], self)
        else:
          self.__dict__[mixItem] = mixin.__dict__[mixItem]
    return self

  def removeMixin(self, mixin):
    """Remove mixin functions from instance.
    """
    # don't remove interfaces that weren't added
    if not self.__dict__.get('__mixin__', {}).has_key(mixin):
      raise ValueError("Mixin was not added to this instance")

    # remove items that were added to this instace
    for mixItem in self.__mixin__[mixin]:
      del self.__dict__[mixItem]

    # remove the mixin from our list of mixins
    del self.__mixin__[mixin]
    return self

  def copyMixins(self, c):
    """Copy mixins attached to a different class to the current instance.
    """
    if not isinstance(c, Mixin):
      raise ValueError("source class must implement mixin interface")
    
    for mixin in c.listMixins():
      self.addMixin(mixin)
    return self
  
  def listMixins(self):
    """List mixin classes that have been attached to this instance
    """
    return self.__dict__.get('__mixin__', {}).keys()

  def isMixinInstance(self, mixin_class):
    """Is this class an instance of a particular mixin?
    """
    return self.__dict__.get('__mixin__', {}).has_key(mixin_class)
