#!/usr/bin/env perl

=head po2xlf
Description:
	Script to merge a po and an xliff in to a translated xliff file.

Authors:
	Bernd Groh <bgroh@redhat.com>

	Jeff Fearn <jfearn@redhat.com> Thur May 31, 2007
		Extracted code from l10n-command script
		Modified to run as stand alone script

Usage:
	po2xlf --help
	po2xlf --lang=<lang> --xliff=<xliff input file> --pofile=<po input file> --output=<xml output file>
=cut
=head
    Copyright (C) 2008 Red Hat, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

=cut

use strict;
use warnings;
use utf8;
use bytes;
#use Config::Simple;
use Getopt::Long;

my $idfilter = '#. ID:"([^"]+)"';
my $template = undef;
my $nofuzzy  = undef;
my $indent   = "\t\t\t";
my $bindent  = "\t";

my $pofile     = undef;
my $xliff_file = undef;
my $outfile    = undef;
my $lang       = undef;
my $help       = 0;

GetOptions(
    'i|id-filter=s' => \$idfilter,
    't|template=s'  => \$template,
    'no-fuzzy'      => \$nofuzzy,
    'pofile=s'      => \$pofile,
    'xliff=s'       => \$xliff_file,
    'output=s'      => \$outfile,
    'lang=s'        => \$lang,
    'h|help'        => \$help,
);

if ($help) {
    Usage();
    exit(0);
}

if ( !$pofile || !$outfile || !$xliff_file || !$lang ) {
    die( Usage() );
}

sub Usage {
    print( STDERR
            "po2xlf --lang=<lang> --xliff=<xliff input file> --pofile=<po input file> --output=<xml output file>\n"
    );
    print( STDERR "All arguments are mandatory.\n" );
}

my $xliff_header = <<EOL;
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.1" xmlns="urn:oasis:names:tc:xliff:document:1.1">
	<file source-language="en-US" target-language="$lang" datatype="po" original="$xliff_file">
		<body>
EOL

my $xliff_footer = <<EOL;
		</body>
	</file>
</xliff>
EOL

if ( defined $template ) {
    my $xliff = `cat $template`;

    if ( $xliff
        =~ /^(.*<xliff.*>\s*<file\s+.*target-language="\$LANG".*>.*<body\s*>)(\s*\$BODY.*)(<\/body\s*>\s*<\/file\s*>\s*<\/xliff\s*>\s*)$/s
        )
    {
        $xliff_header = $1;
        $xliff_footer = $3;
        $indent       = $2;
        if ( $indent =~ /^\s*\$BODY\[(\s+)\]\s*$/s ) {
            $bindent = $1;
            $bindent =~ s/\n//gs;
        }
        else {
            $bindent = '';
        }
        my $post = undef;
        if ( $indent =~ /^\s*\$BODY\[\s*\](\s+)$/s ) {
            $post = $1;
        }
        elsif ( $indent =~ /^\s*\$BODY(\s+)$/s ) {
            $post = $1;
        }
        if ($post) {
            if ( $post =~ s/([ \t]+)$//s ) {
                $xliff_footer = $1 . $xliff_footer;
            }
            $post =~ s/\n//s;
            while ( $post =~ s/\n//s ) {
                $xliff_footer = "\n" . $xliff_footer;
            }
        }
        $indent =~ s/\$BODY.*$//gs;
        $indent =~ s/[ \t]*\n//s;
        $xliff_header .= "\n";
        while ( $indent =~ s/[ \t]*\n//s ) {
            $xliff_header .= "\n";
        }
    }
}

sub _xmlize {
    my $string = shift;
    my $specials = @_ ? shift : 1;

    if ($specials) {
        $string =~ s/\\"/"/gs;
        $string =~ s/\\t/\t/gs;
        $string =~ s/\\n/\n/gs;
        $string =~ s/\\\\/\\/gs;
    }
    $string =~ s/&/&amp;/gs;
    $string =~ s/>/&gt;/gs;
    $string =~ s/</&lt;/gs;

    return $string;
}

sub _trans_unit {
    my $indent1    = shift;
    my $indent2    = shift;
    my $id         = shift;
    my $source     = shift;
    my $target     = @_ ? shift : '';
    my $fuzzy      = @_ ? shift : 0;
    my $trans_unit = '';

    $trans_unit .= "$indent1<trans-unit id=\"$id\">\n";
    $trans_unit .= "$indent1$indent2<source>$source</source>\n";

    if ( $target ne '' ) {
        if ( $fuzzy == 0 ) {
            $trans_unit .= "$indent1$indent2<target>$target</target>\n";
        }
        elsif ( $fuzzy > 0 ) {
            $trans_unit
                .= "$indent1$indent2<target state=\"needs-review-translation\">$target</target>\n";
        }
    }

    $trans_unit .= "$indent1</trans-unit>\n";

    return $trans_unit;
}

