Builds a resource name class by mixing a named tuple and ResourceName.

    It also registers the class.

    The field names are changed to lower case and the spaces replaced
    by underscores ('_').

    :param interface_type: the interface type
    :type: interface_type: str
    :param resource_parts: each of the parts of the resource name indicating
                           name and default value.
                           Use None for mandatory fields.
    :type resource_parts: tuple[(str, str)]
    :param resource_class: the resource class
    :type resource_class: str
    :param is_rc_optional: indicates if the resource class part is optional
    :type is_rc_optional: boolean.

def build_rn_class(interface_type, resource_parts, resource_class,
                   is_rc_optional=True):
    """Builds a resource name class by mixing a named tuple and ResourceName.

    It also registers the class.

    The field names are changed to lower case and the spaces replaced
    by underscores ('_').

    :param interface_type: the interface type
    :type: interface_type: str
    :param resource_parts: each of the parts of the resource name indicating
                           name and default value.
                           Use None for mandatory fields.
    :type resource_parts: tuple[(str, str)]
    :param resource_class: the resource class
    :type resource_class: str
    :param is_rc_optional: indicates if the resource class part is optional
    :type is_rc_optional: boolean.
    """

    interface_type = interface_type.upper()
    resource_class = resource_class.upper()

    syntax = interface_type
    fmt = interface_type
    fields = []

    # Contains the resource parts but using python friendly names
    # (all lower case and replacing spaces by underscores)
    p_resource_parts = []

    kwdoc = []

    # Assemble the syntax and format string based on the resource parts
    for ndx, (name, default_value) in enumerate(resource_parts):
        pname = name.lower().replace(' ', '_')
        fields.append(pname)
        p_resource_parts.append((pname, default_value))

        sep = '::' if ndx else ''

        fmt += sep + '{0.%s}' % pname

        if default_value is None:
            syntax += sep + name
        else:
            syntax += '[' + sep + name + ']'

        kwdoc.append('- %s (%s)' % (pname, 'required' if default_value is None
                                    else default_value))

    fmt += '::' + resource_class

    if not is_rc_optional:
        syntax += '::' + resource_class
    else:
        syntax += '[' + '::' + resource_class + ']'

    class _C(namedtuple('Internal', ' '.join(fields)), ResourceName):
        """%s %s"

        Can be created with the following keyword only arguments:
            %s

        Format :
            %s
        """ % (resource_class, interface_type, '    \n'.join(kwdoc), syntax)

        def __new__(cls, **kwargs):
            new_kwargs = dict(p_resource_parts, **kwargs)

            for key, value in new_kwargs.items():
                if value is None:
                    raise ValueError(key + ' is a required parameter')

            return super(_C, cls).__new__(cls, **new_kwargs)

        @classmethod
        def from_parts(cls, *parts):

            if len(parts) < sum(1 for _, v in p_resource_parts
                                if v is not None):
                raise ValueError('not enough parts')
            elif len(parts) > len(p_resource_parts):
                raise ValueError('too many parts')

            (k, default), rp = p_resource_parts[0], p_resource_parts[1:]

            # The first part (just after the interface_type) is the only
            # optional part which can be and empty and therefore the
            # default value should be used.
            p, pending = parts[0], parts[1:]
            kwargs = {k: default if p == '' else p}

            # The rest of the parts are consumed when mandatory elements are required.
            while len(pending) < len(rp):
                (k, default), rp = rp[0], rp[1:]
                if default is None:
                    if not parts:
                        raise ValueError(k + ' part is mandatory')
                    p, pending = pending[0], pending[1:]
                    if not p:
                        raise ValueError(k + ' part is mandatory')
                    kwargs[k] = p
                else:
                    kwargs[k] = default

            # When the length of the pending provided and resource parts
            # are equal, we just consume everything.
            kwargs.update((k, p) for (k, v), p in zip(rp, pending))

            return cls(**kwargs)

    _C.interface_type = interface_type
    _C.resource_class = resource_class
    _C.is_rc_optional = is_rc_optional
    _C._canonical_fmt = fmt
    _C._visa_syntax = syntax

    _C.__name__ = str(interface_type + resource_class.title())

    return register_subclass(_C)