@ACCEPT_CATEGORIES = qw(truetype cid cmap);

package x_ttcidfont_conf;
use strict;
use POSIX;

use vars qw($DEFOMA_TEST_DIR $ROOTDIR);

use Debian::Defoma::Common;
use Debian::Defoma::Font;
use Debian::Defoma::Id;
import Debian::Defoma::Font;
import Debian::Defoma::Id;
import Debian::Defoma::Common;

my ($Id, $IdCmap, $IdSub);

my $configfile = "$DEFOMA_TEST_DIR/etc/defoma/config/x-ttcidfont-conf.conf";
my $PkgDir = "$ROOTDIR/x-ttcidfont-conf.d";
my $FontRootDir = "$PkgDir/dirs";
my $Method;
my @AliasSize = qw(8 10 12 14 16 18 20 22 24 26 28 30 32);
my %SpacingC;
my $Spacing;
my $VL;

sub get_xlfd_element {
    my $h = shift;
    my $ret = {};

    $ret->{Foundry} = 'unknown';
    $ret->{Foundry} = $h->{'Foundry'} if (exists($h->{'Foundry'}));
    $ret->{Foundry} = $h->{'X-Foundry'} if (exists($h->{'X-Foundry'}));

    $ret->{Family} = 'unknown';
    $ret->{Family} = $h->{'FontName'} if (exists($h->{'FontName'}));
    $ret->{Family} = $h->{'Family'} if (exists($h->{'Family'}));
    $ret->{Family} = $h->{'X-Family'} if (exists($h->{'X-Family'}));


    $ret->{Weight} = 'medium';
    $ret->{Weight} = $h->{'Weight'} if (exists($h->{'Weight'}));
    $ret->{Weight} = $h->{'X-Weight'} if (exists($h->{'X-Weight'}));

    $ret->{Slant} = 'r';
    $ret->{Slant} = 'o' if
	(exists($h->{'Shape'}) && $h->{'Shape'} =~ /Oblique/);
    $ret->{Slant} = 'i' if
	(exists($h->{'Shape'}) && $h->{'Shape'} =~ /Italic/);
    $ret->{Slant} = $h->{'X-Slant'} if (exists($h->{'X-Slant'}));

    $ret->{SetWidth} = 'normal';
    $ret->{SetWidth} = 'condensed' if (exists($h->{'Shape'}) &&
				       $h->{'Shape'} =~ /Condensed/);
    $ret->{SetWidth} = 'expanded' if (exists($h->{'Shape'}) &&
				      $h->{'Shape'} =~ /Expanded/);
    $ret->{SetWidth} = $h->{'X-SetWidth'} if
	(exists($h->{'X-SetWidth'}));

    $ret->{Style} = '';
    $ret->{Style} = $h->{'X-Style'} if (exists($h->{'X-Style'}));

    $ret->{Pixel} = 0;
    $ret->{Pixel} = $h->{'X-PixelSize'} if (exists($h->{'X-PixelSize'}));

    $ret->{Point} = 0;
    $ret->{Point} = $h->{'X-PointSize'} if (exists($h->{'X-PointSize'}));

    $ret->{ResX} = 0;
    $ret->{ResX} = $h->{'X-Resolution'} if
	(exists($h->{'X-Resolution'}));

    $ret->{ResY} = 0;
    $ret->{ResY} = $h->{'X-Resolution'} if
	(exists($h->{'X-Resolution'}));

    $ret->{AvgWidth} = 0;
    $ret->{AvgWidth} = $h->{'X-AverageWidth'} if
	(exists($h->{'X-AverageWidth'}));

    $ret->{Encoding} = 'iso8859-1';
    $ret->{Encoding} = $h->{'X-RegistryEncoding'} if
	(exists($h->{'X-RegistryEncoding'}));

    $ret->{Spacing} = 'p';
    $ret->{Spacing} = $Spacing if (defined($Spacing));
    $ret->{Spacing} = $h->{'X-Spacing'} if (exists($h->{'X-Spacing'}));

    foreach my $k (keys(%{$ret})) {
	$ret->{$k} =~ s/ .*//;
	$ret->{$k} =~ tr/A-Z/a-z/;
	$ret->{$k} =~ s/-/_/g if ($k ne 'Encoding');
    }

    return $ret;
}

