#! /usr/bin/python3
# coding: utf-8
#
# Graphical Asynchronous Music Player Client
#
# Copyright (C) 2015 Itaï BEN YAACOV
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import sys
import gc
import gbulb

from gampc import app


gbulb.install(gtk=True)
gc.disable()
app.App().run(sys.argv)


class NaiveReferenceTree(object):
    def __init__(self, top):
        self.top = top
        self._referred = []

    def nodes(self):
        for node in self._referred:
            yield from node.nodes()
        yield self

    def paths(self):
        for node in self._referred:
            for path in node.paths():
                yield [self] + path
        yield [self]

    def add_node(self, node):
        for p in node.paths():
            if self == p[-1]:
                print('LOOP:')
                for n in p:
                    print(type(n.top), n.top if type(n.top) != dict else '')
                raise Exception
        if node not in self._referred:
            self._referred.append(node)

    def print(self, l=0):
        if self.top is not None:
            print('{} [{}] {}'.format('-' * l, type(self.top).__name__, self.top if type(self.top) is not dict else id(self.top)))
        for n in self._referred:
            n.print(l + 1)


class NaiveReferenceTreeTop(NaiveReferenceTree):
    def __init__(self):
        NaiveReferenceTree.__init__(self, None)

    def new_object(self, obj):
        node = NaiveReferenceTree(obj)
        self.add_node(node)
        return node

    def improve(self):
        for o in list(self._referred):
            found = False
            for r in gc.get_referrers(o.top):
                if r != locals() and not (type(r) == dict and 'top' in r):
                    for node in self.nodes():
                        if r is node.top:
                            break
                    else:
                        node = self.new_object(r)
                    node.add_node(o)
                    found = True
            if found:
                self._referred.remove(o)


T = NaiveReferenceTreeTop()


l = gc.get_objects()
for o in l:
    if type(o).__name__.endswith('Extension'):
        T.new_object(o)
        continue
    for prefix in ('gampc', 'ampd'):
        if type(o).__module__.startswith(prefix) and not type(o).__name__.startswith('Condition') and type(o).__name__ not in ['DictNamespace', 'Item', 'OrderedMenu']:
            T.new_object(o)

del l

T.improve()
T.improve()
T.improve()
T.improve()
T.improve()
T.improve()
T.improve()
T.improve()
T.improve()
T.print()

del T
