#!/usr/bin/env perl

#    mobi2imp, Copyright (C) 2008 Nick Rapallo, nrapallo@yahoo.ca
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#    mobi2html, base code (C) 2008 Tommy Persson, tpe@ida.liu.se
#    The additional source code used to build the binary is available at
#    <http://www.ida.liu.se/~tompe/mobiperl/>, the MobiPerl repository.

use FindBin qw($RealBin);
use lib "$RealBin";

use HTML::TreeBuilder;
use Palm::PDB;
use Palm::Doc;
use Image::Size;
use Date::Parse;
use Date::Format;
use Getopt::Mixed;

use MobiPerl::EXTH;
use MobiPerl::Util;

use GD::Image;
use File::Basename;

use strict;

use vars qw ($opt_rawhtml $opt_record0 $opt_saveallrecords $opt_mobihtml $opt_explodedir
             $opt_1200 $opt_1150 $opt_1100 $opt_oeb $opt_verbose $opt_debug $opt_out 
             $opt_BDbig $opt_BDnewpage $opt_BDremove $opt_noBRfix $opt_bgcolor
             $opt_nomargins $opt_tinymargins $opt_largemargins $opt_hugemargins
             $opt_smallerfont $opt_largerfont $opt_nojustify $opt_nopara
             $opt_indent $opt_header_hr $opt_header_color $opt_cover);

