package MGH_Biostat::Locale::POCatalog;
use Modern::Perl '2012';
use experimental 'switch';
use Carp;

use Path::Tiny;
use Set::Tiny 'set';

use MGH_Biostat::Locale::PO;

use Moo;
use namespace::clean;

use constant CTXSEP => chr(4);

# @GROUP attributes

# the directory that holds the .po files.
# this can be changed an instantiation, but not after
has 'dir' => (
    is      => 'ro',
    default => 'po/',
);

# the default language
has 'default_lang' => (
    is      => 'ro',
    default => 'en-US',
);

# a set of the supported languages
has 'langs' => (
    is => 'lazy',
);

# a list of the languages in a sorted order
# (default language first, then the rest alphabetically)
has 'langs_order' => (
    is => 'lazy',
);

# the actual translation data
has 'data' => (
    is => 'lazy',
);

# @GROUP builders

# any language we have a .po file is supported
sub _build_langs {
    my $self = shift;

    my $langs = [];
    for ( path( $self->dir )->children(qr/\.po$/) ) {
        push @$langs, $_->basename('.po');
    }

    return set($langs);
}

# build the order of the languages
sub _build_langs_order {
    my $self    = shift;
    my $order   = [];
    my $default = $self->default_lang;
    push @$order, $default;
    foreach my $lang ( sort $self->langs->members ) {
        next if $lang eq $default;
        push @$order, $lang;
    }
    return $order;
}

# read in the translation data
sub _build_data {
    my $self = shift;

    my $data = {};

    foreach my $lang ( $self->langs->members ) {
        my $pos = MGH_Biostat::Locale::PO->load_file_asarray( $self->dir . $lang . '.po', 'utf8' );
        foreach my $po (@$pos) {
            my $key = $po->hashkey;
            if ( !defined( $po->msgid_plural ) and ( !defined( $po->msgstr ) or ( $po->msgstr eq '' ) ) ) {
                no warnings 'uninitialized';
                warn 'Missing translation for [' . $lang . '|' . $po->msgctxt . '|' . $po->msgid . ']; setting to msgid.' . "\n";
                $po->msgstr( $po->msgid );
            }
            $data->{$lang}{$key} = $po;
        }
    }

    return $data;
}

# force the data to be loaded when the object is created
sub BUILD {
    my $self = shift;
    $self->data;
    return;
}

# @GROUP methods

#
sub is_valid_lang {
    my $self = shift;
    my ($lang) = @_;
    return $self->langs->member($lang);
}

# look up a translation
# returns a MGH_Biostat::Locale::PO object
# the first parameter *must* be the language
# the second parameter is the lookup string
# if there is a context to be provided, you can either pass a third parameter,
#   or use the CTXSEP constant to create a context lookup string
# if there is any kind of error, a warning will be fired,
#   and a Locale::PO object with the same string as request will be returned
sub lookup {
    my $self = shift;
    my ( $lang, $msgid, $context ) = @_;

    if ( $self->is_valid_lang($lang) ) {
        my $key = ( defined($context) ? $context . CTXSEP : '' ) . $msgid;
        my $data = $self->data;
        if ( defined( $data->{$lang}{$key} ) ) {
            return $data->{$lang}{$key};
        }
        elsif ( defined( $data->{ $self->default_lang }{$key} ) ) {
            no warnings 'uninitialized';    # $context may not be defined
            carp "Key [$context|$msgid] not defined for $lang.";
            return $data->{ $self->default_lang }{$key};
        }
        else {
            no warnings 'uninitialized';    # $context may not be defined
            carp "Key [$context|$msgid] not defined for any lang.";
            return MGH_Biostat::Locale::PO->new( -msgid => $msgid, -msgstr => $msgid, -msgctxt => $context );
        }
    }
    else {
        carp "Language $lang not supported.";
        return MGH_Biostat::Locale::PO->new( -msgid => $msgid, -msgstr => $msgid, -msgctxt => $context );
    }
}

1;