""" A set of utilities for transforming json/tests/ALS traces data for the
    purposes of easing debugging and writing tests.
"""

import re
import json
import yaml

SEND_KEY = "send"
WAIT_KEY = "wait"
# The keys in the json format for tests that represent, respectively,
# what we send and what we expect to receive.


def traces_to_test(inout_file, project_root=None, input_only=False):
    """Take as parameter the name of a file that was generated using the
       i/o traces of ada_language_server, and the root directory of the
       project that the ada_language_server was run on, and return
       a list for it - this list is "as is" the json format in use
       for our tests.

       inout_file: path to a file which was created via the ALS.IN
         and ALS.OUT traces
       project_root: the full path to where the project sits.
          if project_root is None, do not replace paths.

       input_only: whether to consider only the input

       return: a list representing the test
    """

    groups = []
    # A list of groups. Each group is a dict with "sends" containing the
    # request to send, and "waits" containing a list of things to await
    # corresponding to that request
    with open(inout_file, 'rb') as f:
        in_re = re.compile(b' *([^{]*) ({.*})')
        for line in f.readlines():
            m = in_re.match(line)
            if m and m.group(1) in (b"[ALS.IN]", b"[ALS.OUT]"):
                is_input = m.group(1) == b"[ALS.IN]"
                cleaned = m.group(2)
                if project_root:
                    cleaned = re.sub('"file://?{}/?([^"]*)"'.format(project_root),
                                     '"$URI{\\1}"', cleaned.decode('ascii')
                                     ).replace('URI{}', 'URI{.}')
                d = json.loads(cleaned)

                if is_input:
                    # Found an "in" line. Create a group and append it
                    groups.append({"sends": d, "waits": []})
                else:
                    if not input_only:
                        # Found an "out" line: add it to the last bit of "in"
                        del(d['jsonrpc'])  # btw we remove jsonrpc from waits
                        groups[-1]["waits"].append(d)

    # Generate the test header
    result = [{"comment": ["test automatically generated"]},
              {"start": {"cmd": ["${ALS}"]}}]

    # Generate all the send commands
    for g in groups:
        result.append({"send": {"request": g["sends"], "wait": g["waits"]}})

    # Generate the test footer
    result.append({"stop": {"exit_code": 0}})

    return result


def python_to_protocol_string(reqs, pwd=None):
    """Take a list of requests (each one being a dict) and return a string
       ready for consumption by the ALS.

       pwd is the path to substitute to URI{} blocks.
       If None, no substitution is performed.
    """
    result = ""
    for req in reqs:
        # Add the "jsonrpc" field if needs be
        req["jsonrpc"] = "2.0"
        s = json.dumps(req, separators=(',', ':'))
        # TODO: perform path localization in s?
        # ... and add the "Content-Length" and CRLF terminators requred by the
        # protocol
        result += 'Content-Length: {}\r\n\r\n{}'.format(len(s), s)

    return result
