#!/usr/bin/perl
#---------------------------------------------------------------
# File            : groupfont4xep.pl
# Author          : Camille Bégnis
# Created On      : 2004-11-24
# Copyright       : Camille Bégnis <camille@neodoc.biz>,
#                    NeoDoc under the GPL license
#---------------------------------------------------------------
# synopsis: groupfont4xep.pl --help

# This script searches for AFM and TTF fonts into provided paths. It
# then generates a modified xep.xml configuration file. Optionnaly,
# the script can also output a sample FO file with all found fonts and
# trasform it to PDF. Some details:

# - A "font-group" is created for each parsed directory and for each
# font format (TTF or AFM);
# - By defaults AFM fonts are not embedded;
# - if a PFB or PFA file associated to an AFM file is found, then it
# is added to the font-data definition, and the font is embedded;
# - AFM files are parsed in order to try to determine the font style.
# Fonts are then grouped into the font-family element. 
# - TTF files are assigned a font-family each and are embedded by default.

use strict;
use Getopt::Long;

########################################################################
# initialize variables:
my $app = $0;
my $version = "$app 0.1.0    2004-11-24";
my $verbose = 0;
my ($conf, $out) = "";
# A list of hashes, one hash for each afm font file
my @fonts;
# list of family fonts in all dirs to avoid duplicates
my $allfontnames;
# Fields parsed in AFM files
my @fields=( "FontName" ,"FullName", "FamilyName" );
# New conf file to be written
my $newconffile="xep-new.xml";
# List of unstyled fonts to be used in sample PDF
my @usefonts;
# A hash that associate to each style keyword found in AFM files,
# the corresponding attribute to be used in conf file
my %styles=(
	    "Slanted" => " style=\"oblique\"",
#	    "Unslanted" => " style=\"backslant\"",
	    "Oblique" => " style=\"oblique\"",
	    "Italic" => " style=\"italic\"",
	    "Bold" => " weight=\"bold\"",
	    "Medium" => " weight=\"500\"",
#	    "Light" => " weight=\"light\"",
#	    "Book" => " weight=\"book\"",
	    "Condensed" => " stretch=\"condensed\"",
	    "Extended" => " stretch=\"extended\"",
	    );
# Sample text for PDF output
my $sampletext="A quick brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog. A quick brown fox jumps over the lazy dog. 1234(} ! &#x000C1; &#x000DF; &#x2192;";
my $block=<<END_OF_BLOCK;
          <fo:block text-align="center"
            keep-together.within-column="always">
            <fo:block space-before="12pt" space-after="3pt">Font origin: 
            %ORIG% Family: 
            <fo:wrapper font-weight="bold">%FONT%</fo:wrapper></fo:block>
            <fo:block margin-left="0pt" margin-right="0pt"
              border="0.5pt silver solid" font-family="%FONT%"
              padding="6pt">$sampletext</fo:block>
          </fo:block>\n
END_OF_BLOCK
# FO file header and footer
my $fo_header =<<END_OF_TEXT;
<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="all-pages">
      <fo:region-body region-name="xsl-region-body" margin="0.7in"
      column-gap="0.25in" padding="6pt" column-count="1" />
      <fo:region-before region-name="xsl-region-before"
      extent="0.7in" display-align="after" padding="6pt 0.7in" />
      <fo:region-after region-name="xsl-region-after"
      extent="0.7in" display-align="before" padding="6pt 0.7in" />
    </fo:simple-page-master>
    <fo:page-sequence-master master-name="default-sequence">
      <fo:repeatable-page-master-reference master-reference="all-pages" />
    </fo:page-sequence-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="default-sequence">
    <fo:static-content flow-name="xsl-region-before">
      <fo:list-block font="10pt Helvetica"
      provisional-distance-between-starts="5in"
      provisional-label-separation="0in">
        <fo:list-item>
          <fo:list-item-label end-indent="label-end()">
            <fo:block text-align="start" font-weight="bold">Font Families Samples</fo:block>
          </fo:list-item-label>
          <fo:list-item-body start-indent="body-start()">
            <fo:block text-align="end">Page 
            <fo:page-number /></fo:block>
          </fo:list-item-body>
        </fo:list-item>
      </fo:list-block>
    </fo:static-content>
    <fo:flow flow-name="xsl-region-body">
      <fo:block>
        <fo:block margin-left="0pt" margin-right="0pt"
        font="bold 14pt Helvetica" space-before="18pt"
        space-before.conditionality="discard" space-after="6pt"
        keep-with-next.within-column="always"
        keep-together.within-column="always" text-align="center"
        padding="3pt" background-color="silver">Font Families Samples</fo:block>
        <fo:block font="12pt Times" space-before="6pt"
        space-after="6pt">This document lists all fonts found and
        gives a sample text formatted for each of them.</fo:block>
        <fo:block font="12pt Times" space-before="12pt">
END_OF_TEXT
my $fo_footer =<<END_OF_TEXT;
        </fo:block>
      </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>
END_OF_TEXT
########################################################################

my $usage =<<END_OF_USAGE;
Usage:  $app --help --verbose --version --conf </path/to/xep.xml> --out <sample.pdf> <path1> <path2> ...

Options:
  --help       - shows this text.
  --verbose    - self explaining.
  --version    - shows version number and exits.
  </path/to/xep.xml>   - the full path to XEP configuration file
  <sample.pdf>         - Name of output sample PDF file (optional)
  <path1> <path2> ...  - The paths where to search for fonts

