#! /usr/bin/env python3
# This file is part of the Gentium package for TeX.
# It is licensed under the Expat License, see doc//README for details.
# author: Pavel Farar, pavel.farar@centrum.cz
#
# This script generates extra kerning pairs for the
# combination accent + capital Greek letter. The kerning
# pairs will have such a value that the combination will
# look like the precomposed accented letter (with the
# exception of the left side bearing). The input must be
# a fontforge source (sfd file) and the output will have
# the same form as kerning pairs in the afm file
#
# The main idea is that the fontforge source contains the
# information how the accented letter is composed from the
# accent and the base letter. The relevant information is
# the width of the accent and the position of the accent
# and the base letter (how they are moved from the position
# X = 0). The kerning is computed using the following formula:
#
# Kern = X_letter - X_accent - WidthOfAccent
#
# This script is dirtier than it could be. The
# reason is that it should work with different fonts,
# but some fonts have problems. There is a problem
# with the letter Omega in GentiumPlus which has not
# the usual unicode value. In DejaVu the precomposed
# letters are composed sometimes as accent + letter,
# but sometimes also as letter + accent.

import sys

# Table with LIGKERNs for Greek capital letters, where
# first (accent) + second (letter) gives third (accented
# letter.  Well, probably not the best term, but I created
# the following table to a great extent automatically
# from the LIGKERN commands for the precomposed small Greek
# accented letters in the encoding LGR. Then I did uppercasing
# using information from Unicode and looked if there is
# some accented letter missing. Therefore I call it
# LigatureTable and this file uses one line for every
# capital Greek letter. I did it in such a way to avoid
# random errors.
LigatureTable = []

LigatureTable.append(['uni1FBF', 'Alpha', 'uni1F08'])
LigatureTable.append(['uni1FBF', 'Epsilon', 'uni1F18'])
LigatureTable.append(['uni1FBF', 'Eta', 'uni1F28'])
LigatureTable.append(['uni1FBF', 'Iota', 'uni1F38'])
LigatureTable.append(['uni1FBF', 'Omicron', 'uni1F48'])
LigatureTable.append(['uni1FBF', 'Omega', 'uni1F68'])
LigatureTable.append(['uni1FFE', 'Alpha', 'uni1F09'])
LigatureTable.append(['uni1FFE', 'Epsilon', 'uni1F19'])
LigatureTable.append(['uni1FFE', 'Eta', 'uni1F29'])
LigatureTable.append(['uni1FFE', 'Iota', 'uni1F39'])
LigatureTable.append(['uni1FFE', 'Omicron', 'uni1F49'])
LigatureTable.append(['uni1FFE', 'Upsilon', 'uni1F59'])
LigatureTable.append(['uni1FFE', 'Omega', 'uni1F69'])
LigatureTable.append(['uni1FFE', 'Rho', 'uni1FEC'])
LigatureTable.append(['uni1FCD', 'Alpha', 'uni1F0A'])
LigatureTable.append(['uni1FCD', 'Epsilon', 'uni1F1A'])
LigatureTable.append(['uni1FCD', 'Eta', 'uni1F2A'])
LigatureTable.append(['uni1FCD', 'Iota', 'uni1F3A'])
LigatureTable.append(['uni1FCD', 'Omicron', 'uni1F4A'])
LigatureTable.append(['uni1FCD', 'Omega', 'uni1F6A'])
LigatureTable.append(['uni1FDD', 'Alpha', 'uni1F0B'])
LigatureTable.append(['uni1FDD', 'Epsilon', 'uni1F1B'])
LigatureTable.append(['uni1FDD', 'Eta', 'uni1F2B'])
LigatureTable.append(['uni1FDD', 'Iota', 'uni1F3B'])
LigatureTable.append(['uni1FDD', 'Omicron', 'uni1F4B'])
LigatureTable.append(['uni1FDD', 'Upsilon', 'uni1F5B'])
LigatureTable.append(['uni1FDD', 'Omega', 'uni1F6B'])
LigatureTable.append(['uni1FCE', 'Alpha', 'uni1F0C'])
LigatureTable.append(['uni1FCE', 'Epsilon', 'uni1F1C'])
LigatureTable.append(['uni1FCE', 'Eta', 'uni1F2C'])
LigatureTable.append(['uni1FCE', 'Iota', 'uni1F3C'])
LigatureTable.append(['uni1FCE', 'Omicron', 'uni1F4C'])
LigatureTable.append(['uni1FCE', 'Omega', 'uni1F6C'])
LigatureTable.append(['uni1FDE', 'Alpha', 'uni1F0D'])
LigatureTable.append(['uni1FDE', 'Epsilon', 'uni1F1D'])
LigatureTable.append(['uni1FDE', 'Eta', 'uni1F2D'])
LigatureTable.append(['uni1FDE', 'Iota', 'uni1F3D'])
LigatureTable.append(['uni1FDE', 'Omicron', 'uni1F4D'])
LigatureTable.append(['uni1FDE', 'Upsilon', 'uni1F5D'])
LigatureTable.append(['uni1FDE', 'Omega', 'uni1F6D'])
LigatureTable.append(['uni1FCF', 'Alpha', 'uni1F0E'])
LigatureTable.append(['uni1FCF', 'Eta', 'uni1F2E'])
LigatureTable.append(['uni1FCF', 'Iota', 'uni1F3E'])
LigatureTable.append(['uni1FCF', 'Omega', 'uni1F6E'])
LigatureTable.append(['uni1FDF', 'Alpha', 'uni1F0F'])
LigatureTable.append(['uni1FDF', 'Eta', 'uni1F2F'])
LigatureTable.append(['uni1FDF', 'Iota', 'uni1F3F'])
LigatureTable.append(['uni1FDF', 'Upsilon', 'uni1F5F'])
LigatureTable.append(['uni1FDF', 'Omega', 'uni1F6F'])
LigatureTable.append(['uni1FEF', 'Alpha', 'uni1FBA'])
LigatureTable.append(['uni1FEF', 'Epsilon', 'uni1FC8'])
LigatureTable.append(['uni1FEF', 'Eta', 'uni1FCA'])
LigatureTable.append(['uni1FEF', 'Iota', 'uni1FDA'])
LigatureTable.append(['uni1FEF', 'Omicron', 'uni1FF8'])
LigatureTable.append(['uni1FEF', 'Upsilon', 'uni1FEA'])
LigatureTable.append(['uni1FEF', 'Omega', 'uni1FFA'])
LigatureTable.append(['tonos', 'Alpha', 'Alphatonos'])
LigatureTable.append(['tonos', 'Epsilon', 'Epsilontonos'])
LigatureTable.append(['tonos', 'Eta', 'Etatonos'])
LigatureTable.append(['tonos', 'Iota', 'Iotatonos'])
LigatureTable.append(['tonos', 'Omicron', 'Omicrontonos'])
LigatureTable.append(['tonos', 'Upsilon', 'Upsilontonos'])
LigatureTable.append(['tonos', 'Omega', 'Omegatonos'])