sub generate_xlfd {
    my $xe = shift;
    my $h = shift;
    my $xlfd;
    my (@xlfds, @xlfdsb, @xlfds_, @xlfdsb_);
    my ($i, $j);
    my (@ret, @list);
    

    $xlfdsb[0] = $xe->{Pixel};
    $xlfdsb[1] = $xe->{Point};
    $xlfdsb[2] = $xe->{ResX};
    $xlfdsb[3] = $xe->{ResY};
    $xlfdsb[4] = $xe->{Spacing};
    $xlfdsb[5] = $xe->{AvgWidth};
    $xlfdsb[6] = $xe->{Encoding};

    @xlfdsb_ = @xlfdsb;

    $xlfds[0] = $xe->{Foundry};
    $xlfds[1] = $xe->{Family};
    $xlfds[2] = $xe->{Weight};
    $xlfds[3] = $xe->{Slant};
    $xlfds[4] = $xe->{SetWidth};
    $xlfds[5] = $xe->{Style};

    @xlfds_ = @xlfds;

    $xlfd = join('-', '', @xlfds, @xlfdsb);

    push(@ret, $xlfd);

    if (exists($h->{'X-Alias'})) {
	@list = split(' ', $h->{'X-Alias'});
	
	foreach $i (@list) {
	    $i =~ tr/A-Z/a-z/;
	    $xlfd = join('-', $i, @xlfdsb);
	    push(@ret, $xlfd);
	}
    }

    if (exists($h->{'X-SimpleAlias'})) {
	@list = split(' ', $h->{'X-SimpleAlias'});

	foreach $i (@list) {
	    $i =~ tr/A-Z/a-z/;
	    push(@ret, $i);
	}
    }

    if (exists($h->{'X-ElementAlias'})) {
	@list = split(' ', $h->{'X-ElementAlias'});

	foreach $i (@list) {
	    $i =~ tr/A-Z/a-z/;
	    my @l = split(/:/, $i);
	    my @xs = (@xlfds, @xlfdsb);
	    my %c2e = ('foundry' => 0, 'family' => 1, 'weight' => 2,
		       'slant' => 3, 'setwidth' => 4, 'style' => 5,
		       'pixel' => 6, 'point' => 7, 'resx' => 8, 'resy' => 9,
		       'spacing' => 10, 'avgwidth' => 11, 'encoding' => 12);
	    
	    foreach my $p (@l) {
		$p =~ /^([^=]+)=(.+)$/;

		$xs[$c2e{$1}] = $2;
	    }

	    $xlfd = join('-', '', @xs);
	    push(@ret, $xlfd);
	}
    }

    return @ret;
}

sub generate_alias {
    my $o = shift;
    my $i = shift;
    my $aliasptr = shift;

    my $id = $o->{0}->[$i];
    my $oid = $o->{5}->[$i];
    my @l;
    my ($p, $size, $psize, $sid, $soid, $flag, $j);

    $id =~ s/_/ /g;
    $oid =~ s/_/ /g;

    my @xe = split(/-/, $id);
    
    if ($xe[7] == 0 && $xe[8] == 0) {
	foreach $size (@AliasSize) {
	    $psize = $size * 10;
	    $xe[7] = $size;
	    $xe[8] = $psize;
	    $xe[12] = $psize;
	    $sid = join('-', @xe);
	    
	    $soid = $oid;
	    $soid =~ s/-0-0-0-0-/-$size-$psize-0-0-/;
	    
	    push(@{$aliasptr}, "\"$sid\" \"$soid\"");
	}
    } elsif ($xe[0]) {
	foreach $size (@AliasSize) {
	    $psize = $size * 10;
	    $sid = $id.'-'.$size;
	    
	    $soid = $oid;
	    $soid =~ s/-0-0-0-0-/-$size-$psize-0-0-/;
	    
	    push(@{$aliasptr}, "\"$sid\" \"$soid\"");
	}
    } else {
	$soid = $oid;
	$soid =~ s/-0-0-0-0-/-$xe[7]-$xe[8]-$xe[9]-$xe[10]-/;
	
	push(@{$aliasptr}, "\"$id\" \"$soid\"");
	
	return 0;
    }
    
    push(@{$aliasptr}, "\"$id\" \"$oid\"");
}

