#!/usr/bin/perl -w
#  Author        : Dr. Detlef Groth dgroth(at)gmx(dot)de
#  Created       : Sat Oct 21 07:27:38 2006
#  Last Modified : <070603.1811>
# $Log:$
package CombinePDFs;
our $VERSION = "0.2" ;
use PDF::Reuse;
use strict;
our @parts ; # keeps track of the pages ranges
our $total = 0 ; # current page number
sub addDoc {
    my $file = shift ;
    my $pages = shift;
    my $n = 0 ;
    if ($pages =~ m/^[0-9]+$/) {
        # single page
        prDoc($file,$pages,$pages);
        $n = 1 ;
    } elsif  ($pages =~ m/^[0-9]+-[0-9]+$/) {
        # pagerange
        my @range = split(/-/,$pages);
        $n = prDoc($file,$range[0],$range[1]);
    } elsif  ($pages =~ m/^[0-9]+-end+$/) {
        # pages till the end of the document
        my @range = split(/-/,$pages);
        $n = prDoc($file,$range[0]);
    } elsif ($pages eq "all") {
        $n = prDoc($file);
    } 
    $total += $n ;
    #print "$file\t$total\n";
}
sub createBookmarks {
    my $file = shift;
    my @last_levels ; 
    my @bookmarks ;
    my $cnt = 0 ;
    my $current  ;
    open (FILE, "$file") or die "Could not open file $file at $!" ;
    while (<FILE>) {
        next if /^\n/ ;
        if (/^([0-9])\s+"(.+)"\s+([0-9]+)\s*([0-9]*)/) {
            my $level = $1 ;
            my $text = $2 ;
            my $page = $3;
            $page-- ;
            my $scroll = $4;
            if ($level == 0) {
                if ($current) {
                    $bookmarks[$cnt++] = $current;
                }
                # redefine current
                if ($scroll) {
                    $current = {
                        text => $text,
                        act => "$page,40,$scroll",
                        page => "$page,40,$scroll",
                        close => 1
                    };
                } else {
                    $current = {
                        text => $text,
                        close => 1 ,
                        act => "this.pageNum = $page;",
                        page => "$page"
                    };
                }
            } elsif ($level >= 1) {
                my $mark ;
                if ($scroll) {
                    $mark = {
                        text => $text,
                        act => "$page,40,$scroll",
                        page => "$page,40,$scroll"
                    };
                } else {
                    $mark = {
                        text => $text,
                        act => "this.pageNum = $page;",
                        page => "$page"
                    };
                }
                if ($level == 1) {
                    if ($current->{kids}) {
                        push @{$current->{kids}}, $mark;
                    } else {
                        $current->{kids} = [$mark];
                    }
                } elsif ($level == 2) {
                    if ($current->{kids}[-1]->{kids}) {
                        push @{$current->{kids}[-1]->{kids}}, $mark ;
                    } else {
                        $current->{kids}[0]->{kids} =  [$mark] ;
                    }
                } elsif ($level == 3) {
                    if ($current->{kids}[-1]->{kids}[-1]) {
                        push @{$current->{kids}[-1]->{kids}[-1]->{kids}}, $mark ;
                    } else {
                        $current->{kids}[-1]->{kids}[0]->{kids} =  [$mark] ;
                    }
                }
            }
        }
    }
    close (FILE);
    $bookmarks[$cnt] = $current;
    #prBookmark({text => "Dokument", close => 1, kids => \@bookmarks});
    prBookmark(\@bookmarks);
}
sub createPDF {
    my $infile = shift ;
    my @infile = @{$infile} ;
    my $pages = shift ;
    my @pages = @{$pages} ;
    @parts = ();
    $total = 0;
    my $outfile = shift ;
    my $bookmarks = shift ;
    my $ndocs = $#pages ;
    unlink $outfile if (-e $outfile) ;
    unlink "$outfile.tmp" if (-e "$outfile.tmp") ;
    prFile($outfile);
    if($bookmarks) {
        createBookmarks($bookmarks);
    }
    foreach my $x (0..$ndocs) {
        push(@parts,$total);
        foreach my $prange (split(/,/,$pages[$x])) {
            addDoc($infile[$x],$prange);
        }
    }
    # last entry must be added as well
    push(@parts,$total);
    prEnd();
}
sub isPDF {
    my $pdffile = shift;
    open (PDFFILE, "$pdffile") or die "Could not open file at $!" ;
    my $header = <PDFFILE> ;
    my $res = 0 ;
    if ($header =~ m/^%PDF-1.[0-9]/) {
        $res = 1 ;
    }
    close (PDFFILE);
}
sub getPagesParts {
   return @parts ;
}
sub addBookmarksByArray {
    my $infile = shift ;
    my $outfile = shift ;
    my @partnames = @_ ;
    my @last_levels ;
    my @bookmarks ;
    my $cnt = 0 ;
    my $current  ;
    my $mark ;
    my $x = 0 ;
    foreach my $part (@partnames) {
        my @bm = split(/\t/,$part) ;
        if ($bm[0] == 0) {
            if ($current) {
                $bookmarks[$cnt++] = $current;
            }
            # redefine current
            if ($parts[$x] eq "None") {
                $current = {
                    text => $bm[1],
                    close => 1 
                };
            } else {
                $current = {
                    text => $bm[1],
                    close => 1 ,
                    act => "this.pageNum = $parts[$x];",
                    page => "$parts[$x]"
                };
            }
        } elsif ($bm[0] == 1) {
            $mark = {
                text => $bm[1],
                act => "this.pageNum = $parts[$x];",
                page => "$parts[$x]"
                #act => $parts[$x]
            };
            if ($current->{kids}) {
                push @{$current->{kids}}, $mark;
            } else {
                $current->{kids} = [$mark];
            }

        } 
        $x++;
    }
    $bookmarks[$cnt] = $current;
    prFile($outfile);
    prBookmark(\@bookmarks);
    prDoc($infile);
    prEnd();
    prBookmark(\@bookmarks);
    prDoc($infile);
    prEnd();
    
}
1;

__END__

=head1 NAME

CombinePDFs - utility package for combining PDF documents with PDF::Reuse

=head1 SYNOPSIS

    use CombinePDFs;
    prFile('myFile.pdf');
    my @infiles = ('in1.pdf','in2.pdf','in1.pdf');
    my @ranges  = ('1-4,5','9-12','8-10');
    if (CombinePDFs::isPDF(@infiles)) {
        CombinePDFs::createPDF(\@infiles,\@ranges,'outfile.pdf');
    }
    prEnd();
    
=head1 DESCRIPTION
    
This module provides an high level abstraction layer over the great PDF::Reuse module of Lars Lundberg.


=head1 FUNCTION

=head2 createPDF - add files with possible page ranges

 createPDF(\@infiles,\@ranges,$outfile,[$bookmarksfile])
 
The specified range might be a single page specified with a number,
a range specified like from-to or the complete document specified with the keyword all. 
Different parts of a document can be separated with commas like seen in the SYNOPSIS.
The optional $bookmarksfile must have the following format:

 <level> "<booomark text" <pagenumber>

Root bookmarks have level=0, their childs level=1 and grandchilds level=2 and so on.

=head2 isPDF - check a file if has a valid PDF-header

 isPDF($filename)
 
Checks a file if ith contains a valid PDF-header.

 
=cut