import Permission
from main import _

import types


class Interface(object):

    """Abstract base class for interfaces."""


    def __get_members(impl):

        return [(name, type(member), member) for name, member
                in impl.__dict__.items()]

    __get_members = classmethod(__get_members)



    def get_properties(iface):

        """Returns a dictionary of the properties of the given implementation."""

        return dict([(n, p) for n, t, p in iface.__get_members()
                      if (t == property)])

    get_properties = classmethod(get_properties)



    def get_methods(iface):

        """Returns a list of the methods of the given implementation."""

        return [(n, "") for n, t, m in iface.__get_members()
                if (t == types.FunctionType)] # or MethodType ?

    get_methods = classmethod(get_methods)



    def get_permissions(iface):

        """Returns a list of the permissions of the properties."""

        props = [(k, v) for k, v in iface.get_properties()
                 if (type(k) == property and k not in Interface.__dict__)]

        for nil, p  in props:
            assert isinstance(p, Permission._Permission)

        return props

    get_permissions = classmethod(get_permissions)



    def get_id(iface):

        """classmethod for returning the unique identifier of the given interface"""

        # the algorithm is simple:
        # build a string containing the class name and a sorted list of the
        # properties and return the MD5 fingerprint of it
        import md5
        import utils

        name = iface.__name__
        items1 = iface.get_permissions()
        items1.sort() # we need python2.4
        items2 = iface.get_methods()
        items2.sort()
        tmp = ["%s:%s" % (k, v) for k, v in items1 + items2]

        tmp = "%s:%s" % (name, ",".join(tmp))

        ash = md5.new(tmp).hexdigest()
        # encode it in base36 to get shorter ID
        ash = utils.radix( int(ash, 16), 36 )
        # ID have to be 25 char long
        ash = '0' * (25 - len(ash)) + ash

        assert (len(ash) == 25)

        return ("%s:%s" % (name, ash))

    get_id = classmethod(get_id)



    def get_interfaces(impl):

        """Returns the interfaces implemented by the given class"""
    
        return [ c for c in impl.mro()
                 if issubclass(c, Interface) and not c in (Interface, impl) ]

    get_interfaces = staticmethod(get_interfaces)



    #

    #
    def assert_interfaces(impl):

        """Static method for asserting that the interfaces are implemented properly
        in the given class. Throws exceptions otherwise."""

        # find the implemented properties
        impl_props = dict(impl.get_properties())

        # find the implemented methods
        impl_meths = dict(impl.get_methods())

        # check all interfaces
        for iface in Interface.get_interfaces(impl):

            # check properties
            required = iface.get_permissions()
            for name, perm in required:
                if name not in impl_props:
                    raise NotImplementedError("Missing implementation for "
                                              "%s.%s" % (iface.__name__, name))

                # check if the property's mode is according to the interfaces
                if (perm != Permission.Permission(implemented[name])):
                    raise NotImplementedError("Broken implementation for "
                                      "%s.%s" % (iface.__name__, name))
            #end for

            # check methods
            required = iface.get_methods()
            for name, meth in required:
                if name not in impl_meths:
                    raise NotImplementedError("Missing implementation for "
                                              "%s.%s" % (iface.__name__, name))
            #end for

        #end for

    assert_interfaces = staticmethod(assert_interfaces)



    def text_describe(impl):

        """Returns a description of the interfaces of the given class."""

        textlist = []
        interfaces = Interface.get_interfaces(impl)

        for i in interfaces:

            out = ""

            ident = i.get_id()

            out += ident + '\n\n'

            for key in dir(i):

                value = impl.__dict__.get(key)
                if (not value): continue

                if (isinstance(value, property)):
                    out += "  "
                    out += key.ljust(25)
                    perm = str(Permission.Permission(value)).ljust(4)
                    out += perm
                    out += "%s \n" % (value.__doc__ or _("no description"), )

            out += "\n"

            textlist.append(out)

        return ''.join(textlist)

    text_describe = staticmethod(text_describe)



    def gui_describe(impl):
    
        guilist = []
        interfaces = Interface.get_interfaces(impl)

        for i in interfaces:

            items = []
            
            for key in dir(i):

                value = impl.__dict__.get(key)
                if (not value): continue

                if (isinstance(value, property)):
                    items.append((key, str(Permission.Permission(value)),
                                    value.__doc__ or _("no description")))

            guilist.append( (i.get_id(), items) )

        return guilist


    gui_describe = staticmethod(gui_describe)

