#!/usr/bin/perl -w

use strict;
use XML::Parser;
use LWP::UserAgent; 
use LWP::Simple;  # used to fetch the chatterbox ticker
use Archive::Zip qw(:ERROR_CODES);
use Cwd;
use File::Find;
use Getopt::Std;

my $message;      # Hashref containing infos on a message
my $iRTNavPoint=0; # Used to track the parent NavPoint
my $fname = 'toc.ncx';
my $TOCFN;
my $zip;
my @input = @ARGV;
my %opt;
my $opt_string='Rh';

my $parser = new XML::Parser ( Handlers => {   # Creates our parser object
                            Start   => \&hdl_start,
                            End     => \&hdl_end,
                            Char    => \&hdl_char,
                            Default => \&hdl_def,
                          });

# Get command line options
getopts( "$opt_string", \%opt );

Help() if ($opt{'h'});

# Default is to treat parms as individual
# epub files.  Unless the recursive option 'R' is
# in effect.
unless ($opt{'R'}){
	Help() if $#input < 0;

	foreach my $zipFile (@input){
		singleFile($zipFile);
	}
}else{
	find (\&ePUBFinder, cwd);
}

exit;

# Recursive method for the script
# looks for any ePUB in the current 
# directory and it's children
sub ePUBFinder{
	my $file = $File::Find::name;
    my @suffix = ('.epub','.ePUB','.ePub','.EPUB');
   
	return unless -f $file;
	return unless $file=~m/.epub$/i;

	singleFile($file);
}

sub singleFile{
    my $zipFile = shift;
	$zip = Archive::Zip->new();
	print "Fixing file[$zipFile]\n";
    extract_toc($zipFile, $fname);
    open $TOCFN, ">toc_mod.ncx";
    update_toc($fname);
    update_zip($fname);
    unlink $fname;
}

 
sub extract_toc{
	my $zipName = shift;
	my $fileName = shift;

	my $status = $zip->read( $zipName );
	die "Read of $zipName failed\n" if $status != AZ_OK;
    
	$zip->extractMemberWithoutPaths($fileName);
	die "Extracting $fileName from $zipName failed\n" if $status != AZ_OK;
}

sub update_toc{
	my $fileName = shift;

	print $TOCFN "<?xml version='1.0' encoding='UTF-8'?>\n";
	$parser->parsefile($fileName);
	close $TOCFN;

	unlink ($fileName);
	rename('toc_mod.ncx', $fileName);
}
sub update_zip{
	my $file = shift;
	$zip->removeMember($file);
	$zip->addFile($file);
	$zip->overwrite();
}
 
# The XML Handlers
sub hdl_start{
    my ($p, $elt, %atts) = @_;

	$iRTNavPoint++  if $elt eq 'navPoint';


	if ($iRTNavPoint == 1){
    	if ($elt eq 'content') {
    		foreach my $szAttribute (keys %atts){
    			if ($szAttribute eq 'src'){
    				$atts{$szAttribute} =~s/^(.*)#.*$/$1/g;
    			}
    		}
    	}
	}
	print $TOCFN "<$elt";
	foreach my $szAttribute (reverse keys %atts){
		print $TOCFN " $szAttribute=\"$atts{$szAttribute}\" ";
	}
	print $TOCFN ">";
}
 
sub hdl_end{
    my ($p, $elt) = @_;
	$iRTNavPoint--  if ($elt eq "navPoint");

	print $TOCFN "</$elt>";
}

sub hdl_char {
	my ($p, $str) = @_;
	print $TOCFN "$str";
}

sub hdl_def { }  # We just throw everything else
# END XML HANDLERS

sub Help{
    my $this = shift;
    my ($outfile) =  ($0=~ m/^.*[\\|\/](.*)$/s); #only filename.

    print STDERR "\n";
    print STDERR "  usage: $outfile eBookName.epub\n";
    print STDERR "\n";
    print STDERR "\t-h          : this (help) message\n";
    print STDERR "\t-R          : Recursively search for ePUBs\n";
    print STDERR "\n";
    print STDERR "  Example: $outfile -R \n";
    print STDERR "    Will recursively search for ePUBs in\n";
    print STDERR "    the current directory and all its children.\n";
    print STDERR "\n";
    print STDERR "  Example: $outfile MYeBook.epub YOUReBook.epub OUReBOOK.epub\n";
    print STDERR "    Will only fix the eBooks specified.\n";
    print STDERR "\n";

    exit;
}
