"""
Utility to generate terminology.py from PITerminology.h and
PIStringTerminology.h in the Photoshop SDK. Use with Python 3.

Usage:

    python3 tools/extract_terminology.py \
        photoshopsdk/PITerminology.h \
        src/psd_tools/terminology.py

.. note:: Adobe explicitly prohibits Photoshop SDK to be used for Open source
    software. Therefore, psd-tools does not bundle the official header files.
    https://www.adobe.com/devnet/photoshop/sdk/eula.html
"""

from __future__ import print_function

import re
import sys

FILE_HEADER = '''"""
Constants for descriptor.

This file is automaticaly generated by tools/extract_terminology.py
"""
from enum import Enum as _Enum'''


TERM_DEF = '''class {0}(_Enum):
    """
    {0} definitions extracted from PITerminology.h.

    See https://www.adobe.com/devnet/photoshop/sdk.html
    """'''


TERM_PATTERN = re.compile(
    r"^#define\s+(?P<key>\w+)\s+'(?P<value>....)'(\s+//\s(?P<comment>.*))?$"
)


STERM_DEF = '''class StringTerm(Enum):
    """
    String terms extracted from PIStringTerminology.h in Photoshop SDK.

    This defines constants for the strings used to access descriptor events,
    keys, classes, enum types, and enum values.

    See https://www.adobe.com/devnet/photoshop/sdk.html
    """'''


STERM_PATTERN = re.compile(
    r'^#define\s+(?P<key>\w+)\s+"(?P<value>[^"]+)"(\s+//\s(?P<comment>.*))?$'
)


def extract_terminology(filepath, pattern=None):
    terms = {}
    keys = set()
    with open(filepath, "r") as f:
        for line in f:
            m = re.match(pattern or TERM_PATTERN, line)
            if m:
                key = m.group("key")
                if key in keys:
                    continue
                upper = re.search(r"[0-9A-Z]", key)
                kls, name = key[: upper.start()], key[upper.start() :]
                if re.match(r"[0-9]", name[0]) or name in ("None", "True", "False"):
                    name = "_" + name
                kls = kls.capitalize().replace("Class", "Klass")
                if kls in terms:
                    terms[kls].append((name, m.group("value")))
                else:
                    terms[kls] = [(name, m.group("value"))]
    return terms


def print_class(name, fields, header=None, **kwargs):
    print("\n", **kwargs)
    print((header or "class {0}:").format(name), **kwargs)
    for field in fields:
        print("    %s = b%r" % field, **kwargs)


def main():
    terms = extract_terminology(sys.argv[1])

    with open(sys.argv[2], "w") as f:
        print(FILE_HEADER, file=f)
        for name in terms:
            print_class(name, terms[name], TERM_DEF, file=f)


if __name__ == "__main__":
    main()