# Set with Greek accents
GreekAccents = set()  # empty set
for i in range(len(LigatureTable)):
    GreekAccents.add(LigatureTable[i][0])

# Set with Greek letters
GreekLetters = set()  # empty set
for i in range(len(LigatureTable)):
    GreekLetters.add(LigatureTable[i][1])

# Set with precomposed Greek letters
PrecomposedGreekLetters = set()  # empty set
for i in range(len(LigatureTable)):
    PrecomposedGreekLetters.add(LigatureTable[i][2])


def UnicodeValue(s):
    # The unicode value is the second number after "Encoding:"
    if s.find('Encoding:') != 0:
        sys.exit('UnicodeValue error')
    return s.split()[2]  # The third item


def WidthValue(s):
    if s.find('Width:') != 0:
        sys.exit('WidthValue error')
    return s.split()[1]  # The second item


# Dictionaries (all values are strings, not numbers!)
AccentWidth = {}
AccentUnicode = {}
LetterUnicode = {}


# Process the components (accents and base letters)
f = open(sys.argv[1], 'r')
farray = f.readlines()
f.close()
findex = -1
while True:
    findex = findex + 1
    if findex >= len(farray):
        break  # end of file
    s = farray[findex]
    if s.find('StartChar: ') == 0:
        CharacterName = s[11:-1]
        if CharacterName in GreekLetters:
            findex = findex + 1
            s = farray[findex]
            LetterUnicode[CharacterName] = UnicodeValue(s)
        if CharacterName in GreekAccents:
            findex = findex + 1
            s = farray[findex]
            AccentUnicode[CharacterName] = UnicodeValue(s)
            findex = findex + 1
            s = farray[findex]
            AccentWidth[CharacterName] = WidthValue(s)


def MoveValue(ss, lindex):
    sarray = ss.split()
    if sarray[0] != 'Refer:':
        sys.exit('No Refer:')
    x = int(sarray[8])  # the value of move

    # dirty hack to make Omega work in both Gentium and GentiumPlus
    # This script without the following hack would work well for Gentium, but not for
    # GentiumPlus. The problem with GentiumPlus is that the accented letters with Omega
    # uses as a base letter that with the unicode value 937 (which should be Omega), but
    # this letter has PostScript name uni03A9, not Omega. Omega has a different value.
    if (
        sarray[2] == '937'
    ):  # the standard unicode value for Omega = problems in GentiumPlus
        sarray[2] = LetterUnicode['Omega']

    # is it accent or letter?
    # unicode is the second number (third value)
    if sarray[2] == AccentUnicode[LigatureTable[lindex][0]]:  # accent
        x = -x  # the move of accent is taken negatively
    elif sarray[2] == LetterUnicode[LigatureTable[lindex][1]]:  # letter
        x = +x  # the move of letter is taken positively
    else:
        sys.exit('Bad unicode of component')

    return x


def KernValue(letter, s1, s2):
    # letter	- the name of the precomposed letter
    # s1		- Refer to the accent (expected to be first)
    # s2		- Refer to the letter
    for i in range(len(LigatureTable)):
        if LigatureTable[i][2] == letter:
            LetterIndex = i

    FirstMove = MoveValue(s1, LetterIndex)
    SecondMove = MoveValue(s2, LetterIndex)

    return FirstMove + SecondMove - int(AccentWidth[LigatureTable[LetterIndex][0]])


KernTable = {}

# Process the precomposed letters
# The sfd file is still in "farray"
findex = -1
while True:
    findex = findex + 1
    if findex >= len(farray):
        break  # end of file
    s = farray[findex]
    if s.find('StartChar: ') == 0:
        CharacterName = s[11:-1]
        if CharacterName in PrecomposedGreekLetters:
            while s.find('Refer: ') != 0:
                findex = findex + 1
                s = farray[findex]
            KernTable[CharacterName] = KernValue(CharacterName, s, farray[findex + 1])


# Write the kerning table
fafm = open(sys.argv[1][:-4] + '-extra.afm', 'w')
for i in range(len(LigatureTable)):
    sourceKern = KernTable[LigatureTable[i][2]]
    if sourceKern != 0:  # remove zero kerns
        fafm.write(
            'KPX '
            + LigatureTable[i][0]
            + ' '
            + LigatureTable[i][1]
            + ' '
            + str(int(round(1000.0 / 2048.0 * sourceKern)))
            + '\n'
        )
fafm.close()
