# todo make sure what they mean by desc undefined? None or empty? Answer: None :) it can never be empty but None is sometimes returned.

# I am implementing everything as dicts to speed up property creation

# Warning: value, get, set props of dest are PyJs types. Rest is Py!

def is_data_descriptor(desc):
    return desc and ('value' in desc or 'writable' in desc)


def is_accessor_descriptor(desc):
    return desc and ('get' in desc or 'set' in desc)


def is_generic_descriptor(desc): # generic means not the data and not the setter - therefore it must be one that changes only enum and conf
    return desc and not (is_data_descriptor(desc) or is_accessor_descriptor(desc))


def from_property_descriptor(desc, space):
    if not desc:
        return {}
    obj = space.NewObject()
    if is_data_descriptor(desc):
        obj.define_own_property('value', {'value': desc['value'],
                                          'writable': True,
                                          'enumerable': True,
                                          'configurable': True}, False)
        obj.define_own_property('writable', {'value': desc['writable'],
                                             'writable': True,
                                             'enumerable': True,
                                             'configurable': True}, False)
    else:
        obj.define_own_property('get', {'value': desc['get'],
                                        'writable': True,
                                        'enumerable': True,
                                        'configurable': True}, False)
        obj.define_own_property('set', {'value': desc['set'],
                                        'writable': True,
                                        'enumerable': True,
                                        'configurable': True}, False)
    obj.define_own_property('writable', {'value': desc['writable'],
                                         'writable': True,
                                         'enumerable': True,
                                         'configurable': True}, False)
    obj.define_own_property('enumerable', {'value': desc['enumerable'],
                                           'writable': True,
                                           'enumerable': True,
                                           'configurable': True}, False)
    return obj


def to_property_descriptor(obj):
    if obj._type()!='Object':
        raise TypeError()
    desc = {}
    for e in ('enumerable', 'configurable', 'writable'):
        if obj.has_property(e):
            desc[e] = obj.get(e).to_boolean().value
    if obj.has_property('value'):
        desc['value'] = obj.get('value')
    for e in ('get', 'set'):
        if obj.has_property(e):
            cand = obj.get(e)
            if not (cand.is_callable() or cand.is_undefined()):
                raise TypeError()
    if ('get' in desc or 'set' in desc) and ('value' in desc or 'writable' in desc):
        raise TypeError()