sub write_resource_files {
    my $category = shift;
    my $scaleptr = shift;
    my $aliasptr = shift;

    my $fscale = "$PkgDir/dirs/$category/fonts.scale";
    my $falias = "$PkgDir/dirs/$category/fonts.alias";

    open(F, '>' . $fscale) || return 0;
    my $lnum = @{$scaleptr};

    print F $lnum, "\n";

    foreach my $i (@{$scaleptr}) {
	print F $i, "\n";
    }

    close F;

    open(F, '>' . $falias) || return 0;

    foreach my $i (@{$aliasptr}) {
	print F $i, "\n";
    }

    close F;

    system('/usr/X11R6/bin/mkfontdir',
	   '-e', '/usr/X11R6/lib/X11/fonts/encodings',
	   '-e', '/usr/X11R6/lib/X11/fonts/encodings/large',
	   "$PkgDir/dirs/$category");

    return 0;
}

sub register_all {
    my $o = shift;
    my $font = shift;
    my $pri = shift;
    my $xe = shift;
    my $h = shift;
    my $ctg = shift;
    
    my @hints = parse_hints_build($h);
    my @xlfds = generate_xlfd($xe, $h);
    my %add = ();

    $add{category} = $ctg if ($ctg);

    my $xlfd0 = shift(@xlfds);

    defoma_id_register($o, type => 'real', font => $font, id => $xlfd0,
		       priority => $pri, hints => join(' ', @_, @hints),
		       %add);

    while (@xlfds) {
	my $xlfd = shift(@xlfds);

	defoma_id_register($o, type => 'alias', font => $font, id => $xlfd,
			   priority => $pri, origin => $xlfd0, %add);
    }
}

###

