#!/usr/bin/perl

# shuffler 
#  Produced by Toshiyuki Shimono in Tokyo, 2016-01-25 ~ 2016-10-13 ; 2018-03-25 English added.

use 5.001 ; use strict ; use warnings ; # 5.014 is neccesary for srand to work well.
use List::Util qw[ min shuffle ] ;
use Term::ANSIColor qw/:constants color/; 
use Getopt::Std ; getopts ":=g:s:q0",\my %o ;
use FindBin qw [ $Script ] ;
$Term::ANSIColor::AUTORESET = 1 ;


sub procOptions ( ) ; 
sub choreHeader ( ) ; 
sub coreLoops ( ) ; 

my $time0 = time ; 
my $seed ; # ランダムシード

procOptions ; 
choreHeader ; 
coreLoops ; 
exit 0 ; 

## いろいろな関数たち
  
sub procOptions ( ) { 
	srand do{ $o{s}//='';my $s=($o{s}=~s/(.*)!$//)?$1:1<<32; $seed = $o{s}||int rand($s) } ;
	#$o{s} = defined $o{s} ? srand $o{s} : srand 
} # 乱数シードの保管/設定
sub choreHeader ( ) { do { print  "=:\t" if $o{':'} ; print ( my $tmp = <> ) } if $o{'='} } # ヘッダの処理 

sub coreLoops ( ) {
	my @lines ; # 標準入力の各行が格納される。
	push @lines, $_ while ( <> ) ; # 標準入力を全てここで読みとる。
	my @nums = shuffle 0 .. $#lines ; 
	splice @nums , 0 , -$o{g} if defined $o{g} ; # <- -- 最初の方ではなくて最後の方を取り出すことに注意。
	@nums = sort { $a <=> $b } @nums if $o{0} ;
	for ( @nums ) { 
	  print $_+1 , ":\t" if $o{':'} ; 
	  print $lines[$_] ; 
	}
	$0 =~ s|.*/|| ;

	my $num = @nums ; 
	my $sec = time - $time0 ;
	unless ( $o{q} ) 
	{ 
	     my $he = $o{'='} ? 'with' : 'without' ;
		 print STDERR CYAN "Used random seed: ",  BRIGHT_CYAN $seed ; 
		 print STDERR CYAN ". Read lines: ", BRIGHT_CYAN scalar @lines, ". " ; 
		 print STDERR CYAN "Picked lines: ", BRIGHT_CYAN $num ; 
		 print STDERR CYAN " ; " , BRIGHT_CYAN $he, CYAN " an additional heading line. ($Script, " ; 
		 print STDERR BRIGHT_CYAN "$sec" , CYAN ". sec)\n" ; 
	}
}

# ヘルプの扱い
sub VERSION_MESSAGE {}
sub HELP_MESSAGE {
    use FindBin qw[ $Script ] ; 
    $ARGV[1] //= '' ;
    open my $FH , '<' , $0 ;
    while(<$FH>){
        s/\$0/$Script/g ;
        print $_ if s/^=head1// .. s/^=cut// and $ARGV[1] =~ /^o(p(t(i(o(ns?)?)?)?)?)?$/i ? m/^\s+\-/ : 1;
    }
    close $FH ;
    exit 0 ;
}

=encoding utf8

=head1
 
 $0 -s seed   

 [用途と使い方] What it does? 

 各行をシャッフルする。 Shuffles the STDIN. 

 [オプション]

 -= : 入力の1行目はそのまま出力し、シャッフルの対象とはしない。Just throw the 1st line input. Shuffle starts from 2nd.
 -g num : データとして最大何行を出力するかの指定。負の数を指定すると、その絶対値で何個を省力するかの指定になる。(how many lines to Get.)
 -: : 各行の先頭に、何番目のデータから来たかを表示。 (numbering from where) 
 -s : 乱数のシードを指定する。 (random Seed -- for reproducibility.)
 -q : 乱数シード情報を出さない。(Quiet ; no secondary information such as the seed. )
 -0 : シャッフルをしない。-g で特定個数のみ取り出すときに便利。(no shuffle. Combining -g option is useful.)
=cut

