package PDF::Writer::pdfapi2;

use strict;
use warnings;

our $VERSION = '0.01';

use charnames ':full';
use PDF::API2 0.40;

=head1 NAME

PDF::Writer::pdfapi2 - PDF::API2 backend

=head1 SYNOPSIS

(internal use only)

=head1 DESCRIPTION

No user-serviceable parts inside.

=cut

my %dispatch = (
    pdf => [qw( stringify info )],
    txt => [qw( font )],
    gfx => [qw( move line linewidth stroke fill circle )],
    ''  => [qw( parameter save_state restore_state end_page )],
);

sub new {
    my $class = shift;
    return bless({ pdf => PDF::API2->new }, $class);
}

sub open {
    my ($self, $f) = @_;
    $self->{filename} = $f;
    return !$f || (!-e $f or (!-d $f and -w $f));
}

sub save {
    my $self = shift; my $p = $self->{pdf};
    $p->saveas($self->{filename});
}

sub open_image {
    my $self = shift; my $p = $self->{pdf};
    my ($type, $file, $foo, $bar) = @_;

    require "PDF/API2/Resource/XObject/Image/\U$type\E.pm";
    return "PDF::API2::Resource::XObject::Image::\U$type\E"->new($p->{pdf}, $file);
}

sub image_width {
    my $self = shift; my $p = $self->{pdf};
    my ($image) = @_;
    return $image->width;
}

sub image_height {
    my $self = shift; my $p = $self->{pdf};
    my ($image) = @_;
    return $image->height;
}

sub place_image {
    my $self = shift; my $p = $self->{pdf};
    my ($image, $x, $y, $scale) = @_;
    #$y -= $image->height;
    $self->{gfx}->image($image, $x, $y, $scale);
}

sub close_image {
}

sub find_font {
    my $self = shift; my $p = $self->{pdf};
    my ($face, $pdf_encoding, $is_embed) = @_;
    my $mode = (
        ($face =~ /\.(?:pf[ab]|ps)$/i)
            ? 'ps' :
        ($face =~ /\.(?:ttf|otf|ttc)$/i)
            ? 'tt' :
        ($face =~ /(traditional|simplified|korean|japanese2?)/)
            ? 'cjk'
        : 'core'
    ) . 'font';

    # XXX - handle $pdf_encoding and $is_embed?
    return $p->can($mode)->($p, $face);
}

sub begin_page {
    my $self = shift; my $p = $self->{pdf};
    my ($width, $height) = @_;

    my $page = $p->page;
    $page->mediabox($width, $height);

    $self->{gfx} = $page->gfx;
    $self->{txt} = $page->text;
    $self->{page} = $page;

    return $page;
}

sub color {
    my $self = shift; my $p = $self->{pdf};
    my ($mode, $palette, @colors) = @_;

    die 'Palette other than "rgb" is not supported' unless $palette eq 'rgb';

    $self->{gfx}->fillcolor(@colors) unless $mode eq 'stroke';
    $self->{gfx}->strokecolor(@colors) unless $mode eq 'fill';
    $self->{txt}->fillcolor(@colors) unless $mode eq 'stroke';
    $self->{txt}->strokecolor(@colors) unless $mode eq 'fill';
}

my @SuperScript = (
    "\N{SUPERSCRIPT ZERO}", "\N{SUPERSCRIPT ONE}", "\N{SUPERSCRIPT TWO}",
    "\N{SUPERSCRIPT THREE}", "\N{SUPERSCRIPT FOUR}", "\N{SUPERSCRIPT FIVE}",
    "\N{SUPERSCRIPT SIX}", "\N{SUPERSCRIPT SEVEN}", "\N{SUPERSCRIPT EIGHT}",
    "\N{SUPERSCRIPT NINE}",
);
my @SubScript = (
    "\N{SUBSCRIPT ZERO}", "\N{SUBSCRIPT ONE}", "\N{SUBSCRIPT TWO}",
    "\N{SUBSCRIPT THREE}", "\N{SUBSCRIPT FOUR}", "\N{SUBSCRIPT FIVE}",
    "\N{SUBSCRIPT SIX}", "\N{SUBSCRIPT SEVEN}", "\N{SUBSCRIPT EIGHT}",
    "\N{SUBSCRIPT NINE}",
);

