#!/usr/bin/env python
"""
Create UIDs for the Storage SOP Classes taken from the generated ``_uids.py``.
"""
import os
import re
import tokenize

import pydicom
from pydicom._uid_dict import UID_dictionary

STORAGE_REGEX = re.compile('.*(Storage|Storage SOP Class|Storage - '
                           'For Presentation|Storage - For Processing)$')


def is_storage_class(attributes):
    return (attributes[1] == 'SOP Class' and
            STORAGE_REGEX.match(attributes[0]) and
            attributes[3] != 'Retired')


def replace_number(number):
    """Replace the given number bey a literal representation."""
    numbers = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five',
               'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Eleven',
               'Twelve', 'Thirteen', 'Fourteen', 'Fifteen']
    if number < len(numbers):
        return numbers[number]

    # return the original string if not found - will raise later
    return str(number)


def replace_digits(name):
    """Replace the leading digits in the given string by
    a literal representation.
    """
    number_regex = re.compile(r'^(?P<number>\d*)(?P<rest>.*)')
    match = number_regex.match(name)
    number = replace_number(int(match.group('number')))
    rest = match.group('rest')
    return number + rest[0].upper() + rest[1:]


def sop_class_name(description):
    """Return a name used as class identifier for the given SOP class
    description.
    """
    name = description
    if name.endswith(' SOP Class'):
        name = name[:-10]

    name = replace_bad_characters(name)

    if name[:1].isdigit():
        name = replace_digits(name)
    if not re.match(tokenize.Name + '$', name):
        raise NotImplementedError(
            'Cannot create name for SOP class "{}"'.format(description))
    return name


def replace_bad_characters(name):
    bad_chars = r'!@#$%^&*(),;:.?\|{}[]+-=/ '
    translate_table = dict((ord(char), None) for char in bad_chars)
    return name.translate(translate_table)


def uid_line(uid, name):
    """Return the UID class definition line to be written into the python file.
    """
    # add a line break after UID to avoid too long lines
    return "{} = UID(\n    '{}')\n".format(sop_class_name(name), uid)


def generate_uids(filename):
    """Generate python file with SOP Class UID definitions."""
    with open(filename, 'w') as uid_file:
        doc_string = (
            '"""\nStorage SOP Class UIDs auto-generated by %s\n"""\n\n'
            % os.path.basename(__file__))
        uid_file.write(doc_string)
        uid_file.write('from pydicom.uid import UID\n\n')

        for uid, attribs in sorted(UID_dictionary.items()):
            if is_storage_class(attribs):
                uid_file.write(uid_line(uid, attribs[0]))


if __name__ == "__main__":
    pydicom_dir = os.path.dirname(pydicom.__file__)
    generate_uids(os.path.join(pydicom_dir, '_storage_sopclass_uids.py'))
