#!/usr/bin/perl

=head1 NAME

dapper - A publishing tool for static websites.

=cut

use open ':std', ':encoding(UTF-8)';
use 5.010;

use strict;
use warnings;

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

use Pod::Usage;
use Getopt::Long qw(:config bundling no_ignore_case);
use App::Dapper;

my $SOURCE  = undef;
my $OUTPUT  = undef;
my $LAYOUT  = undef;
my $CONFIG  = undef;
my $PORT    = 8000;
my $QUIET   = 0;
my $HELP    = 0;
my $VERSION = 0;

=head1 SYNOPSIS

    dapper [options] <command>

    # Initialize the current directory with a fresh skeleton of a site
    $ dapper init

    # Build the site
    $ dapper build

    # Build the site, then serve it locally at http://localhost:8000,
    # rebuilding whenever a file changes
    $ dapper serve

    # Rebuild the site whenever a file (source, layout, config) changes
    $ dapper watch

    # Get help on usage and switches
    $ dapper -h

    # Print the version
    $ dapper -v

=head1 DESCRIPTION

B<Dapper> transforms simple text files into static websites. Source files
(Markdown with YAML front matter) are combined with layout templates and
written to an output directory.

See L<App::Dapper> or the README at L<https://github.com/markdbenson/dapper>
for the full documentation: the project file, source files, layouts,
variables, filters and deployment.

=head1 OPTIONS

=over 4

=item B<-s>, B<--source>=I<source directory>

Specify the directory containing source files to process. If this command line option is not present, it defaults to the C<source> setting in the config file, or "_source".

=item B<-o>, B<--output>=I<output directory>

Specify the directory to place the output files in. If this command line option is not present, it defaults to the C<output> setting in the config file, or "_output".

=item B<-l>, B<--layout>=I<layout directory>

Specify the directory containing layout files. If this command line option is not present, it defaults to the C<layout> setting in the config file, or "_layout".

=item B<-c>, B<--config>=I<config file>

Specify the config file name to use. If this command line option is not present, it defaults to "_config.yml".

=item B<-p>, B<--port>=I<port>

Specify the port to use for the serve command. This option is only used for the serve command. If this command line option is not present, it defaults to "8000".

=item B<-q>, B<--quiet>

Only print errors.

=item B<-h>, B<--help>

Get help on available commands and options.

=item B<-v>, B<--version>

Print the version and exit.

=back

=cut

sub dapper {
    my $d = App::Dapper->new($SOURCE, $OUTPUT, $LAYOUT, $CONFIG);
    $d->{quiet} = $QUIET;
    return $d;
}

sub init {
    dapper()->init();
}

sub build {
    dapper()->build();
}

sub watch {
    dapper()->watch();
}

sub serve {
    my $pid = fork();
    die "error: could not fork: $!\n" unless defined $pid;
    if ($pid == 0) { watch(); exit(0); }
    dapper()->serve($PORT);
}

sub help {
    my ($status) = @_;
    pod2usage({ -verbose => 1, -exitval => defined $status ? $status : 0 });
}

sub version {
    print "Dapper version $App::Dapper::VERSION\n";
    exit(0);
}

GetOptions(
    's|source=s' => \$SOURCE,
    'o|output=s' => \$OUTPUT,
    'l|layout=s' => \$LAYOUT,
    'c|config=s' => \$CONFIG,
    'p|port=i'   => \$PORT,
    'q|quiet'    => \$QUIET,
    'h|help'     => \$HELP,
    'v|version'  => \$VERSION,
) or help(2);

help(0) if $HELP;
version() if $VERSION;

my $COMMAND = shift @ARGV;
help(0) if not defined $COMMAND or $COMMAND eq 'help';

my $switch = {
    'init'  => \&init,
    'build' => \&build,
    'serve' => \&serve,
    'watch' => \&watch,
};

if (not $switch->{$COMMAND}) {
    print STDERR "error: unknown command \"$COMMAND\"\n\n";
    help(2);
}

eval { $switch->{$COMMAND}->(); 1 } or do {
    print STDERR $@;
    exit(1);
};

exit(0);

=head1 AUTHOR

Mark Benson, C<< <mark at jayber.org> >>

=head1 BUGS

Please report any bugs or feature requests at
L<https://github.com/markdbenson/dapper/issues>.

=head1 LICENSE AND COPYRIGHT

The MIT License (MIT)

Copyright (c) 2002-2026 Mark Benson

See L<App::Dapper> for the full license text.

=cut
