package PDF::API2::Annotation;

use base 'PDF::API2::Basic::PDF::Dict';

use strict;
use warnings;

our $VERSION = '2.043'; # VERSION

use Carp;
use PDF::API2::Basic::PDF::Utils;

=head1 NAME

PDF::API2::Annotation - Add annotations to a PDF

=head1 SYNOPSIS

    my $pdf = PDF::API2->new();
    my $font = $pdf->font('Helvetica');
    my $page1 = $pdf->page();
    my $page2 = $pdf->page();

    my $content = $page1->text();
    my $message = 'Go to Page 2';
    my $size = 18;
    $content->distance(1 * 72, 9 * 72);
    $content->font($font, $size);
    $content->text($message);

    my $annotation = $page1->annotation();
    my $width = $content->text_width($message);
    $annotation->rect(1 * 72, 9 * 72, 1 * 72 + $width, 9 * 72 + $size);
    $annotation->link($page2);

    $pdf->save('sample.pdf');

=head1 METHODS

=cut

sub new {
    my $class = shift();
    my $self = $class->SUPER::new();
    $self->{'Type'}   = PDFName('Annot');
    $self->{'Border'} = PDFArray(PDFNum(0), PDFNum(0), PDFNum(0));
    return $self;
}

=head2 Annotation Types

=head3 link

    $annotation = $annotation->link($destination, $location, @args);

Link the annotation to another page in this PDF.  C<$location> and C<@args> are
optional and set which part of the page should be displayed, as defined in
L<PDF::API2::NamedDestination/"destination">.

C<$destination> can be either a L<PDF::API2::Page> object or the name of a named
destination defined elsewhere.

=cut

sub link {
    my $self = shift();
    my $destination = shift();

    my $location;
    my @args;

    # Deprecated options
    my %options;
    if ($_[0] and $_[0] =~ /^-/) {
        %options = @_;
    }
    else {
        $location = shift();
        @args = @_;
    }

    $self->{'Subtype'} = PDFName('Link');
    unless (ref($destination)) {
        $self->{'Dest'} = PDFStr($destination);
        return $self;
    }

    $self->{'A'} = PDFDict();
    $self->{'A'}->{'S'} = PDFName('GoTo');

    unless (%options) {
        $self->{'A'}->{'D'} = _destination($destination, $location, @args);
    }
    else {
        # Deprecated
        $self->dest($destination, %options);
        $self->rect(@{$options{'-rect'}})     if defined $options{'-rect'};
        $self->border(@{$options{'-border'}}) if defined $options{'-border'};
    }

    return $self;
}

sub _destination {
    require PDF::API2::NamedDestination;
    return PDF::API2::NamedDestination::_destination(@_);
}

=head3 url

    $annotation = $annotation->uri($uri);

Launch C<$uri> -- typically a web page -- when the annotation is selected.

=cut

# Deprecated (renamed)
sub url { return uri(@_) }

sub uri {
    my ($self, $uri, %options) = @_;

    $self->{'Subtype'}  = PDFName('Link');
    $self->{'A'}        = PDFDict();
    $self->{'A'}->{'S'} = PDFName('URI');
    $self->{'A'}->{'URI'} = PDFStr($uri);

    # Deprecated
    $self->rect(@{$options{'-rect'}})     if defined $options{'-rect'};
    $self->border(@{$options{'-border'}}) if defined $options{'-border'};

    return $self;
}

=head3 file

    $annotation = $annotation->launch($file);

Open C<$file> when the annotation is selected.

=cut

sub file { return launch(@_) }

sub launch {
    my ($self, $file, %options) = @_;
    $self->{'Subtype'}  = PDFName('Link');
    $self->{'A'}        = PDFDict();
    $self->{'A'}->{'S'} = PDFName('Launch');
    $self->{'A'}->{'F'} = PDFStr($file);

    # Deprecated
    $self->rect(@{$options{'-rect'}})     if defined $options{'-rect'};
    $self->border(@{$options{'-border'}}) if defined $options{'-border'};

    return $self;
}

=head3 pdf

    $annotation = $annotation->pdf($file, $page_number, $location, @args);

Open the PDF file located at C<$file> to the specified page number.
C<$location> and C<@args> are optional and set which part of the page should be
displayed, as defined in L<PDF::API2::NamedDestination/"destination">.

=cut

# Deprecated
sub pdfile   { return pdf_file(@_) }
sub pdf_file { return pdf(@_) }

