#!/bin/env python2
# -*- coding: utf-8 -*-
"""
parse_idna_tables.py - Parse IDNA2008 tables to list codepoint property.

Parse the IDNA 2008 tables from IANA website and create a dictionnary with all
codepoints and their IDNA property.

Copied from https://github.com/kjd/idna/blob/master/tools/build-idnadata.py
"""
from lxml import etree
import sys
import argparse
import logging

IDNATABLES_URL = "http://www.iana.org/assignments/idna-tables-{version}/idna-tables-{version}.xml"
IDNATABLES_NS = "http://www.iana.org/assignments"

CODEPOINT_TAG = "{%s}codepoint" % IDNATABLES_NS
PROPERTY_TAG = "{%s}property" % IDNATABLES_NS

logger = logging.getLogger(__name__)


def print_optimised_list(prop):
    codepoint_list = sorted(prop)
    single_codepoints = []
    set_elements = []
    last_write = -1
    for i in xrange(0, len(codepoint_list)):
        if i + 1 < len(codepoint_list):
            if codepoint_list[i] == codepoint_list[i+1]-1:
                continue
        codepoint_range = codepoint_list[last_write+1:i+1]
        if len(codepoint_range) == 1:
            single_codepoints.append("{0}".format(hex(codepoint_range[0])))
        else:
            set_elements.append("list(range({0},{1}))".format(codepoint_range[0],
                                                              codepoint_range[-1] + 1))
        last_write = i

    print("        frozenset(")
    if len(single_codepoints) > 0:
        print("        [\n         " + ",\n         ".join(single_codepoints))
        print("        ] +")
    print("        " + " +\n        ".join(set_elements))
    print("    ),")


def parse_idna_tables(version):
    """
    Make the list of codepoints from IDNA tables.

    Parse IDNA table registry, and create a mapping of all codepoints to their
    structure.

    Input:
        * version: The unicode version to use.
    """
    idna_url = IDNATABLES_URL.format(version=version)
    short_ver = version.translate(None, '.')
    logger.debug("Fetching and parsing '%s'", idna_url)
    registry = etree.parse(idna_url)

    # To keep '{}' when string-formatting
    namespace = "{{{0}}}".format(IDNATABLES_NS)
    registry_id = "idna-tables-properties"
    if list(map(int, version.split('.'))) <= [6, 0, 0]:
        registry_id = "idna-tables-{}-properties".format(version)
    record_xpath = '{0}registry[@id="{1}"]/{0}record'.format(namespace,
                                                             registry_id)

    print('# -*- coding: utf-8 -*-')
    print('# File generated by parse_idna_tables tool')
    print('# Unicode version: %s' % version)
    print('# Generated from %s' % idna_url)
    print('')
    print('idna_tables_%s = {' % short_ver)

    properties = {}
    for record in registry.findall(record_xpath):
        codepoint = record.find(CODEPOINT_TAG).text
        prop = record.find(PROPERTY_TAG).text

        if prop == 'UNASSIGNED':
            continue

        if prop not in properties:
            properties[prop] = set()

        if codepoint.find('-') > 0:
            # Codepoint is a range
            (first_cp, last_cp) = [int(c, 16) for c in codepoint.split('-')]
            for cp in xrange(first_cp, last_cp + 1):
                properties[prop].add(cp)
        else:
            # Single codepoint
            properties[prop].add(int(codepoint, 16))

    for prop in properties:
        print("    '{0}':".format(prop))
        print_optimised_list(properties[prop])

    print('}')


def main():
    parser = argparse.ArgumentParser(description='Parse and make '
                                                 'IDNA properties '
                                                 'from IDNA2008 registry')
    parser.add_argument('-v', '--verbose', action='store_true', help='be verbose')
    parser.add_argument('unicode', metavar='Unicode Version')

    args = parser.parse_args()

    logging.basicConfig(stream=sys.stderr, level=logging.DEBUG if args.verbose else logging.INFO)

    parse_idna_tables(args.unicode)


if __name__ == '__main__':
    main()
