import sys
import urllib
import urllib2

def link(username, objects, fast):
    # Read out all symbol tables that are to be linked
    if not fast:
        definers = {"main": None}
        for obj in objects:
            print("[LINK] %s" % (obj))
            urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": username}))).read()
            urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"read_symbols"', "username": username}))).read()
            urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % obj, "username": username}))).read()

            v = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username}))).read()
            lst = v.rsplit("=", 1)[1]
            lst = lst.split("\n")
            for e in lst:
                if len(e) > 1:
                    name, defined = e.rsplit(":", 1)
                    if defined == "1":
                        if definers.get(name, None):
                            raise Exception("Double definition for symbol %s\nDefined in %s\nDefined in %s" % (name, definers[name], obj))
                        definers[name] = obj
                    else:
                        if name not in definers:
                            definers[name] = None

        # Check for undefined symbols with this linking set
        for symbol in definers:
            if definers[symbol] is None:
                if symbol not in ["input", "output"]:
                    # Some symbols are built-ins which only look like functions
                    raise Exception("Undefined symbol %s" % symbol)

    # Ok, we know that all symbols can be defined with this set of files, now link their initializers together
    initializers = []
    for obj in objects:
        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": username}))).read()
        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"read_initializers"', "username": username}))).read()
        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % obj, "username": username}))).read()
        v = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username}))).read()
        start = str(v.split("&", 1)[0].split("=")[1])
        initializers.append(start)

    # Bind all initializers together
    print("[LOAD] %s:main()" % definers["main"])
    # Set interface to constructors
    commands = [("V", '1')]

    # Link all initializers together
    for init in initializers:
        commands.extend([
                ("V", '"call"'),
                    ("V", '"access"'),
                        ("V", '"resolve"'),
                            ("V", '"exec"'),
                    ("V", '1'),
                    ("V", '"const"'),
                        ("R", str(init)),
                    ("V", 'true'),
            ])

    # Load main function
    commands.extend([
                ("V", '"return"'),
                    ("V", 'true'),
                    ("V", '"call"'),
                        ("V", '"access"'),
                            ("V", '"resolve"'),
                                ("V", '"main"'),
                        ("V", '0'),
                        ("V", 'false'),
            ])

    import json
    urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "data": json.dumps(commands), "username": username}))).read()

if len(sys.argv) == 1:
    print("No username defined")
else:
    username = sys.argv[1]
    objects = set(sys.argv[2:])
    if "--fast" in objects:
        objects.remove("--fast")
        fast = True
    else:
        fast = False

    if objects:
        link(username, objects, fast)
    else:
        print("No files to link defined")
