from types import FunctionType, InstanceType, ClassType
import threading

def _get_method_names (obj):
    if type(obj) == InstanceType:
        return _get_method_names(obj.__class__)
    
    elif type(obj) == ClassType:
        result = []
        for name, func in obj.__dict__.items():
            if type(func) == FunctionType:
                result.append((name, func))

        for base in obj.__bases__:
            result.extend(_get_method_names(base))

        return result
    else:
        result = []
        for name in dir(obj):
            func = getattr(obj, name)
            if type(func) == FunctionType:
                result.append((name, func))
        return result

class _SynchronizedMethod:
    def __init__ (self, method, obj, lock, cleanup_handler):
        self.__method = method
        self.__obj = obj
        self.__lock = lock
        self.__cleanup_handler = cleanup_handler

    def __call__ (self, *args, **kwargs):
        if not self.__lock.acquire(0):
            self.__cleanup_handler()
        self.__lock.acquire()
        try:
            return self.__method(self.__obj, *args, **kwargs)
        finally:
            self.__lock.release()


class SynchronizedObject:
    def __init__ (self, obj, cleanup_handler=None, ignore=[], lock=None):
        self.__methods = {}
        self.__obj = obj
        lock = lock and lock or threading.RLock()
        for name, method in _get_method_names(obj):
            if not name in ignore:
                self.__methods[name] = _SynchronizedMethod(method, obj, lock, cleanup_handler)

    def __getattr__ (self, name):
        try:
            return self.__methods[name]
        except KeyError:
            return getattr(self.__obj, name)