sub parse_config_file {
    $Method = 'xtt';

    if (open(F, $configfile)) {
	while (<F>) {
	    next if ($_ =~ /^\#/);
	    chomp($_);

	    if ($_ =~ /^X_TRUETYPE_METHOD=(xtt|freetype)\s*$/) {
		$Method = $1;
	    }
	    if ($_ =~ /^XTT_VL=([ynYN])\s*$/) {
		$VL = ($1 =~ /[yY]/) ? 1 : 0;
	    }
	}
	close F;
    }
}

sub parse_config_file2 {
    %SpacingC = ();

    if (open(F, $configfile . "2")) {
	while (<F>) {
	    next if ($_ =~ /^\#/);
	    chomp($_);
	    my @a = split(' ', $_);
	    my $l = shift(@a);

	    if (defined($l)) {
		$SpacingC{$l} = undef;
	    }
	}
	close F;
    }
}

sub init {
    unless ($Method) {
	parse_config_file();
	parse_config_file2();
    }
    unless ($Id) {
	$Id = defoma_id_open_cache();
	$IdCmap = defoma_id_open_cache('cmap');
	$IdCmap->{callback} = 0;
	$IdSub = defoma_id_open_cache('sub');
	$IdSub->{callback} = 0;
    }
    
    return 0;
}

my $done = 0;

sub term {
    unless ($done) {
	$done = 1;
	defoma_id_close_cache($Id);
	defoma_id_close_cache($IdCmap);
	defoma_id_close_cache($IdSub);
    }

    return 0;
}

sub make_link {
    my $diro = shift;
    my $font = shift;
    my $fname = shift;

    my $fontfile;
    
    if ($fname) {
	$fontfile = $fname;
    } else {
	return 1 unless($font =~ /^(.*)\/(.+)$/);
	$fontfile = $2;
    }
    
    my $dir = $FontRootDir.$diro;
    
    return 1 if (-e $dir . $fontfile);
    symlink($font, $dir . $fontfile) || return 1;

    return 0;
}

sub remove_link {
    my $diro = shift;
    my $font = shift;
    my $fname = shift;

    my $fontfile = shift;
    
    if ($fname) {
	$fontfile = $fname;
    } else {
	return 1 unless($font =~ /^(.*)\/(.+)$/);
	$fontfile = $2;
    }
    
    my $dir = $FontRootDir.$diro;

    return 1 unless(-l $dir . $fontfile);
    unlink($dir . $fontfile);

    return 0;
}

### CATEGORY: TrueType

sub xtt_register {
    my $font = shift;
    my $facenum = shift;
    my $face = shift;
    my $ttcap = shift;
    my $pri = shift;
    my $h = shift;

    my $i_angle = 0.4;
    my $o_angle = 0.2;
    my $boldstring = 'bold';
    my $hw_bw = '';
    my $hw_sw = '';
    my $nobold = 0;
    my $nori = 0;
    my $noi = 0;
    my $noo = 0;
    my $noro = 0;

    my %horig;
    my $k;
    foreach $k (keys(%{$h})) {
	$horig{$k} = $h->{$k};
    }

    if ($ttcap) {
	my @l = split(' ', $ttcap);
	foreach my $i (@l) {
	    if ($i =~ /^italic-angle=(.+)$/) {
		$i_angle = $1;
	    } elsif ($i =~ /^oblique-angle=(.+)$/) {
		$o_angle = $1;
	    } elsif ($i =~ /^halfwidth-bw=(.+)$/) {
		$hw_bw = $1;
	    } elsif ($i =~ /^halfwidth-sw=(.+)$/) {
		$hw_sw = $1;
	    } elsif ($i =~ /^bold-string=(.+)$/) {
		$boldstring = $1;
		$boldstring =~ tr/A-Z/a-z/;
	    } elsif ($i eq 'no-bold') {
		$nobold = 1;
	    } elsif ($i eq 'no-ritalic') {
		$nori = 1;
	    } elsif ($i eq 'no-italic') {
		$noi = 1;
	    } elsif ($i eq 'no-roblique') {
		$noro = 1;
	    } elsif ($i eq 'no-oblique') {
		$noo = 1;
	    }
	}
    }

    my $ttcapbase = '';
    $ttcapbase = 'fn='.$face.':' if ($facenum > 1);
    my $ttcapbase_hw = '';

    if ($h->{'X-RegistryEncoding'} !~/^(jisx0208\.|jisx0212\.|jisx0213\.|gb2312\.|big5|ksc5601\.|gbk|gb18030)/) {
	$ttcapbase_hw .= 'bw='.$hw_bw.':' if ($hw_bw);
	$ttcapbase_hw .= 'sw='.$hw_sw.':' if ($hw_sw);
    }

    my $xe = get_xlfd_element($h);
    my $weight0 = $xe->{Weight};
    my $slant0 = $xe->{Slant};
    my $space0 = $xe->{Spacing};
    
    my $hweight0 = $h->{Weight};
    my $hwidth0 = $h->{Width};
    my $hshape0 = $h->{Shape} || '';
    $hshape0 =~ s/(Upright|Italic|Oblique|)//g;
    my $hslant0 = $1 || 'Upright';
    
    my @italiclist = ($slant0);
    if ($slant0 eq 'r' &&
	(($h->{Transform} && $h->{Transform} !~ /NotSlant/) ||
	 ! $h->{Transform})) {
	push(@italiclist, 'i') unless ($noi);
	push(@italiclist, 'ri') unless ($nori);
	push(@italiclist, 'o') unless ($noo);
	push(@italiclist, 'ro') unless ($noro);
    }
    
    my @boldlist = ($weight0);
    if ($weight0 ne $boldstring &&
	(($h->{Transform} && $h->{Transform} !~ /NotBoldize/) ||
	 ! $h->{Transform})) {
	push(@boldlist, $boldstring) unless ($nobold);
    }

    my @spclist = ($space0);
    if ($h->{'X-Spacing'}) {
	@spclist = split(' ', $h->{'X-Spacing'});
    } elsif ($Spacing) {
	push(@spclist, ($Spacing eq 'c') ? 'm' : 'c');
    }
    
    my $fontname0 = $h->{FontName};
    my $fontname0_b = $h->{'FontName-Bold'};
    my $fontname0_bi = $h->{'FontName-BoldItalic'};
    my $fontname0_i = $h->{'FontName-Italic'};
    
    parse_hints_cut($h, 'X-Weight', 'X-Slant', 'X-Spacing');

    my $idobj = $Id;
    
    foreach my $spc (@spclist) {
	$xe->{Spacing} = $spc;

	foreach my $slant (@italiclist) {
	    $h->{Shape} = $hshape0.' ';
	    $h->{Shape} .= ($slant eq $slant0) ? $hslant0 : 'Italic';
	    $xe->{Slant} = $slant;
	    
	    foreach my $weight (@boldlist) {
		$h->{Weight} = $hweight0 if ($hweight0);
		$h->{Weight} = 'Bold' if ($weight eq $boldstring);
		$xe->{Weight} = $weight;

		my $ttcap = $ttcapbase;
		$ttcap .= $ttcapbase_hw if ($spc eq 'c');
		$ttcap .= 'vl=y:' if ($spc ne 'c' && $VL);
		$ttcap .= 'ds=y:' if ($weight ne $weight0);
		$ttcap .= 'ai='.$i_angle.':' if ($slant eq 'i');
		$ttcap .= 'ai=-'.$i_angle.':' if ($slant eq 'ri');
		$ttcap .= 'ai='.$o_angle.':' if ($slant eq 'o');
		$ttcap .= 'ai=-'.$o_angle.':' if ($slant eq 'ro');
		
		$ttcap = '.' unless($ttcap);

		if ($weight eq $boldstring && $slant eq 'i') {
		    $h->{FontName} = $fontname0_bi || $fontname0;
		} elsif ($weight eq $boldstring) {
		    $h->{FontName} = $fontname0_b || $fontname0;
		} elsif ($slant eq 'i') {
		    $h->{FontName} = $fontname0_i || $fontname0;
		} else {
		    $h->{FontName} = $fontname0;
		}

		register_all($idobj, $font, $pri, $xe, $h, '', $ttcap);
	    }
	    $idobj = $IdSub if ($slant ne 'r');
	}
	$idobj = $IdSub;
    }

    foreach $k (keys(%horig)) {
	$h->{$k} = $horig{$k};
    }
}

sub freetype_register {
    my $font = shift;
    my $facenum = shift;
    my $face = shift;
    my $pri = shift;
    my $h = shift;

    my $cap = '.';
    $cap = ':'.$face.':' if ($facenum > 1);

    my $hwidth = $h->{Width};
    my $xe = get_xlfd_element($h);

    register_all($Id, $font, $pri, $xe, $h, '', $cap);

#    
    if ($h->{'X-Spacing'}) {
	my @spclist = split(' ', $h->{'X-Spacing'});
	
	shift(@spclist);
	foreach my $spc (@spclist) {
	    $xe->{Spacing} = $spc;
	    
	    register_all($IdSub, $font, $pri, $xe, $h, '', $cap);
	}
    } elsif ($Spacing) {
	$xe->{Spacing} = $Spacing eq 'c' ? 'm' : 'c';
	
	register_all($IdSub, $font, $pri, $xe, $h, '', $cap);
    }
}

sub tt_register {
    my $font = shift;

    make_link('/TrueType/', $font) && return 1;
    
    my $hh = parse_hints_start(@_);
    
    my $facenum = $hh->{FaceNum} || 1;
    parse_hints_cut($hh, 'FaceNum');
    my ($i, $j);
    my $noerror = 0;

    for ($i = 0; $i < $facenum; $i++) {
	my $h = parse_hints_subhints_inherit($hh, $i);
	parse_hints_cut($h, 'Encoding');
	parse_hints_cut($h, 'X-Alias', 'X-SimpleAlias') if ($Method eq 'xtt');
	my $pri = $h->{Priority} || 0;
	next unless ($h->{FontName});
	
	my %xencoding;

	if (exists($h->{Charset})) {
	    my @charset = split(' ', $h->{'Charset'});

	    foreach $j (@charset) {
		my $x = get_xencoding($j, '');
		$xencoding{$x} = $j if ($x);
	    }
	}

	my @xenc;
	if ($h->{'X-RegistryEncoding'}) {
	    @xenc = split(' ', $h->{'X-RegistryEncoding'});
	    foreach $j (@xenc) {
		my $c = get_charset($j);
		$xencoding{$j} = $c;
	    }
	}

	$noerror = 1;

	@xenc = keys(%xencoding);

	undef $Spacing;
	if ($h->{Width} && $h->{Width} eq 'Fixed') {
	    if (grep(exists($SpacingC{$_}), @xenc)) {
		$Spacing = 'c';
	    } else {
		$Spacing = 'm';
	    }
	}
	
	foreach my $xe (@xenc) {
	    my $cset = $xencoding{$xe};

	    $h->{'X-RegistryEncoding'} = $xe;
	    parse_hints_cut($h, 'Charset');
	    $h->{'Charset'} = $cset if ($cset);

	    if ($Method eq 'xtt') {
		xtt_register($font, $facenum, $i, $h->{TTCap}, $pri, $h);
	    } else {
		freetype_register($font, $facenum, $i, $pri, $h);
	    }
	}
    }

    unless ($noerror) {
	remove_link('/TrueType/', $font);
	return 2;
    }

    return 0;
}

sub tt_unregister {
    my $font = shift;

    remove_link('/TrueType/', $font);

    defoma_id_unregister($Id, type => 'alias', font => $font);
    defoma_id_unregister($Id, type => 'real', font => $font);
    defoma_id_unregister($IdSub, type => 'alias', font => $font);
    defoma_id_unregister($IdSub, type => 'real', font => $font);

    return 0;
}

sub tt_install {
    my $font = shift;
    my $id = shift;
    shift;
    shift;
    shift;

    defoma_font_register('xfont', $id, @_);
}

sub tt_remove {
    my $font = shift;
    my $id = shift;

    defoma_font_unregister('xfont', $id);
}

sub tt_term {
    my @scale = ();
    my @alias = ();
    my $file;
    my $id;
    my $oid;

    my @l = defoma_id_grep_cache($Id, 'installed', f4 => 'truetype');
    foreach my $i (@l) {
	$id = $Id->{0}->[$i];
	$id =~ s/_/ /g;

	if ($Id->{2}->[$i] eq 'SrI') {
	    $file = $Id->{1}->[$i];
	    $file =~ s/^(.*)\///;

	    my $cap = $Id->{7}->[$i];
	    $cap =~ s/ .*$//;
	    $cap = '' if ($cap eq '.');

	    push(@scale, $cap.$file.' '.$id);
	} else {
	    generate_alias($Id, $i, \@alias);
	}
    }

    @l = defoma_id_grep_cache($IdSub, 'installed', f4 => 'truetype');
    foreach my $i (@l) {
	$id = $IdSub->{0}->[$i];
	$id =~ s/_/ /g;

	if ($IdSub->{2}->[$i] eq 'SrI') {
	    $file = $IdSub->{1}->[$i];
	    $file =~ s/^(.*)\///;

	    my $cap = $IdSub->{7}->[$i];
	    $cap =~ s/ .*$//;
	    $cap = '' if ($cap eq '.');

	    push(@scale, $cap.$file.' '.$id);
	} else {
	    generate_alias($IdSub, $i, \@alias);
	}
    }

    write_resource_files('TrueType', \@scale, \@alias);

    term();

    return 0;
}

sub truetype {
    my $com = shift;

    if ($com eq 'register') {
	return tt_register(@_);
    } elsif ($com eq 'unregister') {
	return tt_unregister(@_);
    } elsif ($com eq 'do-install-real') {
	return tt_install(@_);
    } elsif ($com eq 'do-remove-real') {
	return tt_remove(@_);
    } elsif ($com eq 'init') {
	return init();
    } elsif ($com eq 'term') {
	return tt_term();
    }

    return 0;
}

### CATEGORY: cid

my $cid_term_done = 0;

sub cid_term {
    return 0 if ($cid_term_done);
    
    my @l = defoma_id_grep_cache($Id, 'installed', f4 => 'cid');
    my @scale = ();
    my @alias = ();
    my $id;
    my $oid;

    foreach my $i (@l) {
	$id = $Id->{0}->[$i];
	next if ($id =~ /^CID:/);
	$id =~ s/_/ /g;
	
	if ($Id->{2}->[$i] eq 'SrI') {
	    my $cidfont = $Id->{1}->[$i];

	    push(@scale, $cidfont . ' ' . $id);
	} else {
	    generate_alias($Id, $i, \@alias);
	}
    }

    write_resource_files('CID', \@scale, \@alias);
    system('/usr/X11R6/bin/mkcfm', "$PkgDir/dirs/CID");

    term();

    return 0;
}

sub cid_check_dir {
    my ($reg, $ord) = @_;

    my $dir = $FontRootDir.'/CID/'.$reg.'-'.$ord.'/';

    unless (-d $dir) {
	mkdir($dir, 0755) || return 1;

	mkdir($dir.'CIDFont', 0755) || return 1;
	mkdir($dir.'AFM', 0755) || return 1;
	mkdir($dir.'CFM', 0755) || return 1;
	mkdir($dir.'CMap', 0755) || return 1;
    }

    return 0;
}

sub cid_register_all {
    my $font = shift;
    my $cmap = shift;
    my $reg = shift;
    my $ord = shift;
    my $cset = shift;
    my $enc = shift;
    my $xenc = shift;
    my $h = shift;

    $h->{'X-RegistryEncoding'} = $xenc;
    $h->{'Charset'} = $cset if ($cset ne '.');
    $h->{'Encoding'} = $enc if ($enc ne '.');

    my $pri = $h->{Priority} || 0;
    my $fontname = $h->{FontName};
    
    my $xe = get_xlfd_element($h);

    $font =~ /(.*)\/(.+)/;
    my $cidfont = $reg.'-'.$ord.'/'.$2.'--'.$cmap.'.cid';

    register_all($Id, $cidfont, $pri, $xe, $h, 'cid');

    return 0;
}

sub cid_register {
    my $font = shift;
    return 1 unless ($font =~ /(.*)\/(.+)/);
    
    my $h = parse_hints_start(@_);
    
    my $reg = $h->{CIDRegistry};
    my $ord = $h->{CIDOrdering};
    my $fontname = $h->{FontName};
    return 1 unless ($reg && $ord && $fontname);

    cid_check_dir($reg, $ord) && return 2;

    my $dir = '/CID/'.$reg.'-'.$ord.'/';

    make_link($dir.'CIDFont/', $font, $fontname) && return 3;

    if (exists($h->{AFM})) {
	my $afm = $h->{AFM};

	if (make_link($dir.'AFM/', $afm, $fontname.'.afm')) {
	    remove_link($dir.'CIDFont/', $font, $fontname);
	    return 4;
	}
    }
    
    my $pri = $h->{Priority} || 0;

    parse_hints_cut($h, 'CIDRegistry', 'CIDSupplement', 'CIDOrdering',
		    'Charset', 'Encoding', 'AFM');
    my @hints = parse_hints_build($h);

    defoma_id_register($IdCmap, type => 'real', font => $font,
		       id => $reg.'-'.$ord.'/'.$fontname,
		       priority => $pri,
		       hints => join(' ', $reg, $ord, @hints));

    my @l = defoma_id_grep_cache($IdCmap, 'real', r0 => $reg.'-'.$ord.'/.*',
				 f4 => 'cmap');

    foreach my $i (@l) {
	$IdCmap->{0}->[$i] =~ /(.*)\/(.+)/;
	my $cmap = $2;
	my @chints = split(' ', $IdCmap->{7}->[$i]);
	
	cid_register_all($font, $cmap, $reg, $ord, $chints[2], $chints[3],
			 $chints[4], $h);
    }

    return 0;
}

sub cid_unregister {
    my $font = shift;
    my $h = parse_hints_start(@_);

    my $reg = $h->{CIDRegistry};
    my $ord = $h->{CIDOrdering};
    my $fontname = $h->{FontName};
    return 1 unless ($reg && $ord && $fontname);

    my $dir = '/CID/'.$reg.'-'.$ord.'/';

    remove_link($dir.'CIDFont/', $font, $fontname);

    if (exists($h->{AFM})) {
	my $afm = $h->{AFM};

	remove_link($dir.'AFM/', $afm, $fontname.'.afm');
    }

    defoma_id_unregister($IdCmap, type => 'real', font => $font);

    my @l = defoma_id_grep_cache($IdCmap, 'real', r0 => $reg.'-'.$ord.'/.*',
				 f4 => 'cmap');

    foreach my $i (@l) {
	$IdCmap->{0}->[$i] =~ /(.*)\/(.+)/;
	my $cmap = $2;

	$font =~ /(.*)\/(.+)/;
	my $cidfont = $reg.'-'.$ord.'/'.$2.'--'.$cmap;

	defoma_id_unregister($Id, type => 'alias', font => $cidfont);
	defoma_id_unregister($Id, type => 'real', font => $cidfont);
    }

    return 0;
}

sub cid_install {
    my $font = shift;
    my $id = shift;
    shift;
    shift;

    defoma_font_register('xfont', $id, @_);
    
    return 0;
}

sub cid_remove {
    my $font = shift;
    my $id = shift;
    
    defoma_font_unregister('xfont', $id);
    
    return 0;
}

sub cid {
    my $com = shift;

    if ($com eq 'register') {
	return cid_register(@_);
    } elsif ($com eq 'unregister') {
	return cid_unregister(@_);
    } elsif ($com eq 'do-install-real') {
	return cid_install(@_);
    } elsif ($com eq 'do-remove-real') {
	return cid_remove(@_);
    } elsif ($com eq 'init') {
	return init();
    } elsif ($com eq 'term') {
	return cid_term();
    }

    return 0;
}

###

sub cmap_register {
    my $font = shift;
    my $h = parse_hints_start(@_);

    my $cmap = $h->{CMapName};
    my $reg = $h->{CIDRegistry};
    my $ord = $h->{CIDOrdering};
    return 1 unless ($cmap && $reg && $ord);

    my $cset = $h->{Charset};
    my $enc = $h->{Encoding};
    my $xenc = $h->{'X-RegistryEncoding'};

    return 1 unless ($xenc);
    return 1 if ($h->{Direction} && $h->{Direction} eq 'Vertical');

    cid_check_dir($reg, $ord) && return 2;

    make_link('/CID/'.$reg.'-'.$ord.'/CMap/', $font, $cmap) && return 3;

    $cset = '.' unless ($cset);
    $enc = '.' unless ($enc);

    my $pri = $h->{Priority} || 0;

    defoma_id_register($IdCmap, type => 'real', font => $font,
		       id => $reg.'-'.$ord.'/'.$cmap, priority => $pri,
		       hints => join(' ', $reg, $ord, $cset, $enc, $xenc));

    my @l = defoma_id_grep_cache($IdCmap, 'real', r0 => $reg.'-'.$ord.'/.*',
				 f4 => 'cid');

    foreach my $i (@l) {
	my @hints = split(' ', $IdCmap->{7}->[$i]);

	shift(@hints);
	shift(@hints);

	my $h = parse_hints_start(@hints);

	cid_register_all($IdCmap->{1}->[$i], $cmap, $reg, $ord, $cset, $enc,
			 $xenc, $h);
    }

    return 0;
}

sub cmap_unregister {
    my $font = shift;
    my $h = parse_hints_start(@_);

    my $cmap = $h->{CMapName};
    my $reg = $h->{CIDRegistry};
    my $ord = $h->{CIDOrdering};

    return unless ($cmap && $reg && $ord);
    
    remove_link('/CID/'.$reg.'-'.$ord.'/CMap/', $font, $cmap);
    
    defoma_id_unregister($IdCmap, type => 'real', font => $font);

    my @l = defoma_id_grep_cache($IdCmap, 'real', r0 => $reg.'-'.$ord.'/.*',
				 f4 => 'cid');

    foreach my $i (@l) {
	$IdCmap->{0}->[$i] =~ /(.*)\/(.+)/;
	my $cidfont = $reg.'-'.$ord.'/'.$2.'--'.$cmap.'.cid';

	defoma_id_unregister($Id, type => 'alias', font => $cidfont);
	defoma_id_unregister($Id, type => 'real', font => $cidfont);
    }


    return 0;
}

sub cmap {
    my $com = shift;

    if ($com eq 'register') {
	return cmap_register(@_);
    } elsif ($com eq 'unregister') {
	return cmap_unregister(@_);
    } elsif ($com eq 'init') {
	return init();
    } elsif ($com eq 'term') {
	return cid_term();
    }

    return 0;
}

1;