Getopt::Mixed::getOptions ("rawhtml record0 saveallrecords mobihtml explodedir=s
                            1200 1150 1100 oeb verbose debug out=s
                            BDbig BDnewpage BDremove noBRfix bgcolor=s
                            nomargins tinymargins largemargins hugemargins
                            smallerfont largerfont nojustify nopara indent
                            header_hr header_color=s cover");

my $fullpathfilename = shift;

###################################################################
#For .IMP start (version 9.1 - 21 Mar 2008)
#
my $impversion = "version 9.1";
my $usage = 'mobi2imp [options] MobiSource [Category [Authorname [Title]]]';
my $category = shift;
my $author = shift;
my $title = shift;

print "\nMobi2IMP ($impversion) Copyright (C) 2008 Nick Rapallo (nrapallo)\n";

if (not defined $fullpathfilename){
    print "Usage: $usage\n";
    print "\n";
    print "Where [options] are:\n";
    print "   [ --verbose ] printout messages about this conversion\n";
    print "   [ --debug ] printout more detailed messages about conversion\n";
    print " Output related:\n";     
    print "   [ --explodedir DIR ] set 'ExplodeDIR' to use instead of default 'Filename'\n";
    print "   [ --out IMPFILENAME ] set .IMP filename to use (overrides default naming)\n";
    print "   [ --1200 | --1100 | --oeb ] simultaneously create these versions with 1150\n";
    print "   [ --1150 ] conversely do not create the 1150 .IMP version\n";
    print "   [ --cover ] add cover page using the existing cover embedded in MobiSource\n";
    print " Style related:\n";
    print "   [ --nomargins ] set left-right margins to 0% instead of default 2%\n";
    print "   [ --tinymargins ] set left-right margins to 2px instead of default 2%\n";
    print "   [ --largemargins ] set left-right margins to 5% instead of default 2%\n";
    print "   [ --hugemargins ] set left-right margins to 8% instead of default 2%\n";
    print "   [ --smallerfont ] use 'x-small' font size for body text not 'small'\n";
    print "   [ --largerfont ] use 'medium' font size for body text not 'small'\n";
    print "   [ --nojustify ] no full justification (i.e. left-aligned) not 'justify'\n";
    print "   [ --nopara ] use no paragraph separation not 'blank line' (1em) separation\n";
    print "   [ --indent ] use small (1em) indent instead of no (0em) indent\n";
    print "   [ --bgcolor #FF80FF ] use color #FF80FF as background color for every page\n";
    print "   [ --header_hr ] use header text 'Title Author' followed by <hr>\n";
    print "   [ --header_color #FF80FF ] use color #FF80FF as header background color only\n";
    print " HTML/BD Fixes:\n";
    print "   [ --BDbig ] make BookDesigner notice at the end 'big print' not small\n";
    print "   [ --BDnewpage ] put BookDesigner notice at the end on a newpage\n";
    print "   [ --BDremove ] remove BookDesigner notice at the end\n";
    print "   [ --noBRfix ] when using '--nopara', don't fix (broken) <br />'s issue\n";
    print "\n";
    print "Required parameters: MobiSource\n";
    print "   MobiSource is the Mobipocket (.prc/.mobi/.pdb) file to convert to .IMP\n";
    print "      if contains spaces, then surround with quotes (i.e. \"My Source.prc\")\n";
    print "   [now --explodedir is directory where to explode mobi file (left behind!)\n";
    print "      can also be \".\" for current directory]\n";
    print "\n";
    print "Optional parameters: [Category [Authorname [Title]]]\n";
    print "   Are all optional; with same being extracted from source file, if present.\n";
    print "\n";
    print "If 'Build' successful, then default .IMP filename is 'Author - Title.ext'\n";
    print "If 'Build' method fails to create ebook, load .opf and manually 'Build' it!\n";
    die "\n" unless 0;
}

my ($fnbody,$fnpath,$fnext) = fileparse("$fullpathfilename",'\.\w+');
my $filename = $fnbody . $fnext;
my $explodedir = $fnbody unless defined $opt_explodedir;

chdir $fnpath;
mkdir $explodedir;

my $htmlfile = $filename;
$htmlfile =~ s/\.mobi/.html/;
$htmlfile =~ s/\.prc/.html/;
$htmlfile =~ s/\.pdb/.html/;
#$htmlfile =~ s/\.azw/.html/;

#
#For .IMP end
###################################################################
print "FULLFILENAME: $fullpathfilename\n";
print "FILENAME    : $filename\n";
print "EXPLODEDIR  : $explodedir\n";

my $pdb = new Palm::PDB;
$pdb->Load($fullpathfilename);

my $name = $pdb->{"name"};
my $version = $pdb->{"version"};
my $type = $pdb->{"type"};
my $creator = $pdb->{"creator"};
my $seed = $pdb->{"uniqueIDseed"};
my $ctime = $pdb->{"ctime"};
my $mtime = $pdb->{"mtime"};
my $sctime = ctime ($ctime);
my $smtime = ctime ($mtime);

print "DatabaseName: $name\n";
print "Version     : $version\n";
print "Type        : $type\n";
print "Creator     : $creator\n";
##print "Seed        : $seed\n";
##print "Resdb       : " . $pdb->{"attributes"}{"ResDB"} . "\n";
##print "AppInfoDirty: " . $pdb->{"attributes"}{"AppInfoDirty"} . "\n";
##print "ctime       : $ctime - $sctime\n";
##print "mtime       : $mtime - $smtime\n";
print "baktime     : " . $pdb->{"baktime"} . "\n";

my @records = @{$pdb->{"records"}};
print "# of records: " . $#records . "\n";
print "---------------------------------------------------\n";

my $image_index = 0;
my %image_index_to_filename = ();
my $coverimageid = -1;

foreach my $r (@records) {
	my $id = $r->{"id"};
	my $cat = $r->{"category"};
	my $offset = $r->{"offset"};
	my $data = $r->{"data"};
	my $size = length ($data);
	my $filename = "record-$id";
	my ($x, $y, $type) = imgsize(\$data);
	if (defined $x) {
	    if (defined $opt_verbose){ print "Image_Index: $image_index - $filename - $cat - $offset - $size - $x x $y\n"; }
	    $image_index++;
	    $image_index_to_filename{$image_index} = "$filename.$type";
	    open DATA, ">$explodedir/$filename.$type";
	    binmode (DATA);
	    print DATA $data;
	    close DATA;
	} else {
	    if (defined $opt_record0 or defined $opt_saveallrecords) {
		open DATA, ">$explodedir/$filename";
		print DATA $data;
		close DATA;
	    }
	}
	if (defined $opt_record0) {
	    exit (0);
	}
	if ($id == 0) {
	    parse_record_0 ($data);
	}
}

#my @resources = @{$pdb->{"resources"}};
#print "Number of resources: " . $#resources . "\n";

my $text = $pdb->text;

#{
#    local $/;
#    $text =~ s/\r//g;
#}

if (defined $opt_rawhtml) {
    binmode (STDOUT);
    print $text;
}

# this doesn't work always with \f
#if (substr ($text, 0, 6) ne "<html>" and 0) {  
#    #$text =~ s/\cM//g;                  # Unix line endings
#    $text =~ s/\f/\n/g;                  # Windows form feeds
#    $text =~ s/\n/\x01/gi;               # Collapse lines
#    $text =~ s/\x01\x01/<\/p>\n\n<p>/g;  # Separate paragraphs
#    $text =~ s/\x01/ /g;                 # Insert whitespace
#
#    $text = "<html><head></head><body><p>" . $text . "</p></body></html>";
#}

# this works better than above but sloppy
if (substr ($text, 0, 6) ne "<html>" && substr ($text, 0, 6) ne "<HTML>" ) {                                       
    open TEMPFILE, ">$explodedir/$htmlfile.txt" or die "Cannot create .txt file";
    binmode (TEMPFILE);
    print TEMPFILE $text;
    close TEMPFILE;

    open TEMPFILE, "$explodedir/$htmlfile.txt" or die "Cannot open .txt file";
    my @lines = <TEMPFILE>;               # Read it into an array
    close TEMPFILE;                       # Close the file

    #unlink "$explodedir/$htmlfile.txt";

    $text = "<HTML><HEAD></HEAD>\n<BODY>\n" ;

    my $line;
    foreach $line (@lines) {              # assign @lines to $line, one at a time
       $text .= "<P>" . $line . "</P>" unless (length($line) == 1);  
    }

    $text .= "\n</BODY>\n</HTML>\n";

}

my %fileposmap;

print "---------------------------------------------------\n";
print "Looking for filepos\n";
my $cp = 0;
my $len = length ($text);
while ($cp < $len) {
    my $s = substr ($text, $cp, 50);
    if (substr ($s, 0, 7) eq "filepos") {
	if ($s =~ /^filepos=(\d+)/) {
	    if (defined $opt_debug){ print "FILEPOS: $cp - $1\n"; }
	    $fileposmap{$1} = 1;
	}
	if ($s =~ /^filepos=\"(\d+)\"/) {
	    if (defined $opt_debug){ print "FILEPOS: $cp - $1\n"; }
	    $fileposmap{$1} = 1;
	}
    }
    $cp++;
}
print "Found all filepos\n";

my $offset = 0;

print "Adding name attributes\n";
foreach my $pos (sort keys %fileposmap) {
    if (defined $opt_debug){ print "NAMEPOS: $pos\n"; }
    my $a = substr ($text, $pos+$offset, 2);
    if ($a eq "<a" or $a eq "<A") {
	substr ($text, $pos+$offset, 2, "<a name=\"" . $pos . "\"");
	$offset += (8 + length ($pos));
	next;
    }
    if ($a eq "<h" or $a eq "<H") {
	# Put an empty anchor before header
	substr ($text, $pos+$offset, 2, "<a name=\"" . $pos . "\"></a><h");
	$offset += (15 + length ($pos));
	next;
    }
###################################################################
#For .IMP start - Kludge mainly for feedbooks.com .prc files (ignore warning)
#
    if (substr ($a, 0, 1) eq "<") {
	# Put an empty anchor before start of any HTML tag i.e. "<"
	substr ($text, $pos+$offset, 2, "<a name=\"" . $pos . "\"></a>$a");
	$offset += (15 + length ($pos));
        print "FIXED: $pos - Wasn't an anchor: $a\n";
	next;
    }
    print "WARNING: $pos - Not an anchor: $a\n";
#
#For .IMP end
###################################################################
}

my $tree = new HTML::TreeBuilder ();
$tree->ignore_unknown (0);
$tree->parse ($text);
$tree->eof ();

#my $tree = HTML::TreeBuilder->new_from_content ($text);

fix_filepos_attributes ($tree);
fix_image_tags ($tree);

open HTML, ">$explodedir/$htmlfile" or die "Could not open file $explodedir/$htmlfile";

my $html = $tree->as_HTML;

my $booktitle = $name; # mobi provided name for ebook
$booktitle =~ s/_/ /g; # remove any underlines used as spaces
$booktitle = $title unless not defined $title;
$category = "Converted Mobipocket" unless defined $category;
$author = "Mobipocket" unless defined $author;

my $bookname = $author . " - " . $booktitle;
$bookname = $opt_out unless not defined $opt_out;

if (not defined $opt_mobihtml) {
###################################################################
#For .IMP start
#
#    $html =~ s/<mbp:pagebreak\s*\//<br style=\"page-break-after:always\" \//g;
#    $html =~ s/<mbp:pagebreak\s*/<br style=\"page-break-after:always\" \//g;
#
#For .IMP end
###################################################################
#    $html =~ s/<mbp:pagebreak>/<br style=\"page-break-after:always\"\/>/g;
#    $html =~ s/<mbp:pagebreak>//g;
    $html =~ s/<\/mbp:pagebreak>//g;
    $html =~ s/<\/mbpagebreak>//g;
    $html =~ s/<guide>.*?<\/guide>//g;
    $html =~ s/<mbp:nu>//g;
    $html =~ s/<\/mbp:nu>//g;
    $html =~ s/<mbp:section>//g;
    $html =~ s/<\/mbp:section>//g;
    $html =~ s/<mbp:frameset>//g;
    $html =~ s/<\/mbp:frameset>//g;
    $html =~ s/<mbp:slave-frame>//g;
    $html =~ s/<\/mbp:slave-frame>//g;

    $html =~ s/\/div>/\/div>\n/g; 

###################################################################
#For .IMP start
#

my $headerhr = "\n<HEADER><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr>\n<td align=\"left\">"; 
$headerhr .= "<small>" . $booktitle . "</small></td>\n<td align=\"right\"><small>" . $author . "</small></td></tr></table><hr></HEADER>\n";

my $headercolor = "\n<HEADER><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr>\n<td align=\"left\" bgcolor=\"" . $opt_header_color; 
$headercolor .= "\"><small>" . $booktitle . "</small></td>\n<td align=\"right\" bgcolor=\"" . $opt_header_color . "\"><small>" . $author . "</small></td></tr></table></HEADER>\n";

if (defined $opt_bgcolor) {
    $html =~ s/<body([^>])*>/\n<BODY bgcolor=$opt_bgcolor>\n/i;  #remove .mobi defaults in <body> and insert bgcolor
} else {
    $html =~ s/<body([^>])*>/\n<BODY>\n/i;                       #remove .mobi defaults in <body>
}

if (defined $opt_header_hr) {
        $html =~ s/<body([^>])*>/<BODY$1>\n$headerhr/i;          #remove .mobi defaults in <body> and insert header-hr
} elsif (defined $opt_header_color) {
        $html =~ s/<body([^>])*>/<BODY$1>\n$headercolor/i;       #remove .mobi defaults in <body> and insert header-color
}

if (defined $opt_nopara and not defined $opt_noBRfix) {
    $html =~ s/<br([^>])*><div/<BR \/><BR \/><div/g;             #force <br /> to work in Ebook Publisher
}

if (defined $opt_indent) {
    #indent (~2 characters)
    if (defined $opt_nopara) {
        $html =~ s/<\/head>/<STYLE type=\"text\/css\">p {text-indent:1em; margin-top:0em; margin-bottom:0em} header {display:none; display:oeb-page-head}<\/STYLE><\/head>/i;   #nopara separation (--nopara)
    } else {
        $html =~ s/<\/head>/<STYLE type=\"text\/css\">p {text-indent:1em; padding-top:0em; padding-bottom:1em} header {display:none; display:oeb-page-head}<\/STYLE><\/head>/i;   #para separation (default)
    }
} else {
    #noindent (default)
    if (defined $opt_nopara) {
        $html =~ s/<\/head>/<STYLE type=\"text\/css\">p {text-indent:0em; margin-top:0em; margin-bottom:0em} header {display:none; display:oeb-page-head}<\/STYLE><\/head>/i;   #nopara separation (--nopara)
    } else {
        $html =~ s/<\/head>/<STYLE type=\"text\/css\">p {text-indent:0em; padding-top:0em; padding-bottom:1em} header {display:none; display:oeb-page-head}<\/STYLE><\/head>/i;   #para separation (default)
    }
}

if (defined $opt_nojustify) {
    #nojustify body text (left-align)
    if (defined $opt_smallerfont) {
        $html =~ s/<body/<BODY style=\"margin-left:2%; margin-right:2%; font-size:x-small; text-align:left\"/i; # add small margins and left-align text
    } elsif (defined $opt_largerfont) {
        $html =~ s/<body/<BODY style=\"margin-left:2%; margin-right:2%; font-size:medium; text-align:left\"/i; # add small margins and left-align text
    } else {
        $html =~ s/<body/<BODY style=\"margin-left:2%; margin-right:2%; text-align:left\"/i; # add small margins and left-align text
    }
} else {
    #justify body text (default)
    if (defined $opt_smallerfont) {
        $html =~ s/<body/<BODY style=\"margin-left:2%; margin-right:2%; font-size:x-small; text-align:justify\"/i; # add small margins and justified text
    } elsif (defined $opt_largerfont) {
        $html =~ s/<body/<BODY style=\"margin-left:2%; margin-right:2%; font-size:large; text-align:justify\"/i; # add small margins and justified text
    } else {
        $html =~ s/<body/<BODY style=\"margin-left:2%; margin-right:2%; text-align:justify\"/i; # add small margins and justified text
    }
}

if (defined $opt_nomargins) {
    $html =~ s/<BODY style=\"margin-left:2%; margin-right:2%;/<BODY style=\"margin-left:0%; margin-right:0%;/i; # add no margins instead
} elsif (defined $opt_tinymargins) {
    $html =~ s/<BODY style=\"margin-left:2%; margin-right:2%;/<BODY style=\"margin-left:2px; margin-right:2px;/i; # decrease margins instead
} elsif (defined $opt_largemargins) {
    $html =~ s/<BODY style=\"margin-left:2%; margin-right:2%;/<BODY style=\"margin-left:5%; margin-right:5%;/i; # increase margins instead
} elsif (defined $opt_hugemargins) {
    $html =~ s/<BODY style=\"margin-left:2%; margin-right:2%;/<BODY style=\"margin-left:8%; margin-right:8%;/i; # increase margins instead
}

# make BD notice small text
if (not defined $opt_BDbig) {
    $html =~ s/<div align=\"center\">This file was created with([<br \/>])*BookDesigner program</<font size=1><div align=\"center\">This file was created with BookDesigner program</i;
}
# put BD notice on new page and in small text if specified
if (defined $opt_BDnewpage) {
    $html =~ s/<div align=\"center\">This file was created with([<br \/>])*BookDesigner program</<p style=\"page-break-before: always\"><div align=\"center\">This file was created with BookDesigner program</i;
}
# remove BD notice!
if (defined $opt_BDremove) {
    $html =~ s/<div align=\"center\">This file was created with([<br \/>])*BookDesigner program<(.+)*/<\/body><\/html>/is;
}

    $html =~ s/<mbp:pagebreak/<p style=\"page-break-before: always\"/gi; # insert proper page-breaks
    $html =~ s/<mbpagebreak/<p style=\"page-break-before: always\"/gi; # insert proper page-breaks
    $html =~ s/<p/\n<p/gi; # insert newline before '<p' construct
    $html =~ s/<img align="baseline"/<img/gi; # remove the troublesome baseline keyword
    $html =~ s/<p style=\"page-break-before: always\"><\/body>/<\/body>/gi;  #fix up last (unwanted) page-break
    $html =~ s/<div align=\"center\"><img/<div align=\"center\"><p align=\"center\"><img/gi;  # kludge to get eBook Publisher to center images   
#
#For .IMP end
###################################################################

}

print HTML $html;

###################################################################
#For .IMP start
#

flush HTML;

###################################################################
#
# Adapted by Nick Rapallo (January 2008)
#
# Modified code taken directly from "SBPubX.doc" (installed by the eBook Publisher
# software).  Given a single .html it creates .opf project file for later use as well
# as .IMP for GEB/EBW 1150; can change the latter to REB 1200 or REB 1100 or OEBFF by
# passing opt switch for the {BuildTarget} lines below.

use Win32::OLE;
use Win32::OLE qw(EVENTS);
Win32::OLE->Initialize(Win32::OLE::COINIT_APARTMENTTHREADED);

#my $usage='mobi2imp.pl Source.prc [Category [Authorname [Title]]]';
#die "Usage:  $usage\n" if ($#ARGV > 1 and $#ARGV < 5);

###################################################################
#
# get the interfaces, complain and quit if we cannot
#
# .IMP creation requires eBook Publisher to be installed first!
my $project = Win32::OLE->new("SBPublisher.Project") or
	die ".IMP creation requires eBook Publisher to be installed first!\nUnable to get IProject interface\n";

my $builder = Win32::OLE->new("SBPublisher.Builder") or
	die "Unable to get IBuilder interface\n";

# Setup the event handling.
#
#Win32::OLE->WithEvents($builder, 'EventHandlers');

###################################################################
#
# Create a new project and add our document file with optional cover.
#
$project->ClearAll();
if (-e $fnpath . "cover.htm") {
         print "Adding default cover found in $fnpath\n";
         $project->AddSourceFile("cover.htm");
}
if (defined $opt_cover and create_cover_html()) {
         $project->AddSourceFile("$explodedir/cover_nr.html");
}
$project->AddSourceFile("$explodedir/$htmlfile");
 
###################################################################
#
# Set the various "metadata" items for the publication
#
$project->{AuthorFirstName} = $author;
$project->{BookTitle}       = $booktitle;
$project->{Category}        = $category;
#$project->{ISBN} = $project->CanonicalizeISBN("0448163004 ");
#$project->{BISAC} = "FIC004000";

###################################################################
#
# Now build the OEBFF output
#
$project->{OutputDirectory} = ".";
$project->{Compress}        = 1;   #True
$project->{Encrypt}         = 0;   #False
$project->{KeepAnchors}     = 1;   #True
$project->{Language}        = "en";
$project->{RequireISBN}     = 0;   #False
$project->{Zoom}            = 2;

###################################################################
#
# Now (default) build the EBW/GEB 1150 (gray HalfVga) .IMP output
#
if (not defined $opt_1150) {
	$project->{BookFileName}    = $bookname;
	$project->Save($bookname . ".opf");

	$project->{BuildTarget}     = 2;

	# Now generate the .IMP output
	$builder->Build($project);
	if (Win32::OLE->LastError() != 0) {
		print "ERROR: Build method failed for EBW 1150.\n";
	} else {
		print "EBW 1150 ebook created!\n";
	}
}

###################################################################
#
# Now (optionally) build the REB 1200 (FullVga) .IMP output
#
if (defined $opt_1200) {
	$project->{BookFileName}    = $bookname . "_1200";
	$project->Save($bookname . "_1200.opf");
	
	$project->{BuildTarget}     = 1;

	# Now generate the .IMP output
	$builder->Build($project);
	if (Win32::OLE->LastError() != 0) {
		print "ERROR: Build method failed for REB 1200.\n";
	} else {
		print "REB 1200 ebook created!\n";
	}
}

###################################################################
#
# Now (optionally) build the REB 1100 (mono HalfVGA) .RB output
#
if (defined $opt_1100) {
	$project->{BookFileName}    = $bookname;

	$project->{BuildTarget}     = 3;
	
	# Now generate the .RB output
	$builder->Build($project);
	if (Win32::OLE->LastError() != 0) {
		print "ERROR: Build method failed for REB 1100.\n";
	} else {
		print "REB 1100 ebook created!\n";
	}
}

###################################################################
#
# Now (optionally) build OEBFF output
#
if (defined $opt_oeb) {
	$project->{BookFileName}    = $bookname;
	
	$project->{BuildTarget}     = 0;

	# Now generate the OEBFF output
	$builder->GenerateOEBFF($project, 1);
	if (Win32::OLE->LastError() != 0) {
		print "ERROR: GenerateOEBFF method failed for .oeb package.\n";
	} else {
		print "OEBFF (.oeb) ebook created!\n";
	}
}

Win32::OLE->Uninitialize();
#
#For .IMP end
###################################################################

close HTML;


sub fix_image_tags {
    my $tree = shift;
    my @imgel = $tree->find ("img");
    foreach my $img (@imgel) {
	my $recindex = $img->attr ("recindex");
	my $ind = int ($recindex);
	my $filename = $image_index_to_filename{$ind};
###################################################################
#For .IMP start - just rewrite .jpg/.png/.gif image files (fixes non-stnd pics)
#
 if (defined $opt_verbose || defined $opt_debug){ print "FIXED IMAGE/TAGS: $recindex - $ind - $filename\n"; }
 
 my $imagefile = "$explodedir/$filename";
 my $supportedimage = 0;
 
 my $im = $imagefile;
 $im =~ /\.jpe?g$/i and $im = GD::Image->newFromJpeg($imagefile,1) and $supportedimage = 1;
 $im =~ /\.gif$/i   and $im = GD::Image->newFromGif($imagefile) and $supportedimage = 1 and $im->transparent(-1);  #use only non-transparent .gifs
 $im =~ /\.png$/i   and $im = GD::Image->newFromPng($imagefile) and $supportedimage = 1;
 #$im =~ /\.bmp$/i  and next; # not yet implemented in GD, but hopefully not needed here!
 
 #new in version 7 - bugfix for poorly constructed .prc where no image exists (filename=XXXXX)
 if (!$ind) {
    print "ERROR: IMAGE/TAGS not found: $recindex - $ind - $filename (replaced with 'no_image.jpg')\n";
    $img->attr ("recindex", undef);
    $img->attr ("src", "no_image.jpg");
    next;
 }
 if ($supportedimage) {
     my ($width, $height) = $im->getBounds();
     
     my $target_im = new GD::Image($width,$height,1);
     $target_im->copyResized($im,0,0,0,0,$width,$height,$width,$height);
     
     open(IMAGE, "> $imagefile");
     binmode(IMAGE);
     if ($imagefile =~ /\.jpe?g$/i){
         print IMAGE $target_im->jpeg(85);
     } elsif ($imagefile =~ /\.gif$/i) {
        print IMAGE $target_im->gif();
     } elsif ($imagefile =~ /\.png$/i) {
         print IMAGE $target_im->png();
     } #elsif ($imagefile =~ /\.bmp$/i) {
       #  print IMAGE $target_im->bmp();
       #}
     close(IMAGE);
 }
#
#For .IMP end
###################################################################
	$img->attr ("recindex", undef);
	$img->attr ("src", $filename);
    }
}

sub fix_filepos_attributes {
    my $tree = shift;
    my @ael = $tree->find ("a");
    print "Fixing filepos attribute\n";
    foreach my $a (@ael) {
	my $filepos = $a->attr ("filepos");
	if ($filepos) {
	    $a->attr ("href", "\#$filepos");
	    $a->attr ("filepos", undef);
	    if (defined $opt_debug){ print "FIX FILEPOS ATTR: $filepos\n"; }
	}
    }
}

sub parse_record_0 {
    my $rec = shift;
    my $palmdocheader = substr ($rec, 0, 16);
    parse_palmdoc_header ($palmdocheader);
    if ($type eq "BOOK" and $creator eq "MOBI") {
	my $mobiheader = substr ($rec, 16);
	parse_mobi_header ($mobiheader);
    }
}

sub parse_palmdoc_header {
    my $data = shift;
    my ($version, $length, $nrecords, $recsize, $unknown) =
	unpack ("nxxNnnN", $data);
    if (defined $opt_verbose || defined $opt_debug){ 
        print "PDHEADER   Version: $version\n";
        print "PDHEADER    Length: $length\n";
        print "PDHEADER  NRecords: $nrecords\n";
        print "PDHEADER   Recsize: $recsize\n";
        print "PDHEADER   Unknown: $unknown\n";
    }
}

sub parse_mobi_header {
    my $data = shift;
    my ($doctype, $length, $type, $codepage, $uniqueid, $ver) =
	unpack ("a4NNNNN", $data);
    my ($exthflg) = unpack ("N", substr ($data, 0x70));
    if (defined $opt_verbose || defined $opt_debug){ 
        print "MOBIHEADER doctype: $doctype\n";
        print "MOBIHEADER  length: $length\n";
        print "MOBIHEADER    type: $type\n";
        print "MOBIHEADER   codep: $codepage\n";
        print "MOBIHEADER  uniqid: $uniqueid\n";
        print "MOBIHEADER     ver: $ver\n";
        print "MOBIHEADER exthflg: $exthflg\n";
    }

    if ($exthflg & 0x40) {
	my $exth = substr ($data, $length);
	parse_mobi_exth ($exth);
    }
}

sub parse_mobi_exth {
    my $data = shift;
    my ($doctype, $len, $n_items) = unpack ("a4NN", $data);
    print "EXTH doctype: $doctype\n";
    print "EXTH  length: $len\n";
    print "EXTH n_items: $n_items\n";
    my $pos = 12;
    foreach (1..$n_items) {
	my ($id, $size) = unpack ("NN", substr ($data, $pos));
	my $contlen = $size-8;
	my ($id, $size, $content) = unpack ("NNa$contlen", substr ($data, $pos));
	my $hid = sprintf ("%x", $id);
	my $hsize = sprintf ("%x", $size);
	if (MobiPerl::EXTH::is_binary_data ($id)) {
	    $content = MobiPerl::Util::iso2hex ($content);
	}
	print "ITEM: $hid $hsize - $id $size - $content\n";
###################################################################
#For .IMP start
#
	if ($id == 0x64) { $content =~ s/_/ /g; $author = $content unless defined $author; }
	if ($id == 0x69) { $content =~ s/_/ /g; $category = $content unless defined $category; }
	if ($id == 0xC9) {
	    $coverimageid = hex($content);
	    print "----> Cover Image_Index: $coverimageid\n";
	}
#
#For .IMP end
###################################################################
	$pos += $size;
    }
}

sub create_cover_html {     
    if ($coverimageid < 0) {   
        return 0;
    } else {
        my $coverimagefilename = $image_index_to_filename{$coverimageid+1};
        open TEMPFILE, ">$explodedir/cover_nr.html" or die "Cannot create cover.html file";
        binmode (TEMPFILE);

        my $coverhtml = "<HTML><HEAD><STYLE type=\"text/css\">p {text-indent:0em; margin-left:2em; margin-right:2em}</STYLE></HEAD>\n<BODY>\n";
        $coverhtml .= "<p align=center><center><img src=\"$coverimagefilename\"></center></p>\n</BODY>\n</HTML>\n" ;

        print TEMPFILE $coverhtml;
        close TEMPFILE;
        print "Adding cover image: $explodedir/$coverimagefilename\n";
        return 1;
    }
}