"""
Dekorator klasy z prywatnymi i publicznymi deklaracjami atrybutów.
Kontroluje dostęp z zewnątrz do atrybutów zapisanych w instancji lub odziedziczonych
przez nią w dowolny sposób z innych klas.

Dekorator Private deklaruje nazwy atrybutów, których nie można odczytywać ani
przypisywać im wartości poza udekorowaną klasą. Dekorator Public deklaruje wszystkie
nazwy, na których można wykonywać powyższe operacje.

Uwaga: w wersji 3.x przechwytywane są wyłącznie te wbudowane operacje, które są
zakodowane w klasie BuiltinMixins (jej kod można rozszerzyć). Dlatego dekorator Public
zakodowany w takiej postaci jak tutaj może być mniej przydatny przy przeciążaniu
operatorów niż dekorator Private.
"""

from access_builtins import BuiltinsMixin    # Częściowa obsługa!

traceMe = False
def trace(*args):
    if traceMe: print('[' + ' '.join(map(str, args)) + ']')

def accessControl(failIf):
    def onDecorator(aClass):
        if not __debug__:
            return aClass
        else:
            class onInstance(BuiltinsMixin):
                def __init__(self, *args, **kargs):
                    self.__wrapped = aClass(*args, **kargs)

                def __getattr__(self, attr):
                    trace('pobranie:', attr)
                    if failIf(attr):
                        raise TypeError(''pobranie atrybutu prywatnego, ' + attr)
                    else:
                        return getattr(self.__wrapped, attr)

                def __setattr__(self, attr, value):
                    trace('ustawienie:', attr, value)
                    if attr == '_onInstance__wrapped':
                        self.__dict__[attr] = value
                    elif failIf(attr):
                        raise TypeError('modyfikacja atrybutu prywatnegoe, ' + attr)
                    else:
                        setattr(self.__wrapped, attr, value)
            return onInstance
    return onDecorator

def Private(*attributes):
    return accessControl(failIf=(lambda attr: attr in attributes))

def Public(*attributes):
    return accessControl(failIf=(lambda attr: attr not in attributes))

