#!/usr/bin/env perl

use warnings;
use strict;

use FindBin;
use lib
    "$FindBin::Bin/../lib",
;

use File::ChangeNotify;
use Path::Class::File;
use App::Daemon qw( daemonize );
use Try::Tiny;
use Log::Log4perl qw( :easy );
use Getopt::Long;

use Plerd;
use Plerd::Util;

my $webmention_enabled = 0;
my $webmention_port  = 0;
my $config_file;
GetOptions(
    'config=s'              => \$config_file,
    'send-webmentions'      => \$webmention_enabled,
    'receive-webmentions=i' => \$webmention_port,
);

if ($webmention_port) {
    die "Plerd ended its experimental Webmention receipt support in version "
        . "1.900. Please re-run this command without the `receive-webmentions` "
        . "option. (Or use an older version of Plerd.)\n";
}

my $config_ref = Plerd::Util::read_config_file( $config_file );

for my $dir_type ( qw( run log ) ) {
    unless ( $config_ref->{ "${dir_type}_path" } ) {
        if ( $config_ref->{ path } ) {
            $config_ref->{ "${dir_type}_path" } =
                Path::Class::File->new(
                    $config_ref->{path},
                    $dir_type,
                )->stringify;
        }
        else {
            $config_ref->{ "${dir_type}_path" } =
                "$FindBin::Bin/../$dir_type";
        }
    }
    my $dir = $config_ref->{ "${dir_type}_path" };
    mkdir $dir unless -e $dir;
    unless (-w $dir) {
        die "Can't start $0: I don't have write permission to $dir_type "
            . "directory '$dir'. Either make that directory writeable, "
            . "or change Plerd's configuration to use a different "
            . "location as the $dir_type directory.\n";
    }
}
$App::Daemon::logfile = "$$config_ref{log_path}/plerdwatcher.log";
$App::Daemon::pidfile = "$$config_ref{run_path}/plerdwatcher.pid";

daemonize();

foreach (qw( base_uri image ) ) {
    my $value = $config_ref->{ $_ };
    next unless defined $value && length $value;
    unless ( ref $value ) {
        $config_ref->{ $_ } = URI->new ( $value );
    }
}

my $plerd;
my $watcher;
try {
    $plerd = Plerd->new( $config_ref );

    $watcher = File::ChangeNotify->instantiate_watcher (
        directories => [ $plerd->source_directory . '' ],
        filter      => qr/\.(md|markdown)$/,
    );
}
catch {
    ERROR "Couldn't start Plerd: $_";
};

unless ( $plerd && $watcher ) {
    LOGDIE "Couldn't start Plerd; exiting.";
}

while ( my @events = $watcher->wait_for_events ) {
    if ( @events ) {
        try {
            for my $event ( @events ) {
                if (
                    ( $event->type eq 'create' )
                    or ( $event->type eq 'modify' )
                ) {
                    my $file = Path::Class::File->new( $event->path );
                    $plerd->publish_file( $file );

                    if ( $webmention_enabled ) {
                        my $post = Plerd::Post->new(
                            source_file => $file,
                            plerd => $plerd,
                        );
                        INFO "Sending webmentions for $file...";
                        my $report = $post->send_webmentions;
                        INFO "$report->{attempts} attempts, "
                             . "$report->{sent} sent, "
                             . "$report->{delivered} delivered.";
                    }
                }
                else {
                    # A delete (or other) event can change the sidebar and
                    # other shared pages, so republish the whole blog.
                    $plerd->publish_all;
                }
            }
        }
        catch {
            ERROR "Failed to publish: $_\n";
        };
    }
}

=head1 NAME

plerdwatcher - Daemon that automatically updates a Plerd-based blog when
needed

=head1 SYNOPSIS

In /path/to/plerd/conf/plerd.conf:

 base_uri: http://blog.example.com path: /home/me/Dropbox/plerd title:
 My Lovely Blog

And then, on the command line, while in the top-level plerd directory:

 bin/plerdwatcher start

=head1 DESCRIPTION

This script launches a simple daemon that monitors a Plerd blog's
directory of Markdown-based source documents for changes. When it sees
changes, it will direct Plerd to publish or republish files as needed.

It also supports options to send and receive webmentions, as described
in L<"OPTIONS">, below.

I<plerdwatcher> runs via L<App::Daemon>, and accepts all the
command-line arguments documented there.

It stores its logs in a directory called C<log> and other run-time files
in a C<run> directory, both of which it expects to find as siblings of
its own parent directory (usually C<bin>).

For instructions on installing and using Plerd, please see the README
file that should have accompanied this distribution. It is also
available online at L<https://github.com/jmacdotorg/plerd#plerd>.

=head1 OPTIONS

=head2 config

 bin/plerdall --config=/path/to/plerd.conf

Specify the location of a valid Plerd config file.

If not specified here, then this program will seek a config file in these
locations, and in this order:

=over

=item *

C<plerd.conf>, in the current working directory

=item *

C<conf/plerd.conf>, in the current working directory

=item *

C<.plerd>, in your home directory

=back

Consult the config file generated by C<plerdall --init> to learn more
about the config file format.

=head2 send-webmentions

 bin/plerdwatcher --send-webmentions start

Newly created or updated posts will also attempt to send webmentions to
any URLs they link to.

=head1 SEE ALSO

=over

=item *

L<Plerd>

=back

=head1 AUTHOR

Jason McIntosh <jmac@jmac.org>
