# -*- coding: utf-8 -*-
# From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486
# Licensed under PSF: http://python.org/license
# modification by Lionel Martin lionel@fluendo.com

"""
True immutable symbolic enumeration with qualified value access.

"""

def Enum(*names):
    ##assert names, "Empty enums are not supported"
    # ^^ Don't like empty enums? Uncomment!

    class EnumClass(object):
        __slots__ = names
        def __iter__(self):
            return iter(constants)
        def __len__(self):
            return len(constants)
        def __getitem__(self, i):
            return constants[i]
        def __repr__(self):
            return 'Enum' + str(names)
        def __str__(self):
            return 'enum ' + str(constants)
        def index(self, constant):
            return list(constants).index(constant)

    class EnumValue(object):
        __slots__ = ('__value', '__number')
        def __init__(self, value, number):
            self.__value = value
            self.__number = number

        Value = property(lambda self: self.__value)
        Number = property(lambda self: self.__number)
        EnumType = property(lambda self: EnumType)

        def __hash__(self):
            return hash(self.__value)
        def __cmp__(self, other):
            # C fans might want to remove the following assertion
            # to make all enums comparable by ordinal value {;))
            # I'm a C fan! assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
            if isinstance(self, EnumValue):
                a = self.__value
            else:
                a = None
                
            if isinstance(other, EnumValue):
                b = other.__value
            else:
                b = None

            return cmp(a, b)
        
        def __invert__(self):
            return constants[maximum - self.__value]
        def __nonzero__(self):
            return self.__value is not None
        def __repr__(self):
            return str(names[self.__value])
        def __int__(self):
            return self.__number

    maximum = len(names) - 1
    constants = [None] * len(names)
    j = 0
    for i, each in enumerate(names):
        val = EnumValue(i, j)
        setattr(EnumClass, each, val)
        constants[i] = val
        j = j + 1
    constants = tuple(constants)
    EnumType = EnumClass()
    return EnumType


if __name__ == '__main__':
    print '\n*** Enum Demo ***'
    print '--- Days of week ---'
    Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
    print Days
    print Days.Mo
    print Days.Fr
    print Days.Mo < Days.Fr
    print list(Days)
    for each in Days:
        print 'Day:', each
    print '--- Yes/No ---'
    Confirmation = Enum('No', 'Yes')
    answer = Confirmation.No
    print 'Your answer is not', ~answer
    print None == Days.Mo
    print Days.Mo == None