sub show_boxed {
    my $self = shift; my $p = $self->{pdf};
    my ($str, $x, $y, $w, $h, $j, $m) = @_;
    my $txt = $self->{txt};

    return 0 if $m eq 'blind';

    my $method = 'text';
    if ($j =~ /right/) {
        $x += $w;
        $method .= "_$j";
    }
    elsif ($j =~ /center/) {
        $x += $w / 2;
        $method .= "_$j";
    }

    $txt->translate($x, $y);

    my @tokens = split(/ /, $str);
    my @try;
    my $advance_width;
    while (@tokens) {
        push @try, shift(@tokens);
        $advance_width = $txt->advancewidth("@try");
        if ($advance_width >= $w) {
            # overflow only if absolutely neccessary
            pop @try if @try > 1;

            my $chunk = $self->_transform_text("@try");
            $self->_draw_underline($txt->advancewidth($chunk)) if $j =~ /underline/;

            # XXX - sup/sub handling here
            $txt->can($method)->($self->{txt}, $chunk);
            return length($str) - length($chunk);
        }
    }

    my $chunk = $self->_transform_text($str);
    $self->_draw_underline($txt->advancewidth($chunk)) if $j =~ /underline/;
    $txt->can($method)->($self->{txt}, $chunk);

    return 0;
}

sub _transform_text {
    my ($self, $text) = @_;
    my $found;
    foreach my $i (0..9) {
        # XXX - handle subscript.
        # also, redraw using ->transform, instead of substituting
        $found++ if $text =~ s/$SuperScript[$i]/<-<$i>->/g;
    }
    if ($found) {
        $text =~ s/>-><-<//g;
        $text =~ s/ ?<-</ [/g;
        $text =~ s/>->/]/g;
    }
    return $text;
}

sub _draw_underline {
    my $self = shift;
    my $width = shift or return;

    my ($txt, $gfx) = @{$self}{'txt', 'gfx'};

    my %state = $txt->textstate;
    my ($x1, $y1) = $txt->textpos;
    $txt->matrix_update($width, 0);
    my ($x2, $y2) = $txt->textpos;
    my $x3 = $x1 + (($y2 - $y1) / $width)
             * ($txt->{' font'}->underlineposition * $txt->{' fontsize'} / 1000);
    my $y3 = $y1 + (($x2 - $x1) / $width)
             * ($txt->{' font'}->underlineposition * $txt->{' fontsize' }/ 1000);
    my $x4 = $x3 + ($x2 - $x1);
    my $y4 = $y3 + ($y2 - $y1);
    $gfx->save;
    $gfx->linewidth(0.5);
    $gfx->strokecolor(0, 0, 0);
    $gfx->move($x3, $y3);
    $gfx->line($x4, $y4);
    $gfx->stroke;
    $gfx->restore;
    $txt->textstate(%state);
}

sub show_xy {
    my $self = shift; my $p = $self->{pdf};
    my ($str, $x, $y) = @_;

    $self->{txt}->translate($x, $y);
    $self->{txt}->text($str);
}

sub font_size {
    my $self = shift; my $p = $self->{pdf};
    return $self->{txt}{' fontsize'};
}

sub rect {
    my $self = shift; my $p = $self->{pdf};
    my $gfx = $self->{gfx};
    $gfx->linewidth(0.2);
    $gfx->rect(@_);
}

sub fill_stroke {
    my $self = shift; my $p = $self->{pdf};
    my $gfx = $self->{gfx};
    $gfx->fillstroke(@_);
}

sub close { %{$_[0]} = (); }

sub add_weblink {
    die "->add_weblink is not implemented yet for pdfapi2."
}

sub add_bookmark {
    die "->add_bookmark is not implemented yet for pdfapi2."
}

while (my ($k, $v) = each %dispatch) {
    foreach my $method (@$v) {
        no strict 'refs';
        if ($k) {
            *$method = sub {
                my $self = shift;
                $self->{$k}->can($method)->($self->{$k}, @_);
            };
        }
        else {
            *$method = sub {
                return 1;
            }
        }
    }
}

1;

=head1 AUTHORS

Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>

=head1 COPYRIGHT

Copyright 2004, 2005 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

See L<http://www.perl.com/perl/misc/Artistic.html>

=cut