#! /usr/bin/env python3

"""
Given an XML file containing the CF conventions for standardized field names
(https://cfconventions.org/standard-names.html), this tool generates a YAML
file with the same information.

Usage: cf-xml-to-yaml <cf-xml-file>
"""

import sys, os, argparse
from math import *

###############################################################################
def parse_command_line(args, description):
###############################################################################
    parser = argparse.ArgumentParser(
        usage="""\n{0} <xmlfile>
OR
{0} --help

\033[1mEXAMPLES:\033[0m
    \033[1;32m# Convert FILE to YAML \033[0m
    > {0} FILE
""".format(os.path.basename(args[0])),
        description=description,
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    parser.add_argument("xmlfile",
                        help="The path to the xml file. Expects a .xml extension. "
                        "The YAML output file will be the same except using a .yaml extension")

    args = parser.parse_args(args[1:])

    return args

###############################################################################
class Entry:
###############################################################################
    def __init__(self, id=None, units="", description=""):
        self.id = id
        self.units = units
        self.description = description
        self.aliases = []
    def __repr__(self):
        return "Entry(id = '%s', units='%s', description='%s')"% \
                (self.id, self.units, self.description, self.aliases)

###############################################################################
def parse_cf_xml(xml_file):
###############################################################################
    import xml.etree.ElementTree as ET
    tree = ET.parse(xml_file)
    root = tree.getroot()
    entries = {}
    for child in root:
        if child.tag == 'entry':
            id = child.attrib['id']
            units = ""
            descr = ""
            for elem in child:
                if elem.tag == 'units':
                    units = elem.text or ""
                elif elem.tag == 'description':
                    descr = elem.text or ""
            entries[id] = Entry(id, units, descr)
        elif child.tag == 'alias':
            id = child.attrib['id']
            entry_id = None
            for elem in child:
                if elem.tag == 'entry_id':
                    entry_id = elem.text
            entries[entry_id].aliases.append(id)
    return entries.values()

###############################################################################
def write_cf_yaml(entries, yaml_file):
###############################################################################
    with open(yaml_file, 'w', encoding="utf-8") as f:
        f.write('# %s - generated by cf-xml-to-yaml. DO NOT EDIT!\n\n'%yaml_file)
        for e in entries:
            f.write('%s:\n'%e.id)
            f.write("  description: '%s'\n"%e.description.replace("'", "''"))
            if e.units != '':
                f.write('  units: %s\n'%e.units)
            else:
                f.write('  units:\n')
            f.write('  aliases:')
            for alias in e.aliases:
                f.write(' %s'%alias)
            f.write('\n\n')

###############################################################################
def cf_xml_to_yaml(xmlfile):
###############################################################################
    xml_file = sys.argv[1]
    yaml_file = xml_file.replace('.xml', '.yaml')
    entries = parse_cf_xml(xml_file)
    write_cf_yaml(entries, yaml_file)

    return True

###############################################################################
def _main_func(description):
###############################################################################
    success = cf_xml_to_yaml(**vars(parse_command_line(sys.argv, description)))

    sys.exit(0 if success else 1)

###############################################################################

if (__name__ == "__main__"):
    _main_func(__doc__)
