#!/usr/bin/env python3
# coding=utf8

import sys
import os
import re
import subprocess
import fontforge

# Double-quotes required here, for version-bump.sh:
# version-bump.sh is not working here, need to adjust manually!
version = "3.0.0"

archive = 'v18.3.0.tar.gz'

vectorsdir = 'icons'
fontdir = '.'
fontfile = 'octicons.ttf'
glyphsetfile = 'i_oct.sh'
glyphsetsdir = '../../../bin/scripts/lib'

subset = '-16' # use 16 px subset if possible
subset_other = '-24' # use 24 px subset otherwise

def renamer(old_name):
    """ Return new equivalent icon name """
    return {
            'trashcan' : 'trash',
            'cloud-download' : 'download',
            'cloud-upload' : 'upload',
            'clippy' : 'paste',
            'mail-read' : 'read',
            'primitive-dot' : 'dot-fill',
            'primitive-square' : 'square-fill',
            'settings' : 'sliders',
            'dashboard' : 'meter',
            'paintcan' : 'paintbrush',
        }.get(old_name, old_name)

def addIcon(codepoint, name, filename):
    """ Add one outline file and rescale/move """
    dBB = [120, 0, 1000-120, 900] # just some nice sizes
    filename = os.path.join(vectorsdir, filename)
    glyph = font.createChar(codepoint, name)
    glyph.importOutlines(filename)
    glyph.manualHints = True

def createGlyphInfo(icon_datasets, filepathname, into):
    """ Write the glyphinfo file """
    with open(filepathname, 'w', encoding = 'utf8') as f:
        f.write(u'#!/usr/bin/env bash\n')
        f.write(intro)
        f.write(u'# Script Version: (autogenerated)\n')
        f.write(u'test -n "$__i_oct_loaded" && return || __i_oct_loaded=1\n')
        for _, codepoint, name in icon_datasets:
            codepoint = int(codepoint, 16)
            f.write(u"i='{}' i_oct_{}=$i\n".format(chr(codepoint), name.replace('-', '_')))
        f.write(u'unset i\n')

print('\nReading mapping file')
old_mapping = []
with open('mapping', 'r') as f:
    for line in f.readlines():
        if line.startswith('#'):
            continue
        old_mapping.append(tuple(re.split(' +', line.strip())))
print('Found {} entries'.format(len(old_mapping)))
old_mapping.sort(key=(lambda x: x[0]))

print('Fetching octicons archive "{}"\n'.format(archive))
if subprocess.call('curl -OL https://github.com/primer/octicons/archive/' + archive, shell=True):
    sys.exit('Error fetching octicons archive')
print('\nUnpacking octicons archive')
if subprocess.call('rm -rf icons octicons-* && tar zxf *.gz && mv octicons-*/icons . && rm -rf octicons-* && cp file-symlink-directory-*.svg icons', shell=True):
    sys.exit('Error unpacking archive')

svgs = os.listdir(vectorsdir)
print('Found {} svgs'.format(len(svgs)))
names = { s[0:-len('-xx.svg')] for s in svgs if s.endswith(subset + '.svg') or s.endswith(subset_other + '.svg') }
print('Found {} icons after de-duplicating\n'.format(len(names)))

num_found = 0
num_missing = 0
misslist = ''
renamelist = ''
freeslots = []

new_mapping = []
for i, j, old_n in old_mapping:
    if old_n in names:
        names.remove(old_n)
        new_mapping.append((i, j, old_n))
        num_found += 1
        continue
    new_n = renamer(old_n)
    if new_n in names:
        renamelist += 'Renamed {} -> {}\n'.format(old_n, new_n)
        names.remove(new_n)
        new_mapping.append((i, j, new_n))
        num_found += 1
        continue
    misslist += 'Missing {}\n'.format(old_n)
    freeslots.append((i, j))
    num_missing += 1

print(renamelist)
print(misslist)
print('Found {} (of {}, missing {}) and new {}'.format(num_found, len(old_mapping), num_missing, len(names)))

names = list(names)
names.sort()
for n in list(names):
    if len(freeslots) == 0:
        break
    i, j = freeslots[0]
    new_mapping.append((i, j, n))
    names.remove(n)
    freeslots = freeslots[1:]

print('Filled in missing, remaining new {}'.format(len(names)))

i_max = 0
j_max = 0
for i, j, _ in new_mapping:
    i = int(i, 16)
    j = int(j, 16)
    if i > i_max:
        i_max = i
    if j > j_max:
        j_max = j

for n in names:
    i_max += 1
    j_max += 1
    new_mapping.append(('{:X}'.format(i_max), '{:X}'.format(j_max), n))

print('Appended remaining new, total new mapping {}'.format(len(new_mapping)))

new_mapping.sort(key=(lambda x: x[0]))
with open('mapping', 'w') as f:
    for i, j, n in new_mapping:
        f.write('{} {} {}\n'.format(i, j, n))

font = fontforge.font()
font.fontname = 'OcticonsNerdFont-Regular'
font.fullname = 'Octicons Nerd Font Regular'
font.familyname = 'Octicons Nerd Font'
font.em = 2048
font.encoding = 'UnicodeFull'

# Add valid space glyph to avoid "unknown character" box on IE11
glyph = font.createChar(32)
glyph.width = 200

font.sfntRevision = None # Auto-set (refreshed) by fontforge
font.version = version
font.copyright = 'GitHub Inc.'
font.appendSFNTName('English (US)', 'Version', archive + '; ' + version)
font.appendSFNTName('English (US)', 'Vendor URL', 'https://github.com/ryanoasis/nerd-fonts')
font.appendSFNTName('English (US)', 'Copyright', 'GitHub Inc.')

for codepoint, _, name in new_mapping:
    codepoint = int(codepoint, 16)
    filename = name + subset + '.svg'
    if filename not in svgs:
        filename = name + subset_other + '.svg'
    addIcon(codepoint, name, filename)

num_icons = len(new_mapping)

print('Generating {} with {} glyphs'.format(fontfile, num_icons))
font.generate(os.path.join(fontdir, fontfile), flags=("no-FFTM-table",))

codepoints = [ int(p, 16) for _, p, _ in new_mapping ]
intro  = u'# Octicons ({} icons)\n'.format(num_icons)
intro += u'# Codepoints: {:X}-{:X} with gaps\n'.format(min(codepoints), max(codepoints))
intro += u'# Nerd Fonts Version: {}\n'.format(version)

print('Generating GlyphInfo {}'.format(glyphsetfile))
createGlyphInfo(new_mapping, os.path.join(glyphsetsdir, glyphsetfile), intro)
print('Finished')
