from .util import nodenamefmt
from .libgraph import gen_autorefresh_edges, gen_edges, gen_unmanaged_edges, unmanaged_refs, toposort
from . import entitypes


def dot(samizdats):
    """
    Adorned GraphViz dotfile output.
    """
    samizdats = set(filter(lambda s: not getattr(s, 'autorefresher', False), samizdats))  # filter out autogenerated functions/triggers — autorefresh relationships will be expressed as edges only
    unmanaged = unmanaged_refs(samizdats)
    samizdat_map = {sd.fq: sd for sd in samizdats}
    topsorted = list(toposort({k: v.fqdeps_on() for k, v in samizdat_map.items()}))
    samerank = slice(-1, 1)

    def nodefmt(sd):
        styles = {
            entitypes.MATVIEW.name: '"%s" [shape=box3d fillcolor=red]',
            entitypes.VIEW.name: '"%s" [shape=box fillcolor=grey]',
            entitypes.FUNCTION.name: '"%s" [shape=hexagon fillcolor=olivedrab1]',
            entitypes.TRIGGER.name: '"%s" [shape=cds fillcolor=darkorchid1]',
        }
        return styles[sd.entity_type.name] % sd

    def nice_edges(edges):
        for nodepair in edges:
            yield tuple(map(nodenamefmt, nodepair))

    def enquote(thing):
        return '"%s"' % thing

    unmanaged_fmted = {nodenamefmt(n) for n in unmanaged}
    yield '''
    digraph {
    {
    node [style="filled" fontname="sans-serif" margin="0.15, 0.15"];
    newrank="true";
    '''
    yield '\n'.join(('"%s" [shape=house fillcolor=yellow]' % n for n in unmanaged_fmted))
    yield '\n'.join(map(nodefmt, samizdats))
    yield '}'

    yield '\n'.join(('"%s" -> "%s"' % e for e in nice_edges(gen_edges(samizdats))))
    yield '\n'.join(('"%s" -> "%s" [arrowhead="dot" color="navy" style="dashed" label="🗘" fontname="sans-serif" fontcolor="navy"]' % e for e in nice_edges(gen_autorefresh_edges(samizdats))))
    yield '\n'.join(('"%s" -> "%s" [color="red"]' % e for e in nice_edges(gen_unmanaged_edges(samizdats))))

    if unmanaged:
        yield '{ rank=min; %s }' % ' '.join(map(enquote, unmanaged_fmted))
        samerank = slice(0, -1)
    for rank in topsorted[samerank]:
        yield '{ rank=same; %s }' % ' '.join(map(enquote, map(nodenamefmt, rank)))
    yield '{ rank=max; %s }' % ' '.join(map(enquote, map(nodenamefmt, topsorted[-1])))
    yield '}'