END_OF_USAGE
sub parse_command_line {
  my ($opt_help, $opt_verbose, $opt_version);
  my $result = GetOptions(
                          'help'        => \$opt_help,
                          'conf=s'      => \$conf,
                          'out=s'       => \$out,
                          'version'     => \$opt_version,
                          'verbose!'    => \$opt_verbose,
               );

  die "$version\n" if defined $opt_version;
  die $usage if ( (not $conf) || $opt_help );
  die "I can't read configuration file $conf" unless -f $conf;

  $verbose  = $opt_verbose if defined $opt_verbose;
}
parse_command_line;


# Build XML config file
my $fontselement="";
print "   Searching for fonts...\n";
# parse Font files
foreach my $path (@ARGV) {
    print STDERR "Entering $path\n" if $verbose;
    my @fontnames;
# We will first take care of AFM fils
    my @filenames=glob "$path/*.afm";
    foreach my $file (@filenames) {
	print STDERR " $file" if $verbose;
	my %font;
	open (f, "<$file");
	$file=~s,.*/,,;
	$font{"file"}=$file;
	while (<f>) {
	    foreach my $field (@fields) {
		if (/^$field /) {
		    chomp;
		    s/$field //;
		    if ( "$field" eq "FontName" ) {
			s/-.*//;
			s/\W//g;
#			print "$field $_\n" if $verbose;
			unless ( $allfontnames=~/,$_,/ ) {
			    push @fontnames, $_ ;
			    $allfontnames.=",$_,";
			}
		    }
		    $font{"$field"}=$_;
#		    print "$file $_\n" if $verbose;
		}
	    }
	    last if /^StartCharMetrics/;
	}
	close f;
	push @fonts, {%font};
    }

    $fontselement.="<font-group xml:base=\"file://$path\" label=\"$path AFM\" embed=\"false\">\n";

# ugly hack to process al font families together
    foreach my $font (sort @fontnames) {
	print STDERR "Processing font $font" if $verbose;
	my $usefont=0;
	$fontselement.="<font-family name=\"$font\">\n";
	foreach my $fontfields (@fonts) {
	    if ( $fontfields->{FontName} eq $font ) {
		$fontselement.="  <font";
		$_=$fontfields->{FullName};
		my $hasstyle=0;
# setup font attributes
		foreach my $keyword (keys %styles) {
		    if ( /\b$keyword\b/ ) {
			$fontselement.=$styles{$keyword};
			$hasstyle=1;
		    }
#		    print $hasstyle;
		}
		$usefont=1 unless ( $hasstyle );
# test PFB or PFA files to embed font or not (activate subset by default)
		my $namefile=$fontfields->{file};
		$namefile=~s/\.afm$//;
		my $pfa=( -e "$path/$namefile.pfa" );
		my $pfb=( -e "$path/$namefile.pfb" );
		$fontselement.="  embed=\"true\" subset=\"true\"" if ( $pfa or $pfb );
		$fontselement.="><font-data afm=\"$fontfields->{file}\"";
		$fontselement.=" pfa=\"$namefile.pfa\"" if $pfa;
		$fontselement.=" pfb=\"$namefile.pfb\"" if $pfb;
		$fontselement.="/></font>\n";
	    }
	}
	push (@usefonts, "$path/$font") if $usefont;
	$fontselement.="</font-family>\n";
    }
    $fontselement.="</font-group>\n\n";

# let's now process TTF files
    @filenames=glob "$path/*.ttf";
    if ( $#filenames >= 0 ) {
	$fontselement.="<font-group xml:base=\"file://$path\" label=\"$path TTF\" embed=\"true\" subset=\"true\">\n";
	foreach my $file (@filenames) {
	    $file=~s,.*/,,;
	    my $font=$file;
	    $font=~s/\.ttf$//;
	    push (@usefonts, "$path/$font");
	    $fontselement.="<font-family name=\"$font\">\n";
	    $fontselement.="  <font><font-data ttf=\"$file\"/></font>\n";
	    $fontselement.="</font-family>\n";
	}
	$fontselement.="</font-group>\n\n";
    }
}

# Now let's insert those new(?) fonts in the configuration file
print "\n   Writing new configuration file in $newconffile ...\n";
my $newconf="";
open (CONF, "<$conf") || die "Read error: \"$conf\" $!\n";
while (<CONF>) {
    if ( /<\/fonts>/ ) { 
	$newconf.="\n\n<!-- Automatic fonts definitions start here -->\n\n";
	$newconf.=$fontselement;
	$newconf.="\n\n<!-- Automatic fonts definitions end here -->\n\n";
    }
    $newconf.=$_;
}
close CONF;
open (CONF, ">$newconffile") || die "Write error: \"$newconffile\" $!\n";
print CONF $newconf;
close CONF;

# let's generate sample PDF if requested
unless ( $out eq "" ) {
    print "   Generating sample PDF in $out ...\n";
    open (OUT, ">$out.fo") || die "Write error: \"$out.fo\" $!\n";
    print OUT $fo_header;

    foreach my $font (@usefonts) {
	print STDERR "Generating sample for font $font\n" if $verbose;
	$font=~s,(.*)/+,,;
	my $path=$1;
	my $newblock=$block;
	$newblock=~ s/%FONT%/$font/g;
	$newblock=~ s/%ORIG%/$path/g;
	print OUT $newblock;
    }
    print OUT $fo_footer;
    close OUT;

    my @xepargs=("xep",
		 "-DCONFIG=$newconffile",
		 "-fo","$out.fo",
		 "-pdf","$out",
		 );
    system(@xepargs) == 0
	or die "XEP call:\n@xepargs\nfailed: $?"

}