sub convert {
    open( OUTPUT, ">$outfile" ) or die "Error: Cannot write $outfile";

    my $file_header = $xliff_header;
    $file_header =~ s/\$LANG/$lang/;

    #WTF
    #        if ( $file =~ /(\w+\.po)$/ ) {
    #            my $orig = $1;
    #            $file_header =~ s/\$ORIGINAL/$orig/;
    #        }

    print OUTPUT $file_header;

    my $msgid  = undef;
    my $msgstr = undef;
    my @ids    = ();
    my $state  = -1;
    my $fuzzy  = 0;
    my $line   = 0;
    my $idinc  = 0;

    for ( my $index = 0; $index < $#ids; $index++ ) {

        #		print(STDERR "id $index: " . $ids[$index] . "\n");
        chomp( $ids[$index] );

        #		print(STDERR "id $index: " . $ids[$index] . "\n");
    }

    open( POFILE, "<$pofile" ) or die "Error: Cannot read $pofile";

    while (<POFILE>) {
        $line++;
        if ( $state >= 0 ) {
            if (/^msgid ""\s+$/) {
                if ( $state == 0 ) {
                    $msgid = '';
                    $state = 1;
                }
                else {
                    die "error line $line: $_";
                }
            }
            elsif (/^msgid "(.+)"\s+$/) {
                if ( $state == 0 ) {
                    $msgid = $1;
                    $state = 2;
                }
                else {
                    die "error line $line: $_";
                }
            }
            elsif (/^msgstr ""\s+$/) {
                if ( $state == 2 ) {
                    $msgstr = '';
                    $state  = 3;
                }
                else {
                    die "error line $line: $_";
                }
            }
            elsif (/^msgstr "(.+)"\s+$/) {
                if ( $state == 2 ) {
                    $msgstr = $1;
                    $state  = 4;
                }
                else {
                    die "error line $line: $_";
                }
            }
            elsif (/^"(.*)"\s+$/) {
                my $var = $1;
                if ( $state == 1 ) {
                    $state = 2;
                    $msgid = $var;
                }
                elsif ( $state == 2 ) {
                    $msgid .= $var;
                }
                elsif ( $state == 3 ) {
                    $state  = 4;
                    $msgstr = $var;
                }
                elsif ( $state == 4 ) {
                    $msgstr .= $var;
                }
                else {
                    die "error line $line: $_";
                }
            }
            elsif (/^#/) {
                if (/^#, .*fuzzy/) {
                    $fuzzy = 1;
                }
                elsif (/^$idfilter$/) {
                    push @ids, $1;
                }
            }
            elsif (/^$/) {

         #				print(STDERR "state: $state; msgstr: $msgstr; msgid: $msgid\n");
                if ( $state == 3 ) {
                    $msgstr = '';
                    $state  = 4;
                }
                if ( $state == 4 ) {
                    $msgid  = _xmlize($msgid);
                    $msgstr = _xmlize($msgstr);

=head
                    if ( !@ids ) {
                        $idinc++;
                        push @ids, $idinc;
                    }
=cut

                    while (@ids) {
                        my $id = shift(@ids);
                        chomp($id);
                        $id = _xmlize( $id, 0 );

                        print OUTPUT _trans_unit( $indent, $bindent, $id,
                            $msgid, $msgstr,
                            ( $nofuzzy ? -$fuzzy : $fuzzy ) );
                    }

                    $msgid  = undef;
                    $msgstr = undef;
                    $state  = 0;
                    $fuzzy  = 0;
                }
                else {
                    if ( defined $msgid || defined $msgstr ) {
                        die "error line $line: $_";
                    }
                    $state = 0;
                    $fuzzy = 0;
                }
            }
            else {
                warn "ignore line $line: $_";
            }
        }
        elsif (/^$/) {
            $state = 0;
        }
    }

    if ( $state == 3 ) {
        $msgstr = '';
        $state  = 4;
    }
    if ( $state == 4 ) {
        $msgid  = _xmlize($msgid);
        $msgstr = _xmlize($msgstr);

        if ( !@ids ) {
            $idinc++;
            push @ids, $idinc;
        }

        while (@ids) {
            my $id = shift(@ids);
            $id = _xmlize( $id, 0 );

            print OUTPUT _trans_unit( $indent, $bindent, $id, $msgid, $msgstr,
                ( $nofuzzy ? -$fuzzy : $fuzzy ) );
        }
    }

    print OUTPUT $xliff_footer;

    close OUTPUT;
    close POFILE;
}

convert();
exit(0);
