package Lire::XMLSpecI18N;

use strict;

use Carp;
use File::Basename qw/ basename /;
use POSIX qw/ setlocale LC_MESSAGES /;

use Lire::Utils qw/ tree_apply check_object_param /;

=pod

=head1 NAME

Lire::XMLSpecI18N - Extract strings for localization from XML Specs

=head1 SYNOPSIS

    use Lire::XMLSpecI18N;

=head1 DESCRIPTION

FILL ME IN

=cut

sub new {
    my ( $class, @specs ) = @_;

    croak "missing one or more 'specs' parameter"
      unless @specs;

    my $self = bless {}, $class;

    $self->{'_specs'} = [];
    foreach my $spec (@specs) {
        check_object_param( $spec, 'spec',
                            [ 'Lire::ReportConfig',
                              'Lire::DlfSchema',
                              'Lire::XMLSpecContainer',
                              'Lire::Config::ConfigSpec' ] );
        push @{$self->{'_specs'}}, $spec;
    }

    return $self;
}

sub _generate_ref {
    my $self = $_[0];

    croak( "'_cur_spec' attribute is undef" )
      unless defined $self->{'_cur_spec'};

    my $spec = $self->{'_cur_spec'};
    my $ref;
    if ( UNIVERSAL::isa( $spec, 'Lire::ReportConfig' ) ) {
        $ref = basename( $spec->filename() );
    } elsif ( UNIVERSAL::isa( $spec, 'Lire::Config::ConfigSpec' ) ) {
        croak "no 'xml_file' attribute, was Lire;:Config::ConfigSpec->xml_file() called?"
          unless $spec->xml_file();
        $ref = basename( $spec->xml_file() );
    } elsif ( UNIVERSAL::isa( $spec, 'Lire::ReportSpec' ) ) {
        $ref = "report:" . $spec->superservice() . ":" . $spec->id();
    } elsif ( UNIVERSAL::isa( $spec, 'Lire::FilterSpec' ) ) {
        $ref = "filter:" . $spec->superservice() . ":" . $spec->id();
    } elsif ( UNIVERSAL::isa( $spec, 'Lire::DlfSchema' ) ) {
        $ref = "schema:" . $spec->id();
    } else {
        croak "unknown spec reference: $spec";
    }

    print "# REFERENCE: $ref\n";
    return;
}

sub _generate_msgid {
    my ( $self, $msgid ) = @_;

    $self->_generate_ref();
    $msgid =~ s/(^ +| +$)//gm;
    $msgid =~ s/\n/ /g;
    print "__( q{$msgid} );\n";

    return;
}

sub generate_catalog {
    my $self = $_[0];

    # Make sure we get the C strings
    my $old_locale = setlocale( LC_MESSAGES );
    setlocale( LC_MESSAGES, 'C' );
    eval {
        foreach my $spec ( @{ $self->{'_specs'} } ) {
            $self->{'_cur_spec'} = $spec;
            if ( $spec->isa( 'Lire::ReportSpec' ) ) {
                $self->_report_spec_i18n();
            } elsif ( $spec->isa( 'Lire::ReportConfig' ) ) {
                $self->_report_config_i18n();
            } elsif ( $spec->isa( 'Lire::Config::ConfigSpec' ) ) {
                $self->_config_spec_i18n();
            } elsif ( $spec->isa( 'Lire::DlfSchema' ) ) {
                $self->_schema_i18n();
            } elsif ( $spec->isa( 'Lire::XMLSpecContainer' ) ) {
                $self->_xml_spec_i18n();
            } else {
                croak "unknown spec type: $spec";
            }
        }
    };
    setlocale( LC_MESSAGES, $old_locale );
    die $@ if $@;

    return;
}

sub _report_config_i18n {
    my $self = $_[0];

    check_object_param( $self->{'_cur_spec'}, '_cur_spec',
                        'Lire::ReportConfig' );

    foreach my $sect ( $self->{'_cur_spec'}->sections() ) {
        $self->_generate_msgid( $sect->title() );
    }
    return;
}

sub _schema_i18n {
    my $self = $_[0];

    my $spec = $self->{'_cur_spec'};

    check_object_param( $self->{'_cur_spec'}, '_cur_spec',
                        'Lire::DlfSchema' );

    $self->_generate_msgid( $spec->title() );
    my $desc = $spec->description();
    $self->_generate_msgid( $self->_strip_para( $desc ) )
      if $desc;
    foreach my $field ( $spec->isa( 'Lire::ExtendedSchema' )
                        ? @{$spec->extended_fields()}
                        : @{$spec->fields()} ) {
        next if $field->name() eq 'dlf_id';
        next if $field->name() eq 'dlf_source';
        $self->_generate_msgid( $field->label() );
        $desc = $field->description();
        $self->_generate_msgid( $self->_strip_para( $desc ) )
          if $desc;
    }

    return;
}

sub _xml_spec_i18n {
    my $self = $_[0];

    my $spec = $self->{'_cur_spec'};

    check_object_param( $self->{'_cur_spec'}, '_cur_spec',
                        'Lire::XMLSpecContainer' );

    $self->_generate_msgid( $spec->title() );
    my $desc = $spec->description();
    $self->_generate_msgid( $self->_strip_para( $desc ) )
      if $desc;
    foreach my $name ( $spec->param_names() ) {
        my $param = $spec->param( $name );
        $desc = $param->description();
        $self->_generate_msgid( $self->_strip_para( $desc ) )
          if $desc;
    }
    $self->_generate_msgid( $spec->display_title() );
    $desc = $spec->display_description();
    $self->_generate_msgid( $self->_strip_para( $desc ) )
      if $desc;

    return;
}

sub _report_spec_i18n {
    my $self = $_[0];

    check_object_param( $self->{'_cur_spec'}, '_cur_spec',
                        'Lire::ReportSpec' );
    my $spec = $self->{'_cur_spec'};

    $self->_xml_spec_i18n();

    tree_apply( $spec->calc_spec(),
                sub {
                    my $op = $_[0];
                    return $op->isa( 'Lire::Aggregator' ) ? $op->ops() : []; },
                sub {
                    my $op = $_[0];
                    $self->_generate_msgid( $op->label() )
                      if $op->has_label();
                } );

    return;
}

sub _config_spec_i18n {
    my $self = $_[0];

    check_object_param( $self->{'_cur_spec'}, '_cur_spec',
                        'Lire::Config::ConfigSpec' );

    my $spec = $self->{'_cur_spec'};

    tree_apply( $spec,
                sub {
                    my $comp = $_[0];
                    return []
                      unless $comp->isa( 'Lire::Config::CompoundSpec' );

                    return [ sort( { $a->name() cmp $b->name() }
                                   $comp->components() ) ];
                },
                sub {
                    my $comp = $_[0];
                    $self->_generate_msgid( $comp->summary() )
                      if $comp->summary() ne $comp->name();
                    my $desc = $comp->description();
                    $self->_generate_msgid( $self->_strip_para( $desc ) )
                      if $desc;
                } );

    return;
}

sub _strip_para {
    my ( $self, $string ) = @_;

    $string =~ s{(^\s*<para>|</para>\s*$)}{}g;

    return $string;
}

# keep perl happy
1;

__END__

=pod

=head1 SEE ALSO

lr_spec2pot(1)

=head1 AUTHORS

  Francis J. Lacoste <flacoste@logreport.org>
  Wolfgang Sourdeau <wolfgang@logreport.org>

=head1 VERSION

$Id: XMLSpecI18N.pm,v 1.11 2006/07/23 13:16:30 vanbaal Exp $

=head1 COPYRIGHT

Copyright (C) 2004 Stichting LogReport Foundation LogReport@LogReport.org

This file is part of Lire.

Lire 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 (see COPYING); if not, check with
http://www.gnu.org/copyleft/gpl.html. 

=cut
