from gk_property_restrictions import *
from gk_property_processors import *

class gds_property_descriptor(object):
    __allowed_keyword_arguments__ = ["required", "default"]
    def __init__(self, internal_member_name, **kwargs):
        self.__name__ = internal_member_name
        
        for (k,v) in kwargs.items():
            if k in self.__allowed_keyword_arguments__:
                object.__setattr__(self, k, v)
            else:
                raise AttributeError("Argument %s is not valid for definition of %s" % (k, self))
                    
    def __get__(self, obj, type = None):
        if hasattr(obj, self.__name__):
            return object.__getattribute__(obj, self.__name__)
        elif hasattr(self, "default"):
            return self.default
        else:
            raise AttributeError("Attribute %s of %s is not set, and no default value is specified" % (self.__name__, obj))
            
        
    def __set__(self, obj, value):
        # override this method to do type checking or something else
        object.__setattr__(obj, self.__name__, value)

    
class restricted_property_descriptor(gds_property_descriptor):
    __allowed_keyword_arguments__ = gds_property_descriptor.__allowed_keyword_arguments__ + ["restriction", "preprocess"]
    
    def __init__(self, internal_member_name, **kwargs):
        self.restriction = restrict_nothing()
        self.preprocess = property_processor()
        gds_property_descriptor.__init__(self, internal_member_name, **kwargs)

    def __get__(self, obj, type = None):
        if hasattr(obj, self.__name__):
            return object.__getattribute__(obj, self.__name__)
        elif hasattr(self, "default"):
            return self.preprocess(self.default, obj)
        else:
            raise AttributeError("Attribute %s of %s is not set, and no default value is specified" % (self.__name__, obj))
            
  
    def __set__(self, obj, value):
        new_value = self.preprocess(value, obj)
        if self.restriction(new_value, obj):
            gds_property_descriptor.__set__(self, obj, new_value)
        else:
            raise RestrictionError("%s does not match restriction %s in property %s" %(value, self.restriction, self.__name__))

######################################################
# predefined
######################################################
def int_property(internal_member_name, restriction = None,**kwargs):
    R = RESTRICT_INT & restriction
    return restricted_property_descriptor(internal_member_name, restriction = R)
def float_property(internal_member_name, restriction = None,**kwargs):
    R = RESTRICT_FLOAT & restriction
    return restricted_property_descriptor(internal_member_name, restriction = R)
def number_property(internal_member_name, restriction = None,**kwargs):
    R = RESTRICT_NUMBER & restriction
    return restricted_property_descriptor(internal_member_name, restriction = R)
def string_property(internal_member_name, restriction = None,**kwargs):
    R = RESTRICT_STRING & restriction
    return restricted_property_descriptor(internal_member_name, restriction = R)
def bool_property(internal_member_name, restriction = None,**kwargs):
    R = RESTRICT_BOOL & restriction
    return restricted_property_descriptor(internal_member_name, restriction = R)

angle_property = number_property # to be specified later
normalized_angle_property = number_property # to be specified later