#!/usr/bin/env php
<?php
/**
 * bulk_convert.php
 *
 * @since       2015-11-30
 * @category    Library
 * @package     PdfFont
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2011-2026 Nicola Asuni - Tecnick.com LTD
 * @license     https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
 * @link        https://github.com/tecnickcom/tc-lib-pdf-font
 *
 * This file is part of tc-lib-pdf-font software library.
 *
 * Command-line tool to convert fonts data for the tc-lib-pdf-font library in bulk.
 */

if (\php_sapi_name() != 'cli') {
    \fwrite(STDERR, 'You need to run this command from console.'."\n");
    exit(1);
}

/**
 * Display help guide for this command.
 */
function showHelp()
{
    $help = <<<EOD

bulk_convert - Command-line tool to convert fonts data for the tc-lib-pdf-font library.

Usage:
    bulk_convert.php [ options ]

Options:

    -o, --outpath
        Output path for generated font files (must be writeable by the
        web server). Leave empty for default font folder.

    -h, --help
        Display this help and exit.

EOD;
    \fwrite(STDOUT, $help);
    exit(0);
}

// initialize the array of options
$options = array('outpath' => \dirname(__DIR__).'/target/fonts/');

// short input options
$sopt = 'o:';

// long input options
$lopt = array('outpath:');

// parse input options
$inopt = \getopt($sopt, $lopt);

// import options (with some sanitization)
foreach ($inopt as $opt => $val) {
    // getopt() hands over an array when the same option is repeated: the last occurrence
    // wins, so that a repeated option is not passed on to a function expecting a string.
    if (\is_array($val)) {
        $val = \end($val);
    }

    switch ($opt) {
        case 'o':
        case 'outpath':
            // realpath() returns false for a missing directory: in that case the
            // raw value is kept and normalized below, after the directory is created.
            $resolved = \realpath($val);
            $options['outpath'] = ($resolved !== false) ? $resolved : $val;
            if (\substr($options['outpath'], -1) != '/') {
                $options['outpath'] .= '/';
            }
            break;
        case 'h':
        case 'help':
        default:
            showHelp();
            break;
    }
}

// check input values
if (!is_dir($options['outpath'])) {
    \mkdir($options['outpath'], 0755, true);
}
if (!is_dir($options['outpath']) || !\is_writable($options['outpath'])) {
    \fwrite(STDERR, 'ERROR: Can\'t write to '.$options['outpath']."\n\n");
    exit(2);
}

$ttfdir = __DIR__.'/vendor/tecnickcom/tc-font-mirror/';
if (!is_dir($ttfdir)) {
    \fwrite(STDERR, 'ERROR: The '.$ttfdir.' directory is empty, please execute \'make build\' before this command.'."\n\n");
    exit(3);
}

\fwrite(STDOUT, "\n".'>>> Converting fonts:'."\n".'*** Output directory set to '.$options['outpath']."\n");

// count conversions
$convert_errors = 0;
$convert_success = 0;

// locate the Composer autoloader of a standalone checkout or of a host project
$autoloadFound = false;
foreach (
    array(
        \dirname(__DIR__) . '/vendor/autoload.php',    // standalone repository checkout
        \dirname(__DIR__, 4) . '/vendor/autoload.php', // installed under <project>/vendor/tecnickcom/tc-lib-pdf-font
    ) as $autoloadFile
) {
    if (\is_file($autoloadFile)) {
        require_once $autoloadFile;
        $autoloadFound = true;
        break;
    }
}

if (!$autoloadFound) {
    \fwrite(STDERR, 'ERROR: Composer autoloader not found. Run "composer install" first.'."\n\n");
    exit(5);
}

// scandir() returns false for a directory it cannot read, which array_diff() would
// reject with a TypeError instead of the message below
$entries = \scandir($ttfdir);
if ($entries === false) {
    \fwrite(STDERR, 'ERROR: Unable to read the '.$ttfdir.' directory.'."\n\n");
    exit(6);
}

$fontdir = \array_diff($entries, array('.', '..', '.git'));

