#!/usr/bin/perl
#use 5.001 ; 
use strict ; 
use warnings ; 
use feature qw[ say ] ; 
use Cwd qw [ getcwd ] ;
use App::dirdim ; # $App::dirdim::VERSIONを利用するため。開発中は、既にインストール済みのものを使ってしまうので、意図しにくい動作になるだろう。
use File::Find qw[ find ] ; 
use File::Spec::Functions qw[ catfile splitdir ] ; 
use Getopt::Std ; 
use List::Util qw[ minstr maxstr all any max ] ;
use Term::ANSIColor qw [ :constants ] ; ${Term::ANSIColor::AUTORESET} = 1 ; 
use Time::HiRes qw[gettimeofday tv_interval] ; 

my $time_start ;# = [ gettimeofday ] ; 
BEGIN { $time_start = [ gettimeofday ] }; # BEGIN UNITCHECK CHECK INIT  # 動作時間の測定をできるだけ正確にするためBEGINで囲んだ。
my $I = catfile '', '' ; # OS毎に異なる可能性のある、ファイルパスの区切り文字を取得。 

getopts '.:adv' , \my%o ; 
$o{'.'} //= ''  ;
@ARGV = ( "." ) unless @ARGV  ; # & HELP_MESSAGE unless @ARGV ; 
my ($y,$z) = (0,0) ; # 結果的に処理対象となったものと、そうでないもの
& measure_simple ; 
exit 0 ; 

