#!/usr/bin/env python
import argparse
import functools
import io
import sys
import shutil
import xmltodict

from pathlib import Path


def cli_parser(parameters= None):
    argparser = argparse.ArgumentParser(description='XML to C functions converter')
    argparser.add_argument('infile', type=Path, help='Input file (.xml)')
    argparser.add_argument('--outfile', type=Path,
                           help='Out file (.c). Only if special filename needed.')
    argparser.add_argument('--dry', help='true: No outfile is generated', action='store_true')
    return argparser.parse_args(parameters)


def trav_dict(parse_dict, prefix=''):
    for name, value in parse_dict.items():

        function = f"{prefix}_{name}"
        if isinstance(value, dict):
            yield from trav_dict(value, prefix=function)
        else:
            yield { "funcname": function, "paramname": name, "value": value }


def extract_root_section(parse_dict, name, create_setter=False):
    width = 80

    file_stream = io.StringIO()
    writer = functools.partial(print, file=file_stream)

    header = f" {name} ".center(width, "=")
    writer(f"//{header}")
    for finding in trav_dict(parse_dict["root"][name], prefix=name):
        writer(f"void get_{finding['funcname']}(char* {finding['paramname']})\n"
               f"{{\n  //{finding['value']}\n}}\n")

        if create_setter:
            writer(f"void set_{finding['funcname']}(char* {finding['paramname']})\n"
                   f"{{\n  //{finding['value']}\n}}\n")
    return file_stream


def main():
    args = cli_parser()

    infile = args.infile
    outfile = args.outfile or infile.with_suffix(".c")

    file_ctx = infile.read_text(encoding="UTF-8", errors="replace")
    xml_dict = xmltodict.parse(file_ctx)

    try:
        status_stream = extract_root_section(xml_dict, "status")
        config_stream = extract_root_section(xml_dict, "config", create_setter=True)
    except KeyError as err:
        print(f"Parsing XML fails seciton is missing: {err}", file=sys.stderr)
        sys.exit(1)

    if args.dry:
        print(status_stream.getvalue(), end='')
        print(config_stream.getvalue(), end='')
    else:
        with outfile.open("w", encoding="UTF-8") as outp:
            status_stream.seek(0)
            shutil.copyfileobj(status_stream, outp)
            config_stream.seek(0)
            shutil.copyfileobj(config_stream, outp)


if __name__ == '__main__':
    main()