#!/usr/bin/env python3
# Copyright 2013,2016 The Font Bakery Authors.
# Copyright 2017 The Google Font Tools Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# See AUTHORS.txt for the list of Authors and LICENSE.txt for the License.
"""
Replace a collection of fonts nametable's with new tables based on
the Google Fonts naming spec from just the filename.

The fsSelection, fsType and macStyle also get updated
to reflect the new names.
"""
from __future__ import print_function
import re
import ntpath
from argparse import ArgumentParser, RawTextHelpFormatter
from fontTools.ttLib import TTFont, newTable

WIN_SAFE_STYLES = [
    "Regular",
    "Bold",
    "Italic",
    "BoldItalic",
]

MACSTYLE = {"Regular": 0, "Bold": 1, "Italic": 2, "Bold Italic": 3}

# Weight name to value mapping:
WEIGHTS = {
    "Thin": 250,
    "ExtraLight": 275,
    "Light": 300,
    "Regular": 400,
    "Italic": 400,
    "Medium": 500,
    "SemiBold": 600,
    "Bold": 700,
    "ExtraBold": 800,
    "Black": 900,
}

REQUIRED_FIELDS = [
    (0, 1, 0, 0),
    (1, 1, 0, 0),
    (2, 1, 0, 0),
    (3, 1, 0, 0),
    (4, 1, 0, 0),
    (5, 1, 0, 0),
    (6, 1, 0, 0),
    (7, 1, 0, 0),
    (8, 1, 0, 0),
    (9, 1, 0, 0),
    (11, 1, 0, 0),
    (12, 1, 0, 0),
    (13, 1, 0, 0),
    (14, 1, 0, 0),
    (0, 3, 1, 1033),
    (1, 3, 1, 1033),
    (1, 3, 1, 1033),
    (2, 3, 1, 1033),
    (3, 3, 1, 1033),
    (4, 3, 1, 1033),
    (5, 3, 1, 1033),
    (6, 3, 1, 1033),
    (7, 3, 1, 1033),
    (8, 3, 1, 1033),
    (9, 3, 1, 1033),
    (11, 3, 1, 1033),
    (12, 3, 1, 1033),
    (13, 3, 1, 1033),
    (14, 3, 1, 1033),
]


def _split_camelcase(text):
    return re.sub(r"(?<=\w)([A-Z])", r" \1", text)


def _mac_subfamily_name(style_name):
    if style_name.startswith("Italic"):
        pass
    elif "Italic" in style_name:
        style_name = style_name.replace("Italic", " Italic")
    return style_name


def _unique_id(version, vendor_id, filename):
    # Glyphsapp style 2.000;MYFO;Arsenal-Bold
    # version;vendorID;filename
    return "%s;%s;%s" % (version, vendor_id, filename)


def _version(text):
    return re.search(r"[0-9]{1,4}\.[0-9]{1,8}", text).group(0)


def _full_name(family_name, style_name):
    style_name = _mac_subfamily_name(style_name)
    full_name = "%s %s" % (family_name, style_name)
    return full_name


def _win_family_name(family_name, style_name):
    name = family_name
    if style_name not in WIN_SAFE_STYLES:
        name = "%s %s" % (family_name, style_name)
    if "Italic" in name:
        name = re.sub(r"Italic", r"", name)
    return name


def _win_subfamily_name(style_name):
    name = style_name
    if "BoldItalic" == name:
        return "Bold Italic"
    elif "Italic" in name:
        return "Italic"
    elif name == "Bold":
        return "Bold"
    else:
        return "Regular"


def set_usWeightClass(style_name):
    name = style_name
    if name != "Italic":
        name = re.sub(r"Italic", r"", style_name)
    return WEIGHTS[name]


def set_macStyle(style_name):
    return MACSTYLE[style_name]


def set_fsSelection(fsSelection, style):
    bits = fsSelection
    if "Regular" in style:
        bits |= 0b1000000
    else:
        bits &= ~0b1000000

    if style in ["Bold", "BoldItalic"]:
        bits |= 0b100000
    else:
        bits &= ~0b100000

    if "Italic" in style:
        bits |= 0b1
    else:
        bits &= ~0b1

    if not bits:
        bits = 0b1000000

    return bits


