The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package App::Followme::FormatPages;
use 5.008005;
use strict;
use warnings;

use lib '../..';

use Cwd;
use File::Spec::Functions qw(abs2rel rel2abs splitdir catfile);

use App::Followme::Common qw(find_prototype read_page top_directory sort_by_date 
                             unchanged_prototype update_page write_page);

our $VERSION = "0.90";

#----------------------------------------------------------------------
# Create a new object to update a website

sub new {
    my ($pkg, $configuration) = @_;
    
    my %self = ($pkg->parameters(), %$configuration); 
    return bless(\%self, $pkg);
}

#----------------------------------------------------------------------
# Read the default parameter values

sub parameters {
    my ($pkg) = @_;
    
    return (
            quick_update => 0,
            web_extension => 'html',
           );
}

#----------------------------------------------------------------------
# Perform all updates on the directory

sub run {
    my ($self) = @_;

    my $current_directory = getcwd();
    my @stats = stat($current_directory);
    my $modtime = $stats[9];
    
    my @filenames = $self->get_filenames();
    my $prototype_file = shift(@filenames);
    
    # The first update uses a file from the directory above
    # as a prototype, if one is found
    my $prototype_path = $self->get_prototype_path($prototype_file);
    my $prototype = read_page($prototype_file);
    
    my $count = 0;
    my $changes = 0;
    my $decorated = 1;

    foreach my $filename (@filenames) {        
        my $page = read_page($filename);
        die "Couldn't read $filename" unless defined $page;

        # Check for changes before updating page
        my $skip = unchanged_prototype($prototype, $page,
                                       $decorated, $prototype_path);

        if ($skip) {
            last if $self->{quick_update} && $count;
            
        } else {    
            $page = update_page($prototype, $page, 
                                $decorated, $prototype_path);
        
            my @stats = stat($filename);
            my $modtime = $stats[9];
        
            write_page($filename, $page);
            utime($modtime, $modtime, $filename);
            $changes += 1;
        }
        
        if ($count == 0) {
            # The second and subsequent updates use the most recently
            # modified file in a directory as the prototype, so we
            # must change the values used for the first update
            $prototype = $page;
            $prototype_path = $self->get_prototype_path($filename);
        }
        
        $count += 1;
    }
    
    utime($modtime, $modtime, $current_directory);
    return ! $self->{quick_update} || $changes; 
}

#----------------------------------------------------------------------
# Get the filename of the prototype and web files

sub get_filenames {
    my ($self) = @_;

    my $pattern = "*.$self->{web_extension}";
    my @filenames = reverse sort_by_date(glob($pattern));
    
    my $prototype_file = find_prototype($self->{web_extension}, 1);
    unshift(@filenames, $prototype_file) if defined $prototype_file;

    return @filenames;   
}

#----------------------------------------------------------------------
# Get the prototype path for the current directory

sub get_prototype_path {
    my ($self, $filename) = @_;
    
    $filename = rel2abs($filename);
    $filename = abs2rel($filename, top_directory());
    my @path = splitdir($filename);
    pop(@path);
    
    my %prototype_path = map {$_ => 1} @path;
    return \%prototype_path;    
}

1;
__END__

=encoding utf-8

=head1 NAME

App::Followme::FormatPages - Simple static web site maintenance

=head1 SYNOPSIS

    use App::Followme::FormatPages;
    my $formatter = App::Followme::FormatPages->new($configuration);
    $formatter->run();
    
=head1 DESCRIPTION

App::Followme::FormatPages updates the web pages in a folder to match the most
recently modified page. Each web page has sections that are different from other
pages and other sections that are the same. The sections that differ are
enclosed in html comments that look like

    <!-- section name-->
    <!-- endsection name -->

and indicate where the section begins and ends. When a page is changed, this
module checks the text outside of these comments. If that text has changed. the
other pages on the site are also changed to match the page that has changed.
Each page updated by substituting all its named blocks into corresponding block
in the changed page. The effect is that all the text outside the named blocks
are updated to be the same across all the web pages.

=head1 CONFIGURATION

The following parameters are used from the configuration:

=over 4

=item quick_update

Only check files in current directory

=item web_extension

The extension used by web pages. The default value is html

=back

=head1 LICENSE

Copyright (C) Bernie Simon.

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

=head1 AUTHOR

Bernie Simon E<lt>bernie.simon@gmail.comE<gt>

=cut