#!/usr/bin/perl -w

use strict ;
use warnings ;
use Carp ;

=head1 NAME 

mci - Index your CPAN mini repository

=head1 DOCUMENTATION

Let you create and search text based on the content of L<pod>, L<pl> and L<pm> files in your CPAN mini repository.

=head2 First indexing

Indexing a CPAN Mini repository takes between two and three hours on a modern box if you have your repository
on an old laptop, it's going to take ages. Grab a pre_indexed cpan at L<http://www.khemir.net/http_share> or 
mail the author if you can't find one at the above URL.

=head1 USAGE

 $> mci --option --option  file_1 file_2 ... file_n

=head2 Examples

=over 2

=item update and search

  $> 

=item search no update

  $> 

=item command line completion (in your current shell)

  $> mci --completion_script > /tmp/mci ; source /tmp/mci ; rm /tmp/mci

=head1 OPTIONS

  'h|help'                display help
  'v|verbose'             displays extra information when indexing the modules
  'completion_script'     generates a bash completion script
  
  'cpan_mini'             cpan mini location or $ENV{CPAN_MINI} or '/devel/cpan'
  'no_index_update'       search the current database without checking if it is up to date
  'modules_only'          only show containing module name in the search results
  'n|lines=i'             display the first N search matches
  'maximum_document_size' files over that size are not indexed, default is 300 KB
  'verbose'               show extra indexing information or search scores
  'database_information'  show some information about the database

=head1 EXIT STATUS

=head1 AUTHOR

	Nadim ibn hamouda el Khemir
	CPAN ID: NKH
	mailto: nkh@cpan.org

=cut

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

our $VERSION = '0.03' ;

use Getopt::Long ;
use Term::Bash::Completion::Generator ;

use Readonly ;
Readonly my $EMPTY_STRING => q{} ;

use English qw( -no_match_vars ) ;

use CPAN::Mini::Indexed qw( search check_index show_database_information) ;

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

my (@siim_arguments) = @ARGV ;
undef @ARGV ;

mci(@siim_arguments) ;

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

sub mci
{

#~ =head2 mci(@arguments)

#~ 

#~ I<Arguments> - command line arguments to be parsed by Getop::Long

#~ I<Returns> -  Nothing

#~ I<Exceptions> - 

#~ =over 2 

#~ =item Invalid options

#~ =item Invalid index database

#~ =back

#~ =cut

my (@arguments) = @_ ;
my ($options, @unexpected_data)  = get_options(@arguments) ;

if(@unexpected_data)
	{
	print {*STDERR} "Error: Don't know what to do with '" . join(' ', @unexpected_data) . "' you passed on the command line!\n" ;
	exit(1) ;
	}

if($options->{completion_script})
	{
	generate_completion_script() ;
	exit(0) ;
	}

if($options->{database_information})
	{
	show_database_information($options) ;
	exit(0) ;
	}

check_index($options) unless $options->{no_index_update};
search($options) if $options->{search} ;
}

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

sub get_options_definition
{
#~ =head2 get_options_definition()

#~ I<Arguments> - None

#~ I<Returns> - a list of tuples, config name => container

#~ I<Exceptions> -None

#~ =cut

my ($container) = @_ ;

croak "Error: Expected a hash reference!\n" if (defined $container && 'HASH' eq ref $container) ;

$container ||=
	{
	add_files => 0,
	remove_files => 0,
	check_index => 0,
	use_position => 0, 
	lines => 1_000_000,
	} ;
	
my @definitions = 
	(
	'h|help' => \&display_help,
	'cpan_mini=s' => \$container->{cpan_mini},
	'i|index_directory=s' => \$container->{index_directory},
	'no_index_update' => \$container->{no_index_update},
	'modules_only' => \$container->{modules_only},
	'n|lines=i' => \$container->{lines},
	'maximum_document_size' => \$container->{maximum_document_size},
	's|search=s' => \$container->{search},
	'v|verbose' => \$container->{verbose},
	'stopwords_file=s' => \$container->{stopwords_file},
	'database_information' => \$container->{database_information},
	'completion_script' => \$container->{completion_script},
	) ;

return $container, @definitions ;
}	

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

sub get_options
{

#~ =head2 get_options(@arguments)

#~ Parses the command line for the module to search and user defined options.

#~ I<Arguments>

#~ =over 2 

#~ =item @arguments - the command line arguments

#~ =back

#~ I<Returns> -  A list containing the module to search followed by the options accepted by this command

#~ I<Exceptions> - exits if an invalid option is passed

#~ =cut

my (@arguments) = @_ ;
local @ARGV = @arguments ;

my ($container, @definitions) = get_options_definition() ;

die "Error: Invalid Option! Try --help.\n" unless GetOptions(@definitions) ;

return($container, @ARGV) ;
}

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

sub display_help
{

#~ =head2 display_help()

#~ I<Arguments> - None

#~ I<Returns> - Nothing

#~ I<Exceptions> - exits with status code B<1>

#~ =cut

my ($this_script) = ($PROGRAM_NAME =~m/(.*)/sxm ) ;

print {*STDERR} `perldoc $this_script`  or croak 'Error: Can\'t display help!' ; ## no critic (InputOutput::ProhibitBacktickOperators)
exit(1) ;
}

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

sub generate_completion_script
{
#~ =head2 generate_completion_script()

#~ I<Arguments> - None

#~ I<Returns> - Nothing

#~ I<Exceptions> - exits with status code B<1> after emitting the completion script on stdout

#~ =cut

my ($container, @definitions) = get_options_definition() ;

my $flip = 0 ;
my @options = grep {++$flip % 2} @definitions ;

print Term::Bash::Completion::Generator::generate_bash_completion_function('mci', [@options], undef, 0) ;
exit(1) ;
}