sub pdf {
    my $self = shift();
    my $file = shift();
    my $page_number = shift();
    my $location;
    my @args;

    # Deprecated options
    my %options;
    if ($_[0] and $_[0] =~ /^-/) {
        %options = @_;
    }
    else {
        $location = shift();
        @args = @_;
    }

    $self->{'Subtype'}  = PDFName('Link');
    $self->{'A'}        = PDFDict();
    $self->{'A'}->{'S'} = PDFName('GoToR');
    $self->{'A'}->{'F'} = PDFStr($file);

    unless (%options) {
        my $destination = PDFNum($page_number);
        $self->{'A'}->{'D'} = _destination($destination, $location, @args);
    }
    else {
        # Deprecated
        $self->dest(PDFNum($page_number), %options);
        $self->rect(@{$options{'-rect'}})     if defined $options{'-rect'};
        $self->border(@{$options{'-border'}}) if defined $options{'-border'};
    }

    return $self;
}

=head3 text

    $annotation = $annotation->text($text);

Define the annotation as a text note with the specified content.

=cut

sub text {
    my ($self, $text, %options) = @_;
    $self->{'Subtype'} = PDFName('Text');
    $self->content($text);

    # Deprecated
    $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};
    $self->open($options{'-open'})    if defined $options{'-open'};

    return $self;
}

=head3 movie

    $annotation = $annotation->movie($filename, $content_type);

Embed and link to the movie located at $filename with the specified MIME type.

=cut

sub movie {
    my ($self, $file, $content_type, %options) = @_;
    $self->{'Subtype'}      = PDFName('Movie');
    $self->{'A'}            = PDFBool(1);
    $self->{'Movie'}        = PDFDict();
    $self->{'Movie'}->{'F'} = PDFDict();

    $self->{' apipdf'}->new_obj($self->{'Movie'}->{'F'});
    my $f = $self->{'Movie'}->{'F'};
    $f->{'Type'}          = PDFName('EmbeddedFile');
    $f->{'Subtype'}       = PDFName($content_type);
    $f->{' streamfile'} = $file;

    # Deprecated
    $self->rect(@{$options{'-rect'}}) if defined $options{'-rect'};

    return $self;
}

=head2 Common Annotation Attributes

=head3 rect

    $annotation = $annotation->rect($llx, $lly, $urx, $ury);

Define the rectangle around the annotation.

=cut

sub rect {
    my ($self, @coordinates) = @_;
    unless (scalar @coordinates == 4) {
        die "Incorrect number of parameters (expected four) for rectangle";
    }
    $self->{'Rect'} = PDFArray(map { PDFNum($_) } @coordinates);
    return $self;
}

=head3 border

    $annotation = $annotation->border($h_radius, $v_radius, $width);

Define the border style.  Defaults to 0, 0, 0 (no border).

=cut

sub border {
    my ($self, @attributes) = @_;
    unless (scalar @attributes == 3) {
        croak "Incorrect number of parameters (expected three) for border";
    }
    $self->{'Border'} = PDFArray(map { PDFNum($_) } @attributes);
    return $self;
}

=head3 content

    $annotation = $annotation->content(@lines);

Define the text content of the annotation, if applicable.

=cut

sub content {
    my ($self, @lines) = @_;
    my $text = join("\n", @lines);
    $self->{'Contents'} = PDFStr($text);
    return $self;
}

sub name {
    my ($self, $name) = @_;
    $self->{'Name'} = PDFName($name);
    return $self;
}

=head3 open

    $annotation = $annotation->open($boolean);

Set the annotation to initially be either open or closed.  Only relevant for
text annotations.

=cut

sub open {
    my ($self, $value) = @_;
    $self->{'Open'} = PDFBool($value ? 1 : 0);
    return $self;
}

sub dest {
    my ($self, $page, %options) = @_;

    unless (ref($page)) {
        $self->{'Dest'} = PDFStr($page);
        return $self;
    }

    $self->{'A'} //= PDFDict();
    $options{'-xyz'} = [undef, undef, undef] unless keys %options;

    if (defined $options{'-fit'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fit');
    }
    elsif (defined $options{'-fith'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fith', $options{'-fith'});
    }
    elsif (defined $options{'-fitb'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fitb');
    }
    elsif (defined $options{'-fitbh'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fitbh', $options{'-fitbh'});
    }
    elsif (defined $options{'-fitv'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fitv', $options{'-fitv'});
    }
    elsif (defined $options{'-fitbv'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fitbv', $options{'-fitbv'});
    }
    elsif (defined $options{'-fitr'}) {
        $self->{'A'}->{'D'} = _destination($page, 'fitr', @{$options{'-fitr'}});
    }
    elsif (defined $options{'-xyz'}) {
        $self->{'A'}->{'D'} = _destination($page, 'xyz', @{$options{'-xyz'}});
    }

    return $self;
}

1;
