#!/usr/bin/env perl

use common::sense;
use warnings FATAL => q(all);
use autodie q(:all);
use Getopt::Long qw(:config no_ignore_case auto_version);
use Pod::Find qw(pod_where);
use Pod::Usage;
use App::BoolFindGrep::CLI;

our $VERSION = '0.02'; # VERSION

binmode STDOUT, q(:utf8);

my %opt;
my $result = GetOptions(
    q(--files-from|T=s)     => sub { $opt{ $_[0] } = $_[1] },
    q(--files-delim|d=s)    => sub { $opt{ $_[0] } = $_[1] },
    q(--file-expr|f=s)      => sub { $opt{ $_[0] } = $_[1] },
    q(--find-type|t=s)      => sub { $opt{ $_[0] } = $_[1] },
    q(--find-ignore-case|I) => sub { $opt{ $_[0] } = $_[1] },
    q(--directory|D=s{1,})  => sub { push @{ $opt{ $_[0] } }, $_[1] },
    q(--fixed-strings|F)    => sub { $opt{ $_[0] } = $_[1] },
    q(--match-expr|m=s)     => sub { $opt{ $_[0] } = $_[1] },
    q(--ignore-case|i)      => sub { $opt{ $_[0] } = $_[1] },
    q(--line-regexp|x)      => sub { $opt{ $_[0] } = $_[1] },
    q(--word-regexp|w)      => sub { $opt{ $_[0] } = $_[1] },
    q(usage|help|h) => sub { pod2usage( q(-verbose) => 1 ) },
    q(man)          => sub { pod2usage( q(-verbose) => 2 ) },
);

pod2usage( -verbose => 1 ) if !($result) || !(%opt);

my $obj   = App::BoolFindGrep::CLI->new();
my $check = $obj->args_checker(%opt);

exit 1 unless $check;
exit 1 unless $obj->process();

my @file = @{ $obj->files() };

say for sort @file;

=pod

=encoding utf8

=head1 NAME

bfg - Command Line Interface for App::BoolFindGrep.

=head1 VERSION

version 0.02

=head1 DESCRIPTION

=head2 Boolean Expressions

In the context of this program, a B<Boolean Expression> is a composite of I<OPERANDS>, I<OPERATORS> and I<GROUPS>.

An I<OPERAND> is a string representing a literal text or a regular expression. It can be delimited by slashes like B<ed>, B<sed> or B<vim>. All non-delimiter slashes need to be escaped.

An I<OPERATOR> can be B<AND>, B<OR> or B<NOT>, delimited by white spaces. The following composition of operators are valid too: B<AND NOT>, B<OR NOT>, B<NOT NOT NOT> ...  Operators are case sensitive.

A I<GROUP> is a sub expression delimite by parentheses used to define a set of sub conditions to match.

Any expression valid in program languages are valid here.

=head1 USAGE

    bfg [ -m <EXPR>]
    bfg [-F|-i|[-w|-x]] [-m <EXPR>]
    bfg [-D <DIR1 [DIR2 [DIR3]]>] [-t <literal|glob|regexp>] [-I <0|1>] -f <EXPR>
    bfg [-t <literal|glob|regexp>] [-I <0|1>] -f <EXPR> -m <EXPR>
    bfg [-T <filename|-|STDIN> [-d <char>]] [-F|-i|[-w|-x]] -m <EXPR>

    OPTIONS:
    [ --files-from       | -T ]    file name, "-" or stdin.
    [ --files-delim      | -d ]    file names' character separator.
    [ --file-expr        | -f ]    boolean expr to file names.
    [ --find-type        | -t ]    regexp (default), literal or glob.
    [ --find-ignore-case | -I ]    ignore find operands' case.
    [ --directory        | -D ]    where to search for files.
    [ --match-expr       | -m ]    boolean expr to file contents.
    [ --fixed-strings    | -F ]    operands as literal strings.
    [ --ignore-case      | -i ]    ignore case of operands.
    [ --line-regexp      | -x ]    interpret operands as whole lines.
    [ --word-regexp      | -w ]    interpret operands as whole words.

=head1 OPTIONS

=head2 "find" options

=over

=item * --files-from, -T

Get file names from a file or from Standard Input. Valid forms to express STDIN are hyphen ou word "stdin" (the case is ignored). This option works like C<-T> from B<gnu tar>.

=item * --files-delim, -d

Specify string separator of file names when C<--files-from, -T> is given. This option can receive a NULL character if written as C<\0> (like C<-0> option from B<gnu xargs>.

=item * --file-expr, -f

Specify the boolean expression to search in file names. Any boolean expression is valid.

=item * --find-type, -t

Determines if operands of C<--file-expr, -f> are interpreted as literal strings, glob patterns or regular expressions. The default is regular expressions.

=item * --find-ignore-case, -I

Determines if case of operand of C<--file-expr, -f> are relevant or no. Default is yes (0). More or less like C<-iregex> and C<-iname> options from B<gnu find>.

=item * --directory, -D

A white space list of directories to search for files. This switch can be declared one time for each directory.

=back

=head2 "grep" options

=over

=item * --match-expr, -m

Specify the boolean expression to search in file contents. Any boolean expression is valid.

=item * --fixed-strings, -F

Interprets the operands of C<--match-expr> as literal strings. Like C<-F> option from B<gnu grep>.

=item * --ignore-case, -i

Ignore or no the case operands' case letters of C<--match-expr> option.

=item * --line-regexp, -x

Interprets each operand of C<--match-expr> as a whole line. Like C<-x> option from B<gnu grep>.

=item * --word-regexp, -w

Interprets each operand of C<--match-expr> as a whole word*. Like C<-w> option from B<gnu grep>.

*word here is regexp's context.

=back

=head1 EXAMPLES

=head2 "Finding" Perl files

All these options are equivalents:

    $ bfg -I -f '\.pl$ OR \.pm$ OR \.t$ OR \.pod$'
    $ bfg -I -f '/\.(?:p[lm]|t|pod)$/'
    $ bfg -I -f '/\.(?:[Pp][LlMm]|Tt|[Pp][Oo][Dd])$/'
    $ bfg -I -f '\.pl$|\.pm$|\.t$|\.pod$'

=head2 "Greping"

=head3 AND operator

 foo AND bar

    $ bfg -m 'foo AND bar'
    $ bfg -m '/(?:foo|bar)/'
    $ bfg -m 'foo|bar'

=head2 Operands composed by operators or parentheses

If you want search strings with any operator or parentheses, you need delimiter your pattern with slashes. Like in:

    /foo OR bar/

This example matches string C<foo or bar> but not matches strings C<foo> or C<bar> separately.

=head1 AUTHOR

Ronaldo Ferreira de Lima aka jimmy <jimmy at gmail>.

=head1 SEE ALSO

=over

=item * B<App::BoolFindGrep>.

=back

=cut
