##
## clirc -- An IRC client in Python.
## reloadable.py - Instances whose __class__ can be changed.
##
## Copyleft 1997-2000 Teemu Kalvas <chery@s2.org>
##

import sys

modules = {}
classes = {}

def register_for_reload(klass):
    classes[(klass.__module__, klass.__name__)] = klass

def register_module(module_name):
    modules[module_name] = ()

def reload_module(module_name):
    if not done_modules.has_key(module_name) and module_name <> 'reloadable':
        reload(sys.modules[module_name])
        done_modules[module_name] = ()

def reload_class(klass):
    if not done_classes.has_key((klass.__module__, klass.__name__)) \
       and klass.__name__ <> 'Reloadable' and issubclass(klass, Reloadable):
        ## The order to reload the class definitions in is bases first, so
        ## we first reload the base classes and only then the module
        ## containing the definition for the class currently being processed.
        for base in klass.__bases__:
            reload_class(base)
        reload_module(klass.__module__)
        for name in klass.__dict__.keys():
            if name <> '__module__':
                delattr(klass, name)
        klass.__bases__ = (ReloadInProgress,)
        classes[(klass.__module__, klass.__name__)] = sys.modules[
            klass.__module__].__dict__[klass.__name__]
        done_classes[(klass.__module__, klass.__name__)] = ()

def do_reloads():
    global done_classes, done_modules
    done_classes = {}
    done_modules = {}
    for module_name in modules.keys():
        reload_module(module_name)
    for klass in classes.values():
        reload_class(klass)
    reload(sys.modules['config'])

class ReloadInProgress:
    def __getattr__(self, name):
        self.__class__ = classes[(self.__module__, self.__class__.__name__)]
        self.post_reload()
        return getattr(self, name)

class Reloadable:
    def post_reload(self):
	pass

    def ensure_defaults(self, defaults):
	for name, default in defaults:
	    self.ensure_value(name, default)

    def ensure_value(self, name, default):
	if not hasattr(self, name):
	    if callable(default):
		setattr(self, name, default())
	    else:
		setattr(self, name, default)

## End. ##
