#!/usr/bin/perl

#  expandtab
#   2021-06-11

use 5.014 ; 
use strict ; 
use warnings ; # also confirmed on 5.011 5.014 5.018  
#use Encode qw[ decode_utf8 encode_utf8 ] ; 
use FindBin qw [ $Script ] ; 
use Getopt::Std ; getopts 'R:b:c:i:s:x' => \my %o ;
use Term::ANSIColor qw [ :constants color ]  ; $Term::ANSIColor::AUTORESET = 1 ; 
#use Time::HiRes qw [ gettimeofday tv_interval ] ; my ${ dt_start } = [ gettimeofday ] ; 
use Text::VisualWidth::UTF8 qw[ trim width ] ;
use List::Util qw [ min max ] ; 

sub dc ($) {  $_[0] =~ s{ \e\[ [\d;]* m }{}xmsgr }  # Delete Color の頭文字を取った。

#my $sdt = sprintf '%04d-%02d-%02d %02d:%02d:%02d', do{my @t= @{[localtime]}[5,4,3,2,1,0]; $t[0]+=1900; $t[1]++; @t } ; 

$o{b} //= ' ' ; # 間に埋める文字
$o{c} //= ' ' ; # 列間で、列の直前に入れる文字
$o{i} //= "\t" ; 
my $optR0 = exists $o{R} && $o{R} eq 0 ; 

## 値の読取り
my @C ; # セルの値
my @L ; # ビジュアルな長さ
my $rcnt = 0 ; # 行番号
my $cmax = 0 ; # 最大の列数
while ( <> ) { 
  chomp ; 
  s/\r$//o unless $optR0 ; 
  $C [ $rcnt ] = [ my @F = split /$o{i}/, $_ , -1 ] ; 
  $L [ $rcnt ] = [ map { Text::VisualWidth::UTF8::width dc $_ } @F ]  ; 

  $cmax = @F if @F > $cmax ; 
  $rcnt ++ 
}

## 各列のVisual幅を算出する。 cmw は The Column's Max Widthのつもり(やや強引だが)
my @cmw = map { my $c = $_ ; max map { $L[$_][$c] // 0 } 0 .. $rcnt - 1 }  0 .. $cmax - 1 ; 


if ( $o{x} ) { my $s = 0 ; say "-x",join "," , map {$s += $_ + 1 } @cmw ; exit } 

## 出力
for my $r ( 0 .. $rcnt -1 ) { 
  my @out ; 
  my $spare0 = 0 ; 
  for my $c ( 0 .. $#{$C[$r]} ) { 
    #( $C[$r][$c] , $L[$r][$c] ) = ( '' , 0 ) if ! defined $C[$r][$c] ; 
    my $spare = exists $o{s} ? min $cmw[$c]  , $o{s} : $cmw[$c] ;
    my $addlen = $spare -$L[$r][$c] + $spare0 ; # if $cmw[$c] > $o{s}
    $spare0 = 0 + min 0 , $addlen ; 
    my $tmp = $C[$r][$c] . $o{b} x max 0, $addlen  ; 
    push @out, $tmp ; 
  }
  say join $o{c} , @out ; 
}

exit 0 ;

## ヘルプの扱い
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 

  入力をTSVと見なして、同じ列は縦に揃えて空白文字で埋めて出力する。
 
 [オプション] :

  -b char ; 間に埋める文字列。未指定なら半角空白 ' ' 。例として　 -b "-" 。betweenのbのつもり。
  -c char ; 列間で、列の直前に入れる文字。未指定なら半角空白 ' ' 。例として　 -c "|" 。connectorのcのつもり。
  -i delim : 区切り文字の変更。未指定なら、タブ文字。(出力は空白文字うめであり、変えない。)
  -s N : 出力の各セルにおいて、可能であれば(長い値は変えないで)埋めた空白をさらに幅何文字分(半角相当)まで縮めるか指定。
  -x : less に渡す引数(-xによるタブ位置の指定)のみを出力して終了。特に便利。
  -R0 : 通常Windows形式の改行文字であるCRLFはCFの部分を取り除く。しかし-R0指定でその処理をわざと行わない(通常時に利用は想定されていない, テスト目的などを想定)。

  --help : この $0 のヘルプメッセージを出す。  perldoc -t $0 | cat でもほぼ同じ。
  --help opt : オプションのみのヘルプを出す。opt以外でも options と先頭が1文字以上一致すれば良い。

  開発メモ: 
   * 右揃えのオプションが欲しいかも。
   * 行列として変数Cを参照するときに値が未定義の時にどうする。

  Text::VisualWidth のインスートルがあらかじめ必要である。
=cut