def nametable_from_filename(filepath):
    """Generate a new nametable based on a ttf and the GF Spec"""
    font = TTFont(filepath)
    old_table = font["name"]
    new_table = newTable("name")
    filename = ntpath.basename(filepath)[:-4]

    family_name, style_name = filename.split("-")
    family_name = _split_camelcase(family_name)

    font_version = font["name"].getName(5, 3, 1, 1033)
    font_version = font_version.toUnicode()
    vendor_id = font["OS/2"].achVendID

    # SET MAC NAME FIELDS
    # -------------------
    # Copyright
    old_cp = old_table.getName(0, 3, 1, 1033).string.decode("utf_16_be")
    new_table.setName(old_cp.encode("mac_roman"), 0, 1, 0, 0)
    # Font Family Name
    new_table.setName(family_name.encode("mac_roman"), 1, 1, 0, 0)
    # Subfamily name
    mac_subfamily_name = _mac_subfamily_name(style_name).encode("mac_roman")
    new_table.setName(mac_subfamily_name, 2, 1, 0, 0)
    # Unique ID
    unique_id = _unique_id(_version(font_version), vendor_id, filename)
    mac_unique_id = unique_id.encode("mac_roman")
    new_table.setName(mac_unique_id, 3, 1, 0, 0)
    # Full name
    fullname = _full_name(family_name, style_name)
    mac_fullname = fullname.encode("mac_roman")
    new_table.setName(mac_fullname, 4, 1, 0, 0)
    # Version string
    old_v = old_table.getName(5, 3, 1, 1033).string.decode("utf_16_be")
    mac_old_v = old_v.encode("mac_roman")
    new_table.setName(mac_old_v, 5, 1, 0, 0)
    # Postscript name
    mac_ps_name = filename.encode("mac_roman")
    new_table.setName(mac_ps_name, 6, 1, 0, 0)

    # SET WIN NAME FIELDS
    # -------------------
    # Copyright
    new_table.setName(old_cp, 0, 3, 1, 1033)
    # Font Family Name
    win_family_name = _win_family_name(family_name, style_name)
    win_family_name = win_family_name.encode("utf_16_be")
    new_table.setName(win_family_name, 1, 3, 1, 1033)
    # Subfamily Name
    win_subfamily_name = _win_subfamily_name(style_name).encode("utf_16_be")
    new_table.setName(win_subfamily_name, 2, 3, 1, 1033)
    # Unique ID
    win_unique_id = unique_id.encode("utf_16_be")
    new_table.setName(win_unique_id, 3, 3, 1, 1033)
    # Full name
    win_fullname = fullname.encode("utf_16_be")
    new_table.setName(win_fullname, 4, 3, 1, 1033)
    # Version string
    win_old_v = old_v.encode("utf_16_be")
    new_table.setName(win_old_v, 5, 3, 1, 1033)
    # Postscript name
    win_ps_name = filename.encode("utf_16_be")
    new_table.setName(win_ps_name, 6, 3, 1, 1033)

    if style_name not in WIN_SAFE_STYLES:
        # Preferred Family Name
        new_table.setName(family_name.encode("utf_16_be"), 16, 3, 1, 1033)
        # Preferred SubfamilyName
        win_pref_subfam_name = _mac_subfamily_name(style_name).encode("utf_16_be")
        new_table.setName(win_pref_subfam_name, 17, 3, 1, 1033)

    # PAD missing fields
    # ------------------
    for field in REQUIRED_FIELDS:
        text = None
        if new_table.getName(*field):
            pass  # Name has already been updated
        elif old_table.getName(*field):
            text = old_table.getName(*field).string
        elif old_table.getName(field[0], 3, 1, 1033):
            text = old_table.getName(field[0], 3, 1, 1033).string.decode("utf_16_be")
        elif old_table.getName(field[0], 1, 0, 0):  # check if field exists for mac
            text = old_table.getName(field[0], 3, 1, 1033).string.decode("mac_roman")

        if text:
            new_table.setName(text, *field)
    return new_table


parser = ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter)
parser.add_argument("fonts", nargs="+")


def main(args=None):
    args = parser.parse_args(args)

    for font_path in args.fonts:
        nametable = nametable_from_filename(font_path)
        font = TTFont(font_path)
        font_filename = ntpath.basename(font_path)

        font["name"] = nametable
        style = font_filename[:-4].split("-")[-1]
        font["OS/2"].usWeightClass = set_usWeightClass(style)
        font["OS/2"].fsSelection = set_fsSelection(font["OS/2"].fsSelection, style)
        win_style = font["name"].getName(2, 3, 1, 1033).string.decode("utf_16_be")
        font["head"].macStyle = set_macStyle(win_style)

        font.save(font_path + ".fix")
        print("font saved %s.fix" % font_path)


if __name__ == "__main__":
    main()
