#!/usr/bin/env python3
"""Write hanja.dict from result-per-row UTF-8 sources."""

import sys
import unicodedata
from pathlib import Path


SOURCES = [Path(__file__).with_name(name)
           for name in ("hanja.src", "mssymbol.src")]
MAXCANDIDATES = 128


def ishangul(s):
    return s != "" and all(0xAC00 <= ord(c) <= 0xD7A3 for c in s)


def isjamo(s):
    return len(s) == 1 and 0x3131 <= ord(s) <= 0x314E


def ishanja(s):
    return s != "" and all(0x3400 <= ord(c) <= 0x4DBF
                           or 0x4E00 <= ord(c) <= 0x9FFF
                           or 0xF900 <= ord(c) <= 0xFAFF for c in s)


def issymbol(s):
    """One rune the popup can draw and a candidate row can carry: not a
    space, which the row separates candidates with, and not a formatting
    character, which would leave a blank candidate to pick."""
    return (len(s) == 1 and not s.isspace() and not ishanja(s)
            and not unicodedata.category(s).startswith("C"))


def read(path, table, seen):
    """Adds path's rows to table, keyed by reading, and returns its header."""
    comments = []
    leading = True
    found = False
    with path.open(encoding="utf-8") as src:
        for lineno, raw in enumerate(src, 1):
            line = raw.rstrip("\r\n")
            if not line:
                continue
            if line.startswith("#"):
                if leading:
                    comments.append(";;" + line[1:])
                continue
            leading = False
            fields = line.split("\t")
            if len(fields) != 2:
                raise ValueError(f"{path}:{lineno}: need result<TAB>reading")
            value, reading = fields
            if ishangul(reading):
                if not ishanja(value):
                    raise ValueError(f"{path}:{lineno}: need BMP Hanja")
            elif isjamo(reading):
                if not issymbol(value):
                    raise ValueError(f"{path}:{lineno}: need one symbol rune")
            else:
                raise ValueError(f"{path}:{lineno}: need a syllable or jamo "
                                 "reading")
            pair = (value, reading)
            if pair in seen:
                raise ValueError(f"{path}:{lineno}: duplicate reading")
            seen.add(pair)
            found = True
            table.setdefault(reading, []).append(value)
    if not found:
        raise ValueError(f"{path}: no readings")
    return comments


def main():
    sys.stdout.reconfigure(encoding="utf-8")
    sys.stderr.reconfigure(encoding="utf-8")
    paths = [Path(arg) for arg in sys.argv[1:]] or SOURCES
    table = {}
    seen = set()
    try:
        comments = [line for path in paths for line in read(path, table, seen)]
        for line in comments:
            print(line)
        if comments:
            print()
        for reading, candidates in table.items():
            print(f"{reading}\t{' '.join(candidates[:MAXCANDIDATES])}")
    except (OSError, UnicodeError, ValueError) as error:
        print(error, file=sys.stderr)
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())
