#!/usr/bin/env python3
#
#   message_data_static text encoder
#

import argparse, ast, re
import sys

def read_charmap(path):
    with open(path) as infile:
        charmap = infile.read()

    charmap = ast.literal_eval(charmap)
    charmap = { repr(k)[1:-1] : chr(v) for k,v in charmap.items() }

    return charmap

# From https://stackoverflow.com/questions/241327/remove-c-and-c-comments-using-python
def remove_comments(text):
    def replacer(match):
        s = match.group(0)
        if s.startswith('/'):
            return " " # note: a space and not an empty string
        else:
            return s

    pattern = re.compile(
        r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
        re.DOTALL | re.MULTILINE
    )
    return re.sub(pattern, replacer, text)

def convert_text(text, charmap):
    def cvt_str(m):
        string = m.group(0)

        for orig,char in charmap.items():
            string = string.replace(orig, char)

        return string

    # Naive string matcher, assumes single line strings and no comments, handles escaped quotations
    string_regex = re.compile(r'"((?:[^\\"\n]|\\.)*)"')

    # Collapse escaped newlines
    text = text.replace("\\\n", "")
    # Encode according to charmap
    text = re.sub(string_regex, cvt_str, text)

    return text

def main():
    parser = argparse.ArgumentParser(description="Encode message_data_static text headers")
    parser.add_argument(
        "input",
        help="path to file to be encoded, or - for stdin",
    )
    parser.add_argument(
        "--output",
        "-o",
        help="path to write encoded file, or - for stdout",
        required=True,
    )
    parser.add_argument(
        "--charmap",
        help="path to charmap file specifying custom encoding elements",
        required=True,
    )
    args = parser.parse_args()

    charmap = read_charmap(args.charmap)

    text = ""
    if args.input == "-":
        text = sys.stdin.read()
    else:
        with open(args.input, "r") as infile:
            text = infile.read()

    text = remove_comments(text)
    text = convert_text(text, charmap)

    if args.output == "-":
        sys.stdout.buffer.write(text.encode("raw_unicode_escape"))
    else:
        with open(args.output, "w", encoding="raw_unicode_escape") as outfile:
            outfile.write(text)

if __name__ == "__main__":
    main()
