package App::Pinpp;
use v5.010;
use strict;
use warnings;
use autodie;
use File::Spec;
use Getopt::Std;
use File::Temp qw(tempfile); 


# ABSTRACT: pinpp - The Pinpoint Pre-processor

our $VERSION = '0.02'; # VERSION: Generated by DZP::OurPkg:Version



sub run {
    my $class = shift;

    # Load our arguments into ARGV, so we can use getopts.
    local @ARGV = @_;

    my %opts = (
        o => '',          # Output to PDF
        I => 'topics'     # Includes directory
    );

    getopts("o:i:",\%opts);

    my ($file) = @ARGV;

    $file or die "Usage: $0 file.pinpp";

    # Okay code, you have just one job:
    # @include <foo.pin> -> includes $INCLUDE_DIR/foo.pin
    # NB: Everything after the @include on a line will be removed.

    my $content = $class->_slurp($file);

    # Remove // comments

    $content =~ s{^//[^\n]*\n}{}gsm;

    # Process includes

    $content =~ s{^\@include\s+<([^>]+)>[^\n]*\n}{$class->include($opts{I},$1)}gmse;

    # Remove blank slides

    $content =~ s{^--\n--}{--}gsm;

    # If a slide has no styling at all, and consists only of indented text,
    # reformat it as code.

    $content =~ s{
        ^--[ \t]*\n         # Start of slide
        (?:
            [ \t]+[^\n]*\n  # Lines starting with spaces/tabs
            |               # or...
            \n              # blank lines. They're cool, too.
        )+                  # And we can have a bunch of either.
        ^--                 # End of slide.
    }{_codeify(${^MATCH})}gsmxpe;   # USE ALL THE FLAGS!

    if (my $outputfile = $opts{o}) {

        # Iff we're producing a PDF, then remove speaker comments
        $content =~ s{^#[^\n]*\n}{}gsm;

        my ($tmp_fh, $tmp_filename) = tempfile( DIR => '.' );

        say {$tmp_fh} $content;
        close($tmp_fh);

        system("pinpoint", "--output=$opts{o}", $tmp_filename);
    }
    else {
        # Otherwise just display our text
        say $content;
    }

    # And we're done!

    # Success!
    return 0;
}


sub include {
    my ($class, $dir, $include) = @_;
    return $class->_slurp(File::Spec->catdir($dir, $include))."--\n";
}

# Slurps in a file. Not as fancy as File::Slurp, but saves us a
# dependency.
sub _slurp {
    my ($class, $file) = @_;

    local $/;

    open(my $fh, '<', $file);

    return <$fh>;
}

# Trims out start/end of slide.
sub _trim_slide {
    my ($slide) = @_;

    $slide =~ s{^--[ \t]*\n}{};
    $slide =~ s{--[ \t]*\n?$}{};

    return $slide;
}

# Turns a slide into a code slide.
sub _codeify {
    my ($slide) = @_;

    $slide = _trim_slide($slide);

    my @lines = split(/\n/,$slide);

    # Initial count.
    my $min_spaces = _count_leading_spaces($lines[0]);

    # Find the minimum number of spaces on any line.
    # Double-checks the first line. Meh.
    foreach my $line (@lines) {
        my $spaces = _count_leading_spaces($line);

        next if $spaces == 0;   # Blank lines don't count.

        if ($spaces < $min_spaces) {
            $min_spaces = $spaces;
        }
    }

    # String of actual leading spaces.
    my $space_leader = ' ' x $min_spaces;

    # Trim off leading spaces.
    $slide =~ s{^$space_leader}{}smg;

    # Return our slide.
    return "-- [font=monospace 50px][text-align=left]\n$slide--";
}

# Returns number of leading spaces on a line.
# TODO: Handle tabs
sub _count_leading_spaces {
    my ($line) = @_;

    $line =~ m{^(?<spaces>[ ]*)};

    return length($+{spaces});
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

App::Pinpp - pinpp - The Pinpoint Pre-processor

=head1 VERSION

version 0.02

=head1 DESCRIPTION

You probably want to use L<pinpp> rather than this library directly.

=head1 METHODS

=head2 run(@args)

Runs the pinpoint preprocessor.

=head2 include($dir, $include)

Looks inside C<$dir> for the file specified in C<$include> and
returns its contents, along with a C<--> at the end to prevent
slides running into each other between topics.

=head1 AUTHOR

Paul Fenwick <pjf@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by Paul Fenwick.

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

=cut
