#!/usr/bin/env python
# Single purpose HTTP server
# - serves files specified as arguments in order of appearance


import os
import sys
import BaseHTTPServer
import xml.etree.ElementTree as ET

def print_method_param_value(value_element, stream=sys.stdout, prefix="", suffix="\n"):
    stream.write(prefix)

    if value_element.tag == "array":
        array = value_element[0]
        if len(array) > 0:
            print_method_param_value(array[0][0], stream, "", "")

        if len(array) > 1:
            for value in array[1:]:
                print_method_param_value(value[0], stream, ", ", "")
    else:
        if value_element.tag == "base64":
            stream.write("<binary data>")
        else:
            stream.write(value_element.text)

    stream.write(suffix)


def print_method_param_member(member_element, stream=sys.stdout):
    stream.write(member_element[0].text)
    stream.write(":")
    print_method_param_value(member_element[1][0], stream, "\t")


class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_POST(self):
        self.send_response(200)
        self.send_header("Content-type", "text/xml")
        self.end_headers()

        data_as_string = self.rfile.read(int(self.headers.getheader('content-length')))
        call = ET.fromstring(data_as_string)
        method_name = "unknown"
        if call.tag != "methodCall" and call[0].tag != "methodName":
            sys.stderr("Missing methodCall or methodName")
        else:
            method_name = call[0].text

        if call[1].tag != "params" and call[1][0].tag != "param"  and call[1][0][0].tag != "value":
            sys.stderr("Missing params")
        else:
            struct = call[1][0][0][0]
            if struct.tag != "struct":
                sys.stderr("Invalid params: no struct")
            else:
                with open("%s_%s_call.log" % (self.prefix, method_name), "w") as logf:
                    for member in struct:
                        print_method_param_member(member, logf)
                        print_method_param_member(member, sys.stdout)

        response = "#! invalid pyserve response"
        if not self.filelist:
            sys.stderr.write("No more files to serve\n")
        else:
            name, tmp_response = self.filelist.pop()
            if not name.startswith(method_name + ".response"):
                sys.stderr.write("Received an unexpected method call: ")
                sys.stderr.write(method_name)
                sys.stderr.write(" vs. ")
                sys.stderr.write(name)
                sys.stderr.write("\n")
            else:
                sys.stdout.write("Response: ")
                sys.stdout.write(name)
                sys.stdout.write("\n")
                response = tmp_response


        sys.stderr.flush()
        sys.stdout.flush()

        self.reply(response)


    def reply(self, response):
        try:
            # redirect stdout to client
            stdout = sys.stdout
            sys.stdout = self.wfile
            print(response)
        finally:
            sys.stdout = stdout # restore


filelist = []
for fn in sys.argv[2:]:
    try:
        with open(fn) as f:
            filelist.append((fn, f.read()))
            sys.stdout.write("Loaded: ")
            sys.stdout.write(fn)
            sys.stdout.write("\n")
            sys.stdout.flush()
    except Exception as ex:
        sys.stderr.write(str(ex))
        sys.stderr.write("\n")
        sys.stderr.flush()

filelist.reverse()

PORT = 12345
print "Serving at port", PORT
Handler.filelist = filelist
Handler.prefix = sys.argv[1]
httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
httpd.serve_forever()
