package Software::Copyright::Owner;

use warnings;
use 5.20.0;
use utf8;
use Unicode::Normalize;

use Mouse;

use feature qw/postderef signatures/;
no warnings qw/experimental::postderef experimental::signatures/;

use overload '""' => \&stringify;

has name => (
    is => 'rw',
    isa => 'Str',
);

has record => (
    is => 'rw',
    isa => 'Str',
);

has email => (
    is => 'rw',
    isa => 'Str',
    predicate => 'has_email',
);

around BUILDARGS => sub ($orig, $class, @args) {
    my $params = {  } ;

    # detect garbage in string argument
    if ($args[0] !~ /^[[:alpha:]]/) {
        # don't try to be smart, keep the record as is: garbage in, garbage out
        $params->{record} = $args[0];
    }
    elsif ($args[0] =~ /\b(and|,)\b/) {
        # combined records, do not try to extract name and email.
        $params->{record} = NFC($args[0]);
    }
    elsif ($args[0] =~ /([^<]+)<([^>]+)>$/) {
        # see https://www.unicode.org/faq/normalization.html
        $params->{name} = NFC($1);
        $params->{email} = $2;
    }
    else {
        $params->{name} = NFC($args[0]);
    }
    return $class->$orig($params) ;
};

sub BUILD ($self, $args) {
    my $name = $self->name;
    if (defined $name) {
        $name =~ s/\s+$//;
        $name =~ s/^\s+//;
        $self->name($name);
    }
    return;
}

sub identifier ($self) {
    return $self->name // $self->record // '';
}

sub stringify ($self, $=1, $=1) {
    if (my $str = $self->name) {
        $str .= " <".$self->email.">" if $self->has_email;
        return $str;
    }
    else {
        return $self->record // '';
    }
}

1;

# ABSTRACT: Copyright owner class

__END__

=head1 SYNOPSIS

 use Software::Copyright::Owner;

 # one owner
 my $owner = Software::Copyright::Owner->new('Joe <joe@example.com>');

 $owner->name; # => is "Joe"
 $owner->email; # => is 'joe@example.com'
 $owner->identifier; # => is 'Joe'

 # stringification
 my $s = "$owner"; # => is 'Joe <joe@example.com>'

 # several owners, separated by "and" or ","
 my $owner2 = Software::Copyright::Owner->new('Joe <joe@example.com>, William, Jack and Averell');

 $owner2->name; # => is undef
 $owner2->email; # => is undef
 $owner2->record; # => is 'Joe <joe@example.com>, William, Jack and Averell'
 $owner2->identifier; # => is 'Joe <joe@example.com>, William, Jack and Averell'

 # stringification
 $s = "$owner2"; # => is 'Joe <joe@example.com>, William, Jack and Averell'

=head1 DESCRIPTION

This class holds the name and email of a copyright holder.

=head1 CONSTRUCTOR

The constructor can be called without argument or with a string
containing a name and an optional email address. E.g:

 my $owner = Software::Copyright::Owner->new();
 my $owner = Software::Copyright::Owner->new('Joe');
 my $owner = Software::Copyright::Owner->new('Joe <joe@example.com>');

It can also be called with copyright assignment involving more than
one person. See synopsis for details.

=head1 Methods

=head2 name

Set or get owner's name. Note that names with Unicode characters are
normalized to Canonical Composition (NFC). Name can be empty when the
copyright owners has more that one name (i.e. C<John Doe and Jane
Doe>) or if the string passed to C<new()> contains unexpected
information (like a year).

=head2 record

Set or get the record of a copyright. The record is set by constructor
when the owner contains more than one name or if the owner contains
unexpected information.

=head2 identifier

Returns C<name> or C<record>.

=head2 email

Set or get owner's email

=head2 stringify

Returns a string containing name (or record) and email (if any) of the copyright
owner.

=head2 Operator overload

Operator C<""> is overloaded to call C<stringify>.

=cut
