# Source code for fontTools.merge

    # Copyright 2013 Google, Inc. All Rights Reserved.
    #
    # Google Author(s): Behdad Esfahbod, Roozbeh Pournader

    from fontTools import ttLib
    import fontTools.merge.base
    from fontTools.merge.cmap import (
        computeMegaGlyphOrder,
        computeMegaCmap,
        renameCFFCharStrings,
    )
    from fontTools.merge.layout import layoutPreMerge, layoutPostMerge
    from fontTools.merge.options import Options
    import fontTools.merge.tables
    from fontTools.misc.loggingTools import Timer
    from functools import reduce
    import sys
    import logging

    log = logging.getLogger("fontTools.merge")
    timer = Timer(logger=logging.getLogger(__name__ + ".timer"), level=logging.INFO)

    class Merger(object):
        """Font merger.

        This class merges multiple files into a single OpenType font, taking into
        account complexities such as OpenType layout (``GSUB``/``GPOS``) tables and
        cross-font metrics (for example ``hhea.ascent`` is set to the maximum value
        across all the fonts).

        If multiple glyphs map to the same Unicode value, and the glyphs are considered
        sufficiently different (that is, they differ in any of paths, widths, or
        height), then subsequent glyphs are renamed and a lookup in the ``locl``
        feature will be created to disambiguate them. For example, if the arguments
        are an Arabic font and a Latin font and both contain a set of parentheses,
        the Latin glyphs will be renamed to ``parenleft.1`` and ``parenright.1``,
        and a lookup will be inserted into the to ``locl`` feature (creating it if
        necessary) under the ``latn`` script to substitute ``parenleft`` with
        ``parenleft.1`` etc.

        Restrictions:

        - All fonts must have the same units per em.
        - If duplicate glyph disambiguation takes place as described above then the
          fonts must have a ``GSUB`` table.

        Attributes:
                options: Currently unused.
        """

        def __init__(self, options=None):
            if not options:
                options = Options()

            self.options = options

        def _openFonts(self, fontfiles):
            fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles]
            for font, fontfile in zip(fonts, fontfiles):
                font._merger__fontfile = fontfile
                font._merger__name = font["name"].getDebugName(4)
            return fonts

        def merge(self, fontfiles):
            """Merges fonts together.

            Args:
                    fontfiles: A list of file names to be merged

            Returns:
                    A :class:`fontTools.ttLib.TTFont` object. Call the ``save`` method on
                    this to write it out to an OTF file.
            """
            #
            # Settle on a mega glyph order.
            #
            fonts = self._openFonts(fontfiles)
            glyphOrders = [list(font.getGlyphOrder()) for font in fonts]
            computeMegaGlyphOrder(self, glyphOrders)

            # Take first input file sfntVersion
            sfntVersion = fonts[0].sfntVersion

            # Reload fonts and set new glyph names on them.
            fonts = self._openFonts(fontfiles)
            for font, glyphOrder in zip(fonts, glyphOrders):
                font.setGlyphOrder(glyphOrder)
                if "CFF " in font:
                    renameCFFCharStrings(self, glyphOrder, font["CFF "])

            cmaps = [font["cmap"] for font in fonts]
            self.duplicateGlyphsPerFont = [{} for _ in fonts]
            computeMegaCmap(self, cmaps)

            mega = ttLib.TTFont(sfntVersion=sfntVersion)
            mega.setGlyphOrder(self.glyphOrder)

            for font in fonts:
                self._preMerge(font)

            self.fonts = fonts

            allTags = reduce(set.union, (list(font.keys()) for font in fonts), set())
            allTags.remove("GlyphOrder")

            for tag in sorted(allTags):
                if tag in self.options.drop_tables:
                    continue

                with timer("merge '%s'" % tag):
                    tables = [font.get(tag, NotImplemented) for font in fonts]

                    log.info("Merging '%s'.", tag)
                    clazz = ttLib.getTableClass(tag)
                    table = clazz(tag).merge(self, tables)
                    # XXX Clean this up and use:  table = mergeObjects(tables)

                    if table is not NotImplemented and table is not False:
                        mega[tag] = table
                        log.info("Merged '%s'.", tag)
                    else:
                        log.info("Dropped '%s'.", tag)

            del self.duplicateGlyphsPerFont
            del self.fonts

            self._postMerge(mega)

            return mega

        def mergeObjects(self, returnTable, logic, tables):
            # Right now we don't use self at all.  Will use in the future
            # for options and logging.

            allKeys = set.union(
                set(),
                *(vars(table).keys() for table in tables if table is not NotImplemented),
            )
            for key in allKeys:
                log.info(" %s", key)
                try:
                    mergeLogic = logic[key]
                except KeyError:
                    try:
                        mergeLogic = logic["*"]
                    except KeyError:
                        raise Exception(
                            "Don't know how to merge key %s of class %s"
                            % (key, returnTable.__class__.__name__)
                        )
                if mergeLogic is NotImplemented:
                    continue
                value = mergeLogic(getattr(table, key, NotImplemented) for table in tables)
                if value is not NotImplemented:
                    setattr(returnTable, key, value)

            return returnTable

        def _preMerge(self, font):
            layoutPreMerge(font)

        def _postMerge(self, font):
            layoutPostMerge(font)

            if "OS/2" in font:
                # https://github.com/fonttools/fonttools/issues/2538
                # TODO: Add an option to disable this?
                font["OS/2"].recalcAvgCharWidth(font)

    __all__ = ["Options", "Merger", "main"]

    @timer("make one with everything (TOTAL TIME)")
    def main(args=None):
        """Merge multiple fonts into one"""
        from fontTools import configLogger

        if args is None:
            args = sys.argv[1:]

        options = Options()
        args = options.parse_opts(args)
        fontfiles = []
        if options.input_file:
            with open(options.input_file) as inputfile:
                fontfiles = [
                    line.strip()
                    for line in inputfile.readlines()
                    if not line.lstrip().startswith("#")
                ]
        for g in args:
            fontfiles.append(g)

        if len(fontfiles) < 1:
            print(
                "usage: fonttools merge [font1 ... fontN] [--input-file=filelist.txt] [--output-file=merged.ttf] [--import-file=tables.ttx]",
                file=sys.stderr,
            )
            print(
                "                                   [--drop-tables=tags] [--verbose] [--timing]",
                file=sys.stderr,
            )
            print("", file=sys.stderr)
            print(" font1 ... fontN              Files to merge.", file=sys.stderr)
            print(
                " --input-file=<filename>      Read files to merge from a text file, each path new line. # Comment lines allowed.",
                file=sys.stderr,
            )
            print(
                " --output-file=<filename>     Specify output file name (default: merged.ttf).",
                file=sys.stderr,
            )
            print(
                " --import-file=<filename>     TTX file to import after merging. This can be used to set metadata.",
                file=sys.stderr,
            )
            print(
                " --drop-tables=<table tags>   Comma separated list of table tags to skip, case sensitive.",
                file=sys.stderr,
            )
            print(
                " --verbose                    Output progress information.",
                file=sys.stderr,
            )
            print(" --timing                     Output progress timing.", file=sys.stderr)
            return 1

        configLogger(level=logging.INFO if options.verbose else logging.WARNING)
        if options.timing:
            timer.logger.setLevel(logging.DEBUG)
        else:
            timer.logger.disabled = True

        merger = Merger(options=options)
        font = merger.merge(fontfiles)

        if options.import_file:
            font.importXML(options.import_file)

        with timer("compile and save font"):
            font.save(options.output_file)

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