#! /usr/bin/env python
from __future__ import print_function
import inspect
import os
from abjad.tools import documentationtools
from abjad.tools import lilypondfiletools
from abjad.tools import systemtools
from abjad.tools.abctools import AbjadObject
from abjad.tools.documentationtools import InheritanceGraph


ignored_classes = (
    lilypondfiletools.Block,
    )

def shorten_class_name(abjad_class):
    parts = abjad_class.__module__.split('.')[-2:]
    return '{}.{}'.format(parts[0], parts[1])


def find_inconsistencies():
    tools_path = os.path.abspath('.')
    abjad_classes = documentationtools.yield_all_classes(tools_path)
    abjad_classes = sorted(abjad_classes, key=lambda x: x.__module__)
    graph = InheritanceGraph(
        addresses=abjad_classes,
        root_addresses=[AbjadObject],
        )
    bad_arcs = []
    children_without_own_slots_def = []
    for parent, children in graph.parent_children_mapping.items():
        parent_attrs = inspect.classify_class_attrs(parent)
        parent_slots_def = [x for x in parent_attrs
            if x.name == '__slots__'][0].defining_class
        parent_has_own_slots_def = parent_slots_def is parent
        for child in children:
            child_attrs = inspect.classify_class_attrs(child)
            child_slots_def = [x for x in child_attrs
                if x.name == '__slots__'][0].defining_class
            if child_slots_def == child and parent_slots_def != parent:
                bad_arcs.append((parent, child))

            child_has_own_slots_def = child_slots_def is child
            if parent_has_own_slots_def and not child_has_own_slots_def:
                children_without_own_slots_def.append((parent, child))
    if bad_arcs:
        print('%d bad slots relationships found:' % len(bad_arcs))
        generator = sorted(
            bad_arcs,
            key=lambda x: (x[0].__module__, x[1].__module__)
            )
        for parent, child in generator:
            print('\t{} -> {}'.format(
                shorten_class_name(parent),
                shorten_class_name(child),
                parent,
                child,
                ))
    else:
        print('No bad slots relationships found.')
    if children_without_own_slots_def:
        message = '{} children without own __slots__ definition found:'
        message = message.format(len(children_without_own_slots_def))
        print(message)
        generator = sorted(
            children_without_own_slots_def,
            key=lambda x: (x[0].__module__, x[1].__module__)
            )
        for parent, child in generator:
            print('\t{} -> {}'.format(
                shorten_class_name(parent),
                shorten_class_name(child),
                parent,
                child,
                ))
    else:
        print('No children without own __slots__ definition found.')
    return graph


if __name__ == '__main__':
    systemtools.IOManager.clear_terminal()
    graph = find_inconsistencies()
    print()
