#!python

import subprocess
from asciitree import LeftAligned
from collections import OrderedDict as OD

def get_reqs(reqs, tree, pkg):
    if pkg=='' or pkg in reqs:
        return
    print('find reqs for', pkg)
    proc = subprocess.Popen(['pip3', 'show', pkg], stdout=subprocess.PIPE)
    out = proc.communicate()[0].decode()
    try:
        pkg_ver = [r.split(':')[1].strip() for r in out.split('\n') if 'Version' in r][0]
        print ("Version:", pkg_ver)
        pkg_reqs = [[p.strip() for p in r.split(':')[1].split(',') if p.strip()!=""] for r in out.split('\n') if 'Requires' in r][0]
        reqs[pkg] = (pkg_ver, pkg_reqs)
        tree[pkg+'=='+pkg_ver] = OD()
        if len(pkg_reqs)==0:
           return
        list(map(lambda pkg_req: get_reqs(reqs, tree[pkg+'=='+pkg_ver], pkg_req), pkg_reqs))
    except IndexError:
        pass

def make_full_tree(reqs, pkg):
    t = OD()
    t[pkg+'=='+reqs[pkg][0]] = OD()
    def recursv(deps, t):
        for dep in deps:
            v, d = reqs[dep]
            t[dep+'=='+v] = OD()
            if len(d)>0:
                recursv(d, t[dep+'=='+v])
    recursv(reqs[pkg][1], t[pkg+'=='+reqs[pkg][0]])
    return t

def parse_reqs(reqs, pkg):
    l = []
    deps = reqs[pkg][1]
    def recursv(deps):
        for dep in deps:
            v, d = reqs[dep]
            if len(d)>0:
                recursv(d)
            if dep+'=='+v not in set(l):
                l.append(dep+'=='+v)
    recursv(deps)
    l.append(pkg+'=='+reqs[pkg][0])
    return l

if __name__=='__main__':
    import sys
    import os
    import argparse

    parser = argparse.ArgumentParser(description='get full list of dependencies for installed pip packages')
    parser.add_argument('pkg', help='installed pip package')
    parser.add_argument('--write', help='write to requirements.txt file', action='store_true')

    args = parser.parse_args()

    reqs = {}
    tree = OD()

    get_reqs(reqs, tree, args.pkg)
    if len(reqs)==0:
        print('Package ['+args.pkg+'] not installed!')
        sys.exit()
    full_tree = make_full_tree(reqs, args.pkg)
    reqs_list = parse_reqs(reqs, args.pkg)
    if args.write:
        with open('requirements.txt', 'w') as fd:
            [fd.write(l+'\n') for l in reqs_list]

    print(25*'*')
    print("full dependency tree")
    print(25*'*')
    tr1 = LeftAligned()
    print(tr1(full_tree))

    print(25*'*')
    print("ordered tree -- no duplicates")
    print(25*'*')
    tr2 = LeftAligned()
    print(tr2(tree))

    print(25*'*')
    print("copy to requirements.txt (or use '--write' option)")
    print(25*'*')
    for l in reqs_list: print(l)

    print(25*'*')
    print("download to local: pip wheel --wheel-dir=/path/to/wheels -r requirements.txt")
    print("install from local: pip install --no-index --find-links=/path/to/wheels -r requirements.txt")
    print("install from online: pip install -r requirements.txt")
    print(25*'*')