sub measure_simple { 
  my @tmp ;
  push @tmp , ( "nondir" , CYAN ( "subdir" ) ) ;
  push @tmp , ( BRIGHT_BLUE ("depth"), "alltree" ) if defined $o{d} ;
  push @tmp , YELLOW "given_dir" ;
  push @tmp , BRIGHT_BLUE "An example at the deepest" if defined $o{d} ;
  push @tmp , ("fileName_minstr" , "fileName_maxstr" ) if $o{v} ; 
  say join "\t" , map { UNDERLINE $_ } @tmp ; 
  my %t ; # 合計 total を いろんなもので数える。
  
  my $dir0 = getcwd ;
  for ( @ARGV ) { 
    chomp ;
    do { print join("\t",'','',$_,RED ": Not a directory."),"\n" if $o{a} ; $z++ ; next } if ! -d $_  ; 
    opendir my $dh , $_ or do { warn "$_ does not open.\n" ; next } ;
    my @files = grep { ! /^\.{1,2}$/ } readdir $dh  ; # そのディレクトリの下の各ファイルについて、ファイル名のみが入る(ディレトクリ名は入らない)。
    @files = grep {/^\./ } @files if $o{'.'} =~ m/only/io ; # -. なら、ドットファイルのみを対象とする。
    @files = grep { ! /^\./ } @files if 0 eq $o{'.'} ; # -. 0 なら、ドットファイルは対象外とする。
    chdir $_ ; 
    my ( @dfiles , @nfiles ) ; # ディレクトリかそれ以外か
    for ( @files ) { if ( -d ) { push @dfiles, $_ ; $_ .= $I } else { push @nfiles, $_ } }
    my ( $dp, $dn , $finum, $links ) = max_depth ( $_ ) if $o{d} ; # <-- 返値は、深さ・最深ファイル名の例・計数したファイル数・シンボリックな数
    chdir $dir0 ;

    do { $t{d} += @dfiles ; $t{n} += @nfiles ; $t{D} = max $t{D}//0, $dp if defined $dp ; $t{a} += $finum // 0 } ;

    my @out ; 
    push @out , fsl ( @nfiles ) , CYAN fsl ( @dfiles ) ; 
    push @out , BRIGHT_BLUE ("$dp"), "$finum" . ($links ? FAINT "($links)" : '') if defined $dp ; # 最も深い所の深さ  それと数えたファイル数
    push @out , YELLOW $_ . $I ; 
    push @out , BRIGHT_BLUE $dn if defined $dn ; # 最も深い所にあるファイルの名前
    if ( $o{v} ) { 
      my $f1 = minstr @files ;
      my $f2 = maxstr @files ; 
      push @out , ($f1) if defined $f1 ; 
      push @out , ($f2) if defined $f1 && $f1 ne $f2 ;
    }
    say join "\t", @out ; 
    $y ++ ;
    #closedir $dh ; 
  }
  say join "\t" , $t{n},$t{d}, $o{d}?($t{D},$t{a}):(), 'total' if $y >= 2  ;
}

END{
  my $time_elapsed = sprintf '%.4f', tv_interval ( $time_start , [ gettimeofday ] ) ;
  my $end ;
  $end .= "$y entries. " if $y > 1 ;
  $end .= "${time_elapsed}s. " ; 
  $end .= "The numbers of files are shown in left columns. " ; 
  $end .= "$z entrie(s) are suppressed in the processing. " if $z ;
  $end .= "(App::dirdim\@$App::dirdim::VERSION $0)" ;
  say STDERR BOLD FAINT ITALIC $end ; 
}


sub fsl ( @ ) {  # Faint, Symblic Link の略のつもり。
  scalar @_ . do { my @L = grep { -l } @_ ; @L == 0 ? "" : FAINT "(" . scalar @L . ")"  }  ;
}

sub max_depth ( $ ) { 
  my $dir0 = getcwd ;
  chdir $_[0] ;
  my $depth = 0 ; # 最大の深さ
  my $deepest_file_name = '' ; # 最も深い所にあるファイルの名前
  my $t ; # 仮変数
  my $n = 0 ; # ついでにファイルの個数も数える。
  my $l = 0 ; # リンクファイルの個数
   find ( {
    no_chdir => 1 , 
    wanted => sub { 
      my @t = splitdir ( $_ ) ; 
      return if $o{'.'} =~ m/only/io && $t[-1] !~ /^\./ ; 
      return if $o{'.'} eq '0' && any { $_ =~ /^\./ } @t[1..$#t] ; # <-- - 定義が微妙になり得る。# findで全部見て回るので計算の無駄が生じている
      $n ++ if $_ ne '.' ; 
      $l ++ if -l $_ ; 
      $depth = @t - 1 and $deepest_file_name = -d $_ ? "$_$I" : $_ if @t > $depth ;
    }
   } , '.' ) ; 
   chdir $dir0 ;
   return $depth , $deepest_file_name =~ s/^\.$I//or , $n , $l ;
}

sub VERSION_MESSAGE {}
sub HELP_MESSAGE {
  use FindBin qw[ $Script ] ;
  $ARGV[1] //= '' ;
  open my $FH , '<' , $0 ;
  while(<$FH>){
    s/\$0/$Script/g ;
    print $_ if $ARGV[1] eq 'opt' ? m/^\ +\-/ : s/^=head1// .. s/^=cut// ;
  }
  close $FH ;
  exit 0 ;
}

=encoding utf8

=head1

 $0 DIR [DIR] [DIR] ..

  指定されたディレクトリの直下にある、非ディリクトリファイルの数とディレトリの数を出力する。
  シンボリックファイルの個数は括弧内に示す。暗い色の文字で(8)や(3)のように表記。
  何も引数が無い場合は、カレントディレクトリに対して動作。

  The command line `perldoc App::dirdim' shows the English help of `dirdim' command.

 オプション: 

  -a  : 引数にディレクトリで無いファイルが指定された場合に、そのことを示す。 
  -d  : 最も深い所にあるファイルの名前とその深さを示す。さらに、findで見つかるファイルの個数も出力。
  -v  : ファイル名の(文字列としての)最小値と最大値も出力する。(verbose)
  -. 0    : ファイル名がピリオドで始まるファイル(隠しファイルと言われる)は、計数対象から除外する。
  -. only : ファイル名がピリオドで始まるファイル(隠しファイルと言われる)のみを、計数対象にする。
  --help : このヘルプを表示。

 開発上のメモ: 
   * glob の */../*のような探索と File::Find による探索の違いを発見した。dirdimとdirdigで共通化の検討が必要。
   * Ctrl-Cを押下した時の挙動を決めたい。
   * 色を消すオプションを実装した方が良いだろうか? 他のコマンドの colorplus -0 に任せるべきか?

=cut
