#!/usr/bin/env perl

use strict;
use warnings;

use Getopt::Long;
use Perl::Metrics::Simple qw(0.13);
use Perl::Metrics::Simple::Output::HTML;
use Perl::Metrics::Simple::Output::JSON;
use Perl::Metrics::Simple::Output::PlainText;
use Pod::Usage qw(pod2usage);

our $VERSION = 'v1.0.1';

exit main() if not caller;

#-------------------------------------------------------------------------------

sub main {
    my ( $options, @files ) = parse_opts(@ARGV);

    if ( $options->{'help'} ) {
        pod2usage( -verbose => 2, -exitval => 1 );    # exits program
    }

    if ( my $modifiers = $options->{'method-modifiers'} ) {
        push @Perl::Metrics::Simple::Analysis::File::METHOD_MODIFIERS,
            split( /,/, $modifiers );
    }

    my $analysis = Perl::Metrics::Simple->new()->analyze_files(@files);

    if ( $options->{'html'} ) {
        my $html = Perl::Metrics::Simple::Output::HTML->new($analysis);
        print $html->make_report();
    }
    elsif ( $options->{'json'} ) {
        my $json = Perl::Metrics::Simple::Output::JSON->new($analysis);
        print $json->make_report();
    }
    else {
        my $plain = Perl::Metrics::Simple::Output::PlainText->new($analysis);
        print $plain->make_report();
    }

    return 0;
}

sub parse_opts {
    my (@command_line_arguments) = @_;

    if ( !@command_line_arguments ) {
        pod2usage(
            -msg     => "Missing required argument(s).\n",
            -exitval => 1,
            -verbose => 1,
        );    # exits program
    }

    my %options;

    my $parsed_ok = Getopt::Long::GetOptionsFromArray(
        \@command_line_arguments,
        \%options,
        'html',
        'json',
        'method-modifiers:s',
    );

    if ( !$parsed_ok ) {
        pod2usage(
            -msg     => "Failed to parse command line.\n",
            -exitval => 1,
            -verbose => 1,
        );    # exits program
    }

    return ( \%options, @command_line_arguments );
}

__END__

=head1 NAME

countperl - count lines, packages, subs and complexity of Perl files.

=head1 USAGE

B<countperl> F<FILE_OR_DIRECTORY> [F<FILE_OR_DIRECTORY> ...] [--html] [--help] [--method-modifiers=a,b,c]

=head1 REQUIRED ARGUMENTS

At least one file or directory path must be supplied.

=head1 OPTIONS

=over 4

=item --help

Prints documentation to STDERR.

=item --html

Produces HTML output instead of the plain-text default.

=item --json

Produces JSON output instead of the plain-text default.

=item --method-modifiers=a,b,c

A comma-separated list of method modifiers to be recognised, see
L<Moose::Manual::MethodModifiers> for details. If unspecified, the
default list is before,after,around.

=back

=head1 CONFIGURATION

N/A. Currently no support for any configuration files.

=head1 EXIT STATUS

Exits zero on success, non-zero on failure.

=head1 DESCRIPTION

F<countperl> uses B<Perl::Metrics::Simple> to examines the named files and
recursivesly searches named directories for Perl files.


Perl files are identified by B<Perl::Metrics::Simple-E<gt>is_perl_file>. Basically
if the file ends in C<.pl>, C<.pm>, or C<.t> or has what appears to be a perl
I<shebang> line.

F<countperl> produces a report on F<STDOUT> of counts of total lines,
packages, subroutines/methods,
the minimum, maximum, mean, standard deviation, and median size and
mccabe_complexity (cyclomatic complexity) of subroutines and
the 'main' portion of each file (everything not in a subroutine.)

=head2 Output Format

Line counts do not include comments nor pod.

The current output format is human-readable text:

    Perl files found:                3

    Counts
    ------
    total code lines:       856
    lines of non-sub code:  450
    packages found:           3
    subs/methods:            42

    Subroutine/Method Size
    ----------------------
    min:                  3 lines
    max:                  32 lines
    mean:                 9.67 lines
    std. deviation:       7.03
    median:               7.50

    McCabe Complexity
    -----------------
    Code not in any subroutine::
    min:                  1
    max                   1
    mean:                 1.00
    std. deviation:       0.00
    median:               1.00

    Subroutines/Methods:
    min:                  1
    max:                  5
    avg:                  1.00
    std. deviation:       1.36
    median:               1.00

    Tab-delimited list of subroutines, with most complex at top
    -----------------------------------------------------------
    complexity      sub     path    size
    5       is_perl_file    lib/Perl/Metrics/Simple.pm      11
    5       _has_perl_shebang       lib/Perl/Metrics/Simple.pm      13
    5       _init   lib/Perl/Metrics/Simple/Analysis/File.pm        30
    4       find_files      lib/Perl/Metrics/Simple.pm      11
    4       new     lib/Perl/Metrics/Simple/Analysis.pm     10
    4       is_ref  lib/Perl/Metrics/Simple/Analysis.pm     8

With --html switch output format is HTML.

=head1 VERSION

This is version 0.031 of F<countperl>.

=head1 DIAGNOSTICS

Prints usage message to STDERR if required arguments are not provided.

=head1 INCOMPATIBILITIES

None known.

=head1 BUGS AND LIMITATIONS

=head2 Bugs
No bugs reported yet :-)
See: http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Metrics-Simple

=head2 Limitations

=over 4

=item Does not accept input from STDIN.

=item No machine-readable report format available (e.g. XML, tab-delimited)

=back

=head1 SUPPORT

Via CPAN:

=head2 Disussion Forum

http://www.cpanforum.com/dist/Perl-Metrics-Simple

=head2 Bug Reports

http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Metrics-Simple

=head1 DEPENDENCIES

=over 4

=item L<Perl::Metrics::Simple|Perl::Metrics::Simple> 0.13 (which depends upon L<PPI|PPI>.)

=item L<Pod::Usage|Pod::Usage>

=back

=head1 SEE ALSO

=over 4

=item L<PPI|PPI>

=item L<Perl::Critic|Perl::Critic>

=item L<Perl::Metrics|Perl::Metrics>

=item http://en.wikipedia.org/wiki/Cyclomatic_complexity

=back

=head1 AUTHOR

    Matisse Enzer
    CPAN ID: MATISSE
    Eigenstate Consulting, LLC
    matisse@eigenstate.net
    http://www.eigenstate.net/

=head1 LICENSE AND COPYRIGHT

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

The full text of the license can be found in the
LICENSE file included with this module.

=cut