// URL of websites containing the font sources
$font_url = array(
    'cid0'     => 'http://unifoundry.com/unifont.html',
    'core'     => 'https://partners.adobe.com/public/developer/en/pdf/Core14_AFMs.zip',
    'dejavu'   => 'http://sourceforge.net/projects/dejavu/files/dejavu/2.35/dejavu-fonts-ttf-2.35.zip',
    'freefont' => 'https://ftp.gnu.org/gnu/freefont/freefont-ttf-20120503.zip',
    'pdfa'     => 'https://github.com/tecnickcom/tc-font-pdfa',
    'unifont'  => 'http://unifoundry.com/unifont.html',
);

foreach ($fontdir as $dir) {
	$indir = $ttfdir.$dir;
    if (!is_dir($indir)) {
        continue;
    }
    // search font files in sub directories
    $all_files  = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($indir));
    $fonts = \iterator_to_array(new RegexIterator($all_files, '/\.ttf$/'));
    $fonts = \array_merge($fonts, \iterator_to_array(new RegexIterator($all_files, '/\.pfb$/')));
    $fonts = \array_merge($fonts, \iterator_to_array(new RegexIterator($all_files, '/\.otf$/')));
    if (empty($fonts)) {
        $fonts = \iterator_to_array(new RegexIterator($all_files, '/\.afm$/'));
    }
    if (empty($fonts)) {
        continue;
    }

    // build output path directory
    $outdir = $options['outpath'].$dir.'/';
    if (!is_dir($outdir)) {
        \mkdir($outdir, 0755, true);
    }
    if (\is_readable($indir.'/LICENSE')) {
        \copy($indir.'/LICENSE', $outdir.'LICENSE');
    } else {
        \fwrite(STDERR, "\033[33m".'!!! WARN : no LICENSE file in '.$indir."\033[m\n");
    }

    // generate a README file
    $readme = '# '.$dir.' font files for tc-lib-pdf-font'."\n\n"
        .'This folder contains font files and/or font data extracted from:'."\n"
        .($font_url[$dir] ?? 'an unlisted source')."\n"
        .'using the "bulk_convert.php" utility in https://github.com/tecnickcom/tc-lib-pdf-font'."\n\n"
        .'The original files (if present) have been renamed and compressed using the ZLIB data format (.z files).'."\n"
        .'The font files are subject to the conditions stated in the LICENSE file.'."\n"
        .'For further information please consult the original documentation at the link above.'."\n";
    \file_put_contents($outdir.'README', $readme);

    foreach ($fonts as $font) {
        if (\substr($font, -4) == '.otf') {
            // OTF fonts are unsupported: convert them to TTF using FontForge
            // escapeshellarg (not escapeshellcmd): $font is a single argument and may
            // contain spaces, which escapeshellcmd would leave unquoted
            \system('fontforge -script otf2ttf.ff '.\escapeshellarg((string) $font), $err);
            if ($err != 0) {
                \fwrite(STDERR, "\033[31m".'Unable to convert: '.$font."\033[m");
                continue;
            }
            $font = \substr($font, 0, -4).'.ttf';
        }
        
        $type = '';
        $encoding = '';
        if ($dir == 'cid0') {
            $type = \strtoupper(\basename($font, '.ttf'));
        } elseif (($dir == 'core') || ($dir == 'pdfa')) {
            if (\strpos($font, 'Symbol') !== false) {
                $encoding = 'symbol';
            } elseif (\strpos($font, 'ZapfDingbats') === false) {
                $encoding = 'cp1252';
            }
        }
        try {
            $import = new \Com\Tecnick\Pdf\Font\Import(
                \realpath($font),
                $outdir,
                $type,
                $encoding
            );
            $fontname = $import->getFontName();
            \fwrite(STDOUT, "\033[32m".'+++ OK   : '.$font.' added as '.$fontname."\033[m\n");
            ++$convert_success;
        } catch (\Exception $exc) {
            ++$convert_errors;
            \fwrite(STDERR, "\033[31m".'--- ERROR: can\'t add '.$font."\n           ".$exc->getMessage()."\033[m\n");
        }
    }
}

$endmsg = '>>> PROCESS COMPLETED: '.$convert_success.' CONVERTED FONT(S), '.$convert_errors.' ERROR(S)!'."\n\n";

if ($convert_errors > 0) {
    \fwrite(STDERR, "\033[31m".$endmsg.'ERROR'."\033[m");
    exit(4);
}

\fwrite(STDOUT, "\033[32m".$endmsg."\033[m");
exit(0);

