#!/usr/bin/env python3
""" Convert SVG paths to UFO glyphs. """


__requires__ = ["fontTools"]

from types import SimpleNamespace
from fontTools.svgLib import SVGPath

from fontTools.pens.pointPen import SegmentToPointPen
from fontTools.ufoLib.glifLib import writeGlyphToString


__all__ = ["svg2glif"]


def svg2glif(svg, name, width=0, height=0, unicodes=None, transform=None, version=2):
    """Convert an SVG outline to a UFO glyph with given 'name', advance
    'width' and 'height' (int), and 'unicodes' (list of int).
    Return the resulting string in GLIF format (default: version 2).
    If 'transform' is provided, apply a transformation matrix before the
    conversion (must be tuple of 6 floats, or a FontTools Transform object).
    """
    glyph = SimpleNamespace(width=width, height=height, unicodes=unicodes)
    outline = SVGPath.fromstring(svg, transform=transform)

    # writeGlyphToString takes a callable (usually a glyph's drawPoints
    # method) that accepts a PointPen, however SVGPath currently only has
    # a draw method that accepts a segment pen. We need to wrap the call
    # with a converter pen.
    def drawPoints(pointPen):
        pen = SegmentToPointPen(pointPen)
        outline.draw(pen)

    return writeGlyphToString(
        name, glyphObject=glyph, drawPointsFunc=drawPoints, formatVersion=version
    )


def parse_args(args):
    import argparse

    def split(arg):
        return arg.replace(",", " ").split()

    def unicode_hex_list(arg):
        try:
            return [int(unihex, 16) for unihex in split(arg)]
        except ValueError:
            msg = "Invalid unicode hexadecimal value: %r" % arg
            raise argparse.ArgumentTypeError(msg)

    def transform_list(arg):
        try:
            return [float(n) for n in split(arg)]
        except ValueError:
            msg = "Invalid transformation matrix: %r" % arg
            raise argparse.ArgumentTypeError(msg)

    parser = argparse.ArgumentParser(
        description="Convert SVG outlines to UFO glyphs (.glif)"
    )
    parser.add_argument(
        "infile",
        metavar="INPUT.svg",
        help="Input SVG file containing " '<path> elements with "d" attributes.',
    )
    parser.add_argument(
        "outfile",
        metavar="OUTPUT.glif",
        help="Output GLIF file (default: " "print to stdout)",
        nargs="?",
    )
    parser.add_argument(
        "-n",
        "--name",
        help="The glyph name (default: input SVG file "
        "basename, without the .svg extension)",
    )
    parser.add_argument(
        "-w",
        "--width",
        help="The glyph advance width (default: 0)",
        type=int,
        default=0,
    )
    parser.add_argument(
        "-H",
        "--height",
        help="The glyph vertical advance (optional if " '"width" is defined)',
        type=int,
        default=0,
    )
    parser.add_argument(
        "-u",
        "--unicodes",
        help="List of Unicode code points as hexadecimal "
        'numbers (e.g. -u "0041 0042")',
        type=unicode_hex_list,
    )
    parser.add_argument(
        "-t",
        "--transform",
        help="Transformation matrix as a list of six "
        'float values (e.g. -t "0.1 0 0 -0.1 -50 200")',
        type=transform_list,
    )
    parser.add_argument(
        "-f",
        "--format",
        help="UFO GLIF format version (default: 2)",
        type=int,
        choices=(1, 2),
        default=2,
    )

    return parser.parse_args(args)


def main(args=None):
    from io import open

    options = parse_args(args)

    svg_file = options.infile

    if options.name:
        name = options.name
    else:
        import os

        name = os.path.splitext(os.path.basename(svg_file))[0]

    with open(svg_file, "r", encoding="utf-8") as f:
        svg = f.read()

    glif = svg2glif(
        svg,
        name,
        width=options.width,
        height=options.height,
        unicodes=options.unicodes,
        transform=options.transform,
        version=options.format,
    )

    if options.outfile is None:
        print(glif)
    else:
        with open(options.outfile, "w", encoding="utf-8") as f:
            f.write(glif)


if __name__ == "__main__":
    import sys

    sys.exit(main())
