#! /usr/bin/env python

##############################################
# Extract each lucide-icons symbol to a      #
# separate PDF file.                         #
#                                            #
# In fact, this script creates only a Ninja  #
# build file to perform the operation.       #
#                                            #
# Author: Scott Pakin <scott-clsl@pakin.org> #
##############################################

import glob
import os
import re
import subprocess
import sys
import textwrap


def kpsewhich(fname):
    'Find a filename in the TeX tree.'
    proc = subprocess.run(['kpsewhich', fname], capture_output=True,
                          check=False, encoding='utf-8')
    if proc.returncode != 0:
        return None
    return proc.stdout.strip()


def header_string():
    'Return a "generated file" header string.'
    full_name = os.path.abspath(sys.argv[0])
    gen_line = 'This is a generated file.  DO NOT EDIT.'
    edit_line = f'Edit {full_name} instead.'
    max_chars = max(len(gen_line), len(edit_line))
    hash_line = '#' * (max_chars + 4)
    return '\n'.join([
        hash_line,
        '# %-*.*s #' % (max_chars, max_chars, gen_line),
        '# %-*.*s #' % (max_chars, max_chars, edit_line),
        hash_line,
        '',
    ])


def parse_sty_file(source_sty):
    '''Parse lucide-icons.sty into a dictionary mapping page number to
    icon name.'''
    num2name = {}
    generate_re = re.compile(r'^\\GenerateLucideIcons\{(\d+)\}\{([^\}]+)\}')
    with open(source_sty) as r:
        for ln in r:
            match = generate_re.match(ln)
            if match is None:
                continue
            num2name[int(match[1])] = match[2]
    return num2name


# Generate a Ninja file that extracts each page of lucide-icons-all.pdf into a
# separate file.
with open('lucide-icons.ninja', 'w') as w:
    # Write the header string then stop if lucide-icons-all.pdf is unavailable.
    w.write(header_string())
    source_pdf = kpsewhich('lucide-icons-all.pdf')
    if source_pdf is None:
        w.write('')
        w.write('build LUCIDE-ICONS : phony\n')
        sys.exit(0)

    # Define a rule that converts lucide-icons.sty to fakelucide-icons.sty.
    source_sty = kpsewhich('lucide-icons.sty')
    if source_sty is None:
        raise FileNotFoundError('No such file lucide-icons.sty')
    full_name = os.path.abspath(sys.argv[0])
    w.write(rf'''
rule fake-lucide-icons-sty
  command = $
    echo '%% This is a generated file.  DO NOT EDIT.' > $out ; $
    echo '%% Edit {full_name} instead.' >> $out ; $
    echo '' >> $out ; $''')
    w.write(r'''
    /bin/echo '\DeclareRobustCommand*{\lucideicon}[1]{%' >> $out ; $
    /bin/echo '  \raisebox{-2pt}{%' >> $out ; $
    /bin/echo '    \includegraphics[height=10pt]{lucide-icons/#1}%' >> $out ; $
    /bin/echo '  }%' >> $out ; $
    /bin/echo '}%' >> $out ; $
    /bin/echo '' >> $out ; $
    /bin/echo '\endinput' >> $out
  description = Generate $out from lucide-icons.sty

''')

    # Invoke the preceding rule.
    w.write(f'build fakelucide-icons.sty : fake-lucide-icons-sty {source_sty}\n')

    # Define a rule that extracts a single page of lucide-icons-all.pdf into a
    # separate file.
    w.write(f'''
rule extract-pdf-page
  command = pdfseparate -f $page -l $page $in 'lucide-icons/${{name}}.pdf'
  description = Extracting page $page from lucide-icons-all.pdf

''')

    # Invoke the preceding rule once for each page of lucide-icons-all.pdf.
    num_to_name = parse_sty_file(source_sty)
    for num, name in sorted(num_to_name.items()):
        w.write(f'build lucide-icons/{name}.pdf : extract-pdf-page {source_pdf}\n')
        w.write(f'  page = {num}\n')
        w.write(f'  name = {name}\n')
    w.write('\n')

    # Define a phony rule that depends on fakelucide-icons.sty and all of the
    # output files.
    w.write('build LUCIDE-ICONS : phony $\n')
    phony = [f'lucide-icons/{name}.pdf'
             for name in sorted(num_to_name.values())] + \
            ['fakelucide-icons.sty']
    lines = textwrap.wrap(' '.join(phony),
                          width=77,
                          break_long_words=False, break_on_hyphens=False,
                          initial_indent='  ', subsequent_indent='  ')
    w.write('%s\n' % ' $\n'.join(lines))
