import cgi
from collections import deque
import json
import os.path
import sys
import time

mario_id = 177


def load_json(filename):
    with open(filename, "rb") as f:
        return json.loads(f.read())

def load(name):
    try:
        return load_json("%s.json" % name)
    except:
        return []

def fetch(type, id):
    filename = "%s/%s.json" % (type, id)
    return load_json(filename)

def fetch_character(id):
    return fetch("character", id)

def fetch_game(id):
    return fetch("game", id)

def p(s):
    print s.encode(sys.stdout.encoding, 'replace')

done = load("done")
todo = load("todo")
seen = done + todo
seen_games = {id: (name, prev) for type, id, name, degree, prev in seen if type == "game"}
seen_characters = {id: (name, prev, degree) for type, id, name, degree, prev in seen if type == "character"}

rev_games = {}
rev_characters = {}
for type, sid, sname, degree, prev in seen:
    if type == "game":
        rev_games.setdefault(prev, []).append((sname, sid))
    elif type == "character":
        rev_characters.setdefault(prev, []).append((sname, sid))

def fill_tree(important_chars):
    tree_chars = set(important_chars)
    tree_games = set()
    tree_edges = list()
    for important_char_id in important_chars:
        char_id = important_char_id
        while True:
            game_id = seen_characters[char_id][1]
            if game_id is None:
                break
            tree_edges.append((char_id, 'g%s'%game_id))
            if game_id in tree_games:
                break
            tree_games.add(game_id)
            char_id = seen_games[game_id][1]
            tree_edges.append(('g%s'%game_id, char_id))
            if char_id in tree_chars:
                break
            tree_chars.add(char_id)
    return tree_chars, tree_games, tree_edges

def isingames(id,min=2):
    return id in rev_games and len(rev_games[id])>=min

def has_descr(id):
    try:
        data = fetch_character(id)
    except:
        return False
    r=data["results"]
    return r["description"] is not None

def find(maxdeg=6):
    c=[]
    for type, id, name, degree, prev in seen:
        if type != "character": continue
        if degree>maxdeg: continue
        if not isingames(id,1): continue
        if not has_descr(id): continue
        c.append(id)
    return fill_tree(c)

cnodes, gnodes, edges = find(6)

print "%s / %s characters" % (len(cnodes), len(seen_characters))
print "%s / %s games" % (len(gnodes), len(seen_games))
print "%s / %s edges" % (len(edges), len(seen) - 1)

img_kinds = [
    ("medium", lambda id: id == mario_id),
    #("icon", lambda id: isingames(id, 2)),
    ("icon", lambda id: True),
    ("tiny", lambda id: True),
]
img_folder = "cimg"

with open("graph.dot", "wt") as f:
    def p(s):
        f.write(s.encode('utf-8', 'replace') + '\n')

    p("digraph {")
    p('size="100,100"; ranksep=2.0; nodesep=1;')
    p('overlap=false;')
    #p('overlap=scalexy;')
    #p('overlap=compress;')

    #p('splines=true;')

    p('sep=1;') # 0.1, 1
    p('node [shape=none,fontcolor=black];')
    for id in gnodes:
        p('g%s [label="%s"];' % (id, seen_games[id][0].replace('"', "'")))
    p("node [shape=none,fontcolor=dodgerblue4];")
    for id in cnodes:
        label =  seen_characters[id][0].replace('"', "'")
        #f2.write(label.encode('utf-8', 'replace') + '\n')
        for img_kind, check in img_kinds:
            if not check(id): continue
            img_filename = "%s/%s-%s.png" % (img_folder, img_kind, id)
            if os.path.isfile(img_filename):
                #p('%s [label="%s", image="%s"];' % (id, label, img_filename))
                #p('%s [label=<<TABLE BORDER="0" CELLBORDER="0"><TR><TD><IMG SRC="%s"/></TD><TD>%s</TD></TR></TABLE>>];' % (id, img_filename, cgi.escape(label)))
                p('%s [label=<<TABLE BORDER="0" CELLBORDER="0"><TR><TD><IMG SRC="%s"/></TD></TR><TR><TD>%s</TD></TR></TABLE>>];' % (id, img_filename, cgi.escape(label)))
                break
        else:
            p('%s [label="%s"];' % (id, label))
    p("edge [weight=1];")
    for id, prev in edges:
        p('%s -> %s;' % (id, prev))
    p("}")
