#!/usr/bin/perl

# Bruno Bonfils, <asyd@debian-fr.org>
# Create html files from a dokuwiki
#
# Published under term of BSD licence
# (c) 2005
#
# Version: 0.1pre

use strict;
use warnings qw(all);
use Getopt::Long;
use File::Find;
use LWP::UserAgent;
use Pod::Usage;
use Digest::MD5;
use Data::Dumper;
use Text::Iconv;

my $pages;
my $odir;
my $start;
my $dokupath;
my $virtualhost;
my $staticurl;
my $md5 = $ENV{'HOME'} . '/.doku-md5sums';

my $md5sums = ();

GetOptions (
	"pages=s" => \$pages,
	"output=s", => \$odir,
   "start=s", => \$start,
   "dokupath=s", => \$dokupath,
	"virtualhost=s", => \$virtualhost,
	"staticurl=s", => \$staticurl,
   "md5=s" => \$md5,
);

pod2usage(1)
	unless (defined $pages and defined $odir and
			defined $start and defined $dokupath and defined $md5 and
			defined $virtualhost and defined $staticurl);
		
# Check if the output directory exist
unless (-r $odir) {
	mkdir $odir or die "$@";
}

# Check if data is a valid directory
unless (-r $pages) {
	die "The data directory doesn't exist!\n";
}

# Create a new UserAgent
my $ua = new LWP::UserAgent;

# Read md5 files
if (-r $md5) {
	my $fh;
	open ($fh, "< $md5") or die "Can't open $md5 for reading $@";
	while(<$fh>) {
		chomp;
		my ($key,$value) = split (/;/);
		$md5sums->{$key} = $value;
	}
	close ($fh);
}

# For each file in data directory
find (\&make_static, $pages);
write_md5();

# Write md5 files
sub write_md5 {
	my $fh;
	open ($fh, "> $md5") or die "Can't open $md5 $@";
	foreach my $key (keys %{$md5sums}) {
		print $fh $key, ";", $md5sums->{$key}, "\n";
	}
	close ($fh);
}

# Find callback
sub make_static {
	my $fullpath = $File::Find::name;
	my $pagespath = $fullpath;
	my $wikipath;

	# Remove the root
	$pagespath =~ s#$pages##;

   # Ignore dot files and attic entries
   
   # return if ( 
   #     $pagespath =~ /^\./ or
   #     $pagespath =~ /changes.log/
   #     $pagespath =~ /^attic/ or 
   #     $pagespath =~ /^cache/ or 
   #     $pagespath =~ /^locks/ or 
   #     $pagespath =~ /^meta/ or 
   #);

	# Remove extension and replace / with :
	$wikipath = $pagespath;
	$wikipath =~ s/\.txt$//;
	# $wikipath =~ s#/#:#g;

	# If the data entry is a directory, create it and return
	if (-d $fullpath) {
		mkdir $odir . '/' . $pagespath;
		return;
	}

   # local path to the html static file
	my $ofile;

	# If the page is the start one, set output file to /index.html
	if ($wikipath eq $start) { $ofile = $odir . '/index.html'; }
	# else 
	else { 
		$ofile = $odir . '/' . $pagespath;
		# Replace txt extension by html
		$ofile =~ s/\.txt$/.html/;
	}
	
	# Current datafile's md5
	my $fh; my $current_md5;
	# Create a md5 object
	my $ctx = new Digest::MD5;

	open($fh, "< $pages/$pagespath") or die "can't open $pages/$pagespath: $@";
	$ctx->addfile($fh);
	close($fh);
	$current_md5 = $ctx->hexdigest;

	# wikipath is like 'docs:solaris:zone'
	# datapath is '/data/docs/solaris/zone.txt'
	# ofile    is '/static/docs/solaris/zone.html

	# check if the entry is available in file
	if (defined $md5sums->{$wikipath}) {
		# same entry for both ?
		unless ($md5sums->{$wikipath} eq $current_md5) {
			# No, compute a new file
			$ofile = $ofile . '.new' if (-f $ofile);
			print "$ofile\n";
			parse_file ($wikipath, $ofile);
			$md5sums->{$wikipath} = $current_md5;
		} else {
			parse_file ($wikipath, $ofile) unless (-f $ofile);
		}
	} else {
		print "$ofile\n";
		$md5sums->{$wikipath} = $current_md5;
		parse_file ($wikipath, $ofile);
	}
}

sub parse_file ($$) {
	my $wikipath = shift;
	my $ofile = shift;
	my $ofh;
        
        # print "wikipath: $wikipath\n";
       
	my $iconv = Text::Iconv->new("utf8","iso8859-15");

	# Open the static file
	open ($ofh, "> $ofile") or die "Can't open static file $@";
	print $ofh $iconv->convert(transform($wikipath));
	close ($ofh);
}

# This function fetch data via HTTP and parse output to replace links
sub transform ($) {
	my $wikipath = shift;
	my $query = $ua->get($virtualhost . $dokupath . '/' . $wikipath);

	if ($query->is_success) {
		return parse_output($query->content, $wikipath);
	}else{
                print "Error while fetching : $virtualhost$dokupath/$wikipath\n";
        }
        
}

# This function parse dokuwiki html output to replace links
sub parse_output ($$) {
	my $pages = shift;
	my $css = $dokupath;

	$css =~ s/doku\.php$/style.css/;

	# Replace CSS
	$pages =~ s#href="$css"#transform_css()#eg;

        # Remove charset
        $pages =~ s# charset=utf-8##;

	# Replace links
	
        # with rewrite [..]/doku.php/[pagename]
        $pages =~ s#href="$dokupath/*([\w_-]*)"#transform_link($1)#eg;
	
        # without rewrite
        $pages =~ s#href="$dokupath\?id=([\w:]+)(&[^"]+)?"#transform_link($1)#eg;
	$pages =~ s#href="$dokupath\?id=(&[^"]+)?"#transform_link($start)#eg;

	return $pages;
}

sub transform_css () {
	return 'href="' . $staticurl . 'style.css"';
}

sub transform_link ($) {
	my $link = shift;
        
        # print "transform link : $link \n";
	
        $link = 'index' if ($link eq $start);
	$link =~ s#:#/#g;
	$link = 'href="' . $staticurl . $link . '.html"';

        # print "transformed link : $link \n";

	return $link;
}

__END__
=head1 NAME

doku_static.pl - Build static pages for a DokuWiki

=head1 SYNOPSIS

doku_static.pl

=head1 OPTIONS

=over 8

=item B<--pages>

Path to dokuwiki's pages (local) directory

=item B<--output>

Local output directory

=item B<--start>

The start page

=item B<--virtualhost>

The HTTP virtualhost

=item B<--dokupath>

The HTTP path to doku.php

=item B<--staticurl>

The HTTP URL to static directory

=item B<--md5>

The file path use to read/store md5 files

=head1 EXAMPLE

./doku-static.pl --data ~/www/pagesperso/asyd/home/data \
 --output ~/www/pagesperso/asyd/static \
 --start asyd \
 --virtualhost "http://www.asyd.net" \
  --dokupath "/home/doku.php" \
  --staticurl "/static/"
