#!perl
#
# This auxiliary script makes five header files
# used for building XSUB of Lingua::KO::Hangul::Util
#
# Usage:
#    <do 'mkheader'> in perl, or <perl mkheader> in command line
#
# Input: nothing
# Output: "lkhutmp.h"
#
use 5.006001;
use strict;
use warnings;

my %Decomp = (
0x1101 => [0x1100, 0x1100],
0x1104 => [0x1103, 0x1103],
0x1108 => [0x1107, 0x1107],
0x110A => [0x1109, 0x1109],
0x110D => [0x110C, 0x110C],
0x1113 => [0x1102, 0x1100],
0x1114 => [0x1102, 0x1102],
0x1115 => [0x1102, 0x1103],
0x1116 => [0x1102, 0x1107],
0x1117 => [0x1103, 0x1100],
0x1118 => [0x1105, 0x1102],
0x1119 => [0x1105, 0x1105],
0x111A => [0x1105, 0x1112],
0x111B => [0x1105, 0x110B],
0x111C => [0x1106, 0x1107],
0x111D => [0x1106, 0x110B],
0x111E => [0x1107, 0x1100],
0x111F => [0x1107, 0x1102],
0x1120 => [0x1107, 0x1103],
0x1121 => [0x1107, 0x1109],
0x1122 => [0x1107, 0x1109, 0x1100],
0x1123 => [0x1107, 0x1109, 0x1103],
0x1124 => [0x1107, 0x1109, 0x1107],
0x1125 => [0x1107, 0x1109, 0x1109],
0x1126 => [0x1107, 0x1109, 0x110C],
0x1127 => [0x1107, 0x110C],
0x1128 => [0x1107, 0x110E],
0x1129 => [0x1107, 0x1110],
0x112A => [0x1107, 0x1111],
0x112B => [0x1107, 0x110B],
0x112C => [0x1107, 0x1107, 0x110B],
0x112D => [0x1109, 0x1100],
0x112E => [0x1109, 0x1102],
0x112F => [0x1109, 0x1103],
0x1130 => [0x1109, 0x1105],
0x1131 => [0x1109, 0x1106],
0x1132 => [0x1109, 0x1107],
0x1133 => [0x1109, 0x1107, 0x1100],
0x1134 => [0x1109, 0x1109, 0x1109],
0x1135 => [0x1109, 0x110B],
0x1136 => [0x1109, 0x110C],
0x1137 => [0x1109, 0x110E],
0x1138 => [0x1109, 0x110F],
0x1139 => [0x1109, 0x1110],
0x113A => [0x1109, 0x1111],
0x113B => [0x1109, 0x1112],
0x113D => [0x113C, 0x113C],
0x113F => [0x113E, 0x113E],
0x1141 => [0x110B, 0x1100],
0x1142 => [0x110B, 0x1103],
0x1143 => [0x110B, 0x1106],
0x1144 => [0x110B, 0x1107],
0x1145 => [0x110B, 0x1109],
0x1146 => [0x110B, 0x1140],
0x1147 => [0x110B, 0x110B],
0x1148 => [0x110B, 0x110C],
0x1149 => [0x110B, 0x110E],
0x114A => [0x110B, 0x1110],
0x114B => [0x110B, 0x1111],
0x114D => [0x110C, 0x110B],
0x114F => [0x114E, 0x114E],
0x1151 => [0x1150, 0x1150],
0x1152 => [0x110E, 0x110F],
0x1153 => [0x110E, 0x1112],
0x1156 => [0x1111, 0x1107],
0x1157 => [0x1111, 0x110B],
0x1158 => [0x1112, 0x1112],
0x1162 => [0x1161, 0x1175],
0x1164 => [0x1163, 0x1175],
0x1166 => [0x1165, 0x1175],
0x1168 => [0x1167, 0x1175],
0x116A => [0x1169, 0x1161],
0x116B => [0x1169, 0x1161, 0x1175],
0x116C => [0x1169, 0x1175],
0x116F => [0x116E, 0x1165],
0x1170 => [0x116E, 0x1165, 0x1175],
0x1171 => [0x116E, 0x1175],
0x1174 => [0x1173, 0x1175],
0x1176 => [0x1161, 0x1169],
0x1177 => [0x1161, 0x116E],
0x1178 => [0x1163, 0x1169],
0x1179 => [0x1163, 0x116D],
0x117A => [0x1165, 0x1169],
0x117B => [0x1165, 0x116E],
0x117C => [0x1165, 0x1173],
0x117D => [0x1167, 0x1169],
0x117E => [0x1167, 0x116E],
0x117F => [0x1169, 0x1165],
0x1180 => [0x1169, 0x1165, 0x1175],
0x1181 => [0x1169, 0x1167, 0x1175],
0x1182 => [0x1169, 0x1169],
0x1183 => [0x1169, 0x116E],
0x1184 => [0x116D, 0x1163],
0x1185 => [0x116D, 0x1163, 0x1175],
0x1186 => [0x116D, 0x1167],
0x1187 => [0x116D, 0x1169],
0x1188 => [0x116D, 0x1175],
0x1189 => [0x116E, 0x1161],
0x118A => [0x116E, 0x1161, 0x1175],
0x118B => [0x116E, 0x1165, 0x1173],
0x118C => [0x116E, 0x1167, 0x1175],
0x118D => [0x116E, 0x116E],
0x118E => [0x1172, 0x1161],
0x118F => [0x1172, 0x1165],
0x1190 => [0x1172, 0x1165, 0x1175],
0x1191 => [0x1172, 0x1167],
0x1192 => [0x1172, 0x1167, 0x1175],
0x1193 => [0x1172, 0x116E],
0x1194 => [0x1172, 0x1175],
0x1195 => [0x1173, 0x116E],
0x1196 => [0x1173, 0x1173],
0x1197 => [0x1173, 0x1175, 0x116E],
0x1198 => [0x1175, 0x1161],
0x1199 => [0x1175, 0x1163],
0x119A => [0x1175, 0x1169],
0x119B => [0x1175, 0x116E],
0x119C => [0x1175, 0x1173],
0x119D => [0x1175, 0x119E],
0x119F => [0x119E, 0x1165],
0x11A0 => [0x119E, 0x116E],
0x11A1 => [0x119E, 0x1175],
0x11A2 => [0x119E, 0x119E],
0x11A9 => [0x11A8, 0x11A8],
0x11AA => [0x11A8, 0x11BA],
0x11AC => [0x11AB, 0x11BD],
0x11AD => [0x11AB, 0x11C2],
0x11B0 => [0x11AF, 0x11A8],
0x11B1 => [0x11AF, 0x11B7],
0x11B2 => [0x11AF, 0x11B8],
0x11B3 => [0x11AF, 0x11BA],
0x11B4 => [0x11AF, 0x11C0],
0x11B5 => [0x11AF, 0x11C1],
0x11B6 => [0x11AF, 0x11C2],
0x11B9 => [0x11B8, 0x11BA],
0x11BB => [0x11BA, 0x11BA],
0x11C3 => [0x11A8, 0x11AF],
0x11C4 => [0x11A8, 0x11BA, 0x11A8],
0x11C5 => [0x11AB, 0x11A8],
0x11C6 => [0x11AB, 0x11AE],
0x11C7 => [0x11AB, 0x11BA],
0x11C8 => [0x11AB, 0x11EB],
0x11C9 => [0x11AB, 0x11C0],
0x11CA => [0x11AE, 0x11A8],
0x11CB => [0x11AE, 0x11AF],
0x11CC => [0x11AF, 0x11A8, 0x11BA],
0x11CD => [0x11AF, 0x11AB],
0x11CE => [0x11AF, 0x11AE],
0x11CF => [0x11AF, 0x11AE, 0x11C2],
0x11D0 => [0x11AF, 0x11AF],
0x11D1 => [0x11AF, 0x11B7, 0x11A8],
0x11D2 => [0x11AF, 0x11B7, 0x11BA],
0x11D3 => [0x11AF, 0x11B8, 0x11BA],
0x11D4 => [0x11AF, 0x11B8, 0x11C2],
0x11D5 => [0x11AF, 0x11B8, 0x11BC],
0x11D6 => [0x11AF, 0x11BA, 0x11BA],
0x11D7 => [0x11AF, 0x11EB],
0x11D8 => [0x11AF, 0x11BF],
0x11D9 => [0x11AF, 0x11F9],
0x11DA => [0x11B7, 0x11A8],
0x11DB => [0x11B7, 0x11AF],
0x11DC => [0x11B7, 0x11B8],
0x11DD => [0x11B7, 0x11BA],
0x11DE => [0x11B7, 0x11BA, 0x11BA],
0x11DF => [0x11B7, 0x11EB],
0x11E0 => [0x11B7, 0x11BE],
0x11E1 => [0x11B7, 0x11C2],
0x11E2 => [0x11B7, 0x11BC],
0x11E3 => [0x11B8, 0x11AF],
0x11E4 => [0x11B8, 0x11C1],
0x11E5 => [0x11B8, 0x11C2],
0x11E6 => [0x11B8, 0x11BC],
0x11E7 => [0x11BA, 0x11A8],
0x11E8 => [0x11BA, 0x11AE],
0x11E9 => [0x11BA, 0x11AF],
0x11EA => [0x11BA, 0x11B8],
0x11EC => [0x11BC, 0x11A8],
0x11ED => [0x11BC, 0x11A8, 0x11A8],
0x11EE => [0x11BC, 0x11BC],
0x11EF => [0x11BC, 0x11BF],
0x11F1 => [0x11F0, 0x11BA],
0x11F2 => [0x11F0, 0x11EB],
0x11F3 => [0x11C1, 0x11B8],
0x11F4 => [0x11C1, 0x11BC],
0x11F5 => [0x11C2, 0x11AB],
0x11F6 => [0x11C2, 0x11AF],
0x11F7 => [0x11C2, 0x11B7],
0x11F8 => [0x11C2, 0x11B8],
);

open FH, ">", "lkhutmp.h" or die $!;
select FH;

my @Lfiller = charlist(0x115F);
print "#define LKHU_LF_STRING  (", strquote(@Lfiller), ")\n";
print "#define LKHU_LF_LENGTH  (", scalar  (@Lfiller), ")\n";

my @Vfiller = charlist(0x1160);
print "#define LKHU_VF_STRING  (", strquote(@Vfiller), ")\n";
print "#define LKHU_VF_LENGTH  (", scalar  (@Vfiller), ")\n";

our $DecompCnt = 3;
our $DecompEnd = 255;

print "#define LKHU_DecompCnt ($DecompCnt)\n";
print "#define LKHU_DecompEnd ((STDCHAR) $DecompEnd)\n";

print "STDCHAR LKHU_Decomp[256][$DecompCnt] = {\n";
for (my $c = 0x1100; $c <= 0x11FF; $c++) {
    my @tmp = $Decomp{$c} ? @{ $Decomp{$c} } : ($c);
    @tmp <= $DecompCnt or die "error in mkheader";
    while (@tmp < $DecompCnt) {
	push @tmp, $DecompEnd;
    }
    printf qq|    {%s}, \n|, join ', ',
	map sprintf("(STDCHAR)(%d)", $_ & 0xFF ), @tmp;
}
print "};\n\n";

our $StrNam = "LKHU_CompStruct";
our $TypStr = 'char*';
our $TypLen = 'U8';
our $TypChr = 'UV';

print <<"EOF";
typedef struct {
    $TypStr trail;
    $TypLen len;
    $TypChr composite;
} $StrNam;\n\n
EOF

my %DecMap12;   # ({integer}{integer} => integer)
my %DecMap123;  # ({integer}{"integer;integer"} => integer)

foreach my $char (sort {$a <=> $b} keys %Decomp) {
    my @dec = @{ $Decomp{$char} };
    if (@dec == 2) {
	$DecMap12{$dec[0]}{$dec[1]} = $char;
    } else {
	$DecMap123{$dec[0]}{"$dec[1];$dec[2]"} = $char;
    }
}

sub charlist {
    use bytes;
    my $uni = pack('U*', @_);
    my $len = length($uni);
    my @ary;
    for(my $i = 0; $i < $len; ++$i) {
	push @ary, ord(substr($uni,$i,1));
    }
    return @ary;
}
sub strquote { sprintf '"%s"', join '', map sprintf("\\x%02x", $_), @_ }

my %CompStruct;

for (my $c = 0x1100; $c <= 0x11FF; $c++) {
    for my $trail (sort keys %{ $DecMap123{$c} }) {
	my @c = charlist(split /;/, $trail);
	push @{ $CompStruct{$c} },
	    [ strquote(@c), scalar(@c), $DecMap123{$c}{$trail} ];
    }
    for my $trail (sort keys %{ $DecMap12{$c} }) {
	my @c = charlist(split /;/, $trail);
	push @{ $CompStruct{$c} },
	    [ strquote(@c), scalar(@c), $DecMap12{$c}{$trail} ];
    }
}

sub comp_struct {
    my($a, $b, $c) = @_;
    return "    { ($TypStr)$a, ($TypLen)$b, ($TypChr)$c },\n";
}

for my $c (sort { $a <=> $b } keys %CompStruct) {
    print "$StrNam LKHU_Comp${c} [] = {\n";
    for my $ary (@{ $CompStruct{$c} }) {
	print comp_struct($ary->[0], $ary->[1], $ary->[2]);
    }
    print comp_struct("NULL", 0, 0);
    print "};\n\n";
}

print "$StrNam * LKHU_Comp [256] = {\n";
for (my $c = 0x1100; $c <= 0x11FF; $c++) {
    printf "    %s,\n", $CompStruct{$c} ? "LKHU_Comp${c}" : "NULL";
}
print "};\n\n";

1;
__END__
