#!/usr/bin/perl

=pod

=head1 NAME

average - Caluculate average of each continuous N-numbers.

=head1 SYNOPSIS

    perl average.pl [-c num] [-h] [-n num] [-p] [-s] input_file

=head1 DESCRIPTION

入力ファイルの各行に対してその過去何行分かの平均(あるいは和)を算出する．

全てのデータの平均(あるいは合計)を求めたり，1と0のみからなるデータに対して1になっている頻度を求めたり，起伏の激しいグラフをなだらかに平均化することが可能．

=head1 OPTIONS

=over 4

=item -c num

対象となる列を指定する．
最初の列が1列目で，デフォルト値は1列目になっている．

=item -h

ヘルプ．

=item -n num

過去n行分(現在の行を含む)の平均をとる．
ただし，最初の行などn行に満たない部分は加算した行数分で平均をとる．
このオプションが省略された場合には，num=入力ファイルの行数とする．

=item -s

平均ではなく和を出力する．

=back

=head1 INPUT EXAMPLE

    2
    1
    8
    4
    5
    3
    1

=head1 OUTPUT EXAMPLE

    perl average.pl -n 3 testdata

    2
    1.5
    3.66666666666667
    4.33333333333333
    5.66666666666667
    4
    3

=cut

use strict;
use Getopt::Std;

# コマンドラインオプション
my %options;
getopts('c:hn:s', \%options);

# ヘルプ
if ($options{h}) {
    &print_usage();
    exit(0);
}

# 何行分を対象にするか
my $n;
if ($options{n}) {
    my $num = $options{n};
    if (&is_numeric($num)) {            ## 数字かどうかチェック
        $n = $num;
    } else {
        &print_usage();
        exit(1);
    }
} else {
    # TODO: not smart.
    split(/\s/, `wc -l $ARGV[0]`);
    $n = $_[0];
}
my @buf;                               ## 対象範囲分のデータを保持するキャッシュ

# 何列目を対象にするか
my $column = 1;
if ($options{"c"}) {
    $column = $options{"c"};
}
$column--;

# 分母
my $denominator = $n; ## 平均を取る範囲
if ($options{s}) {
    $denominator = 1; ## -s なら和を取る 
}

# 引数不正
if (@ARGV >= 2) {
    &print_usage();
    exit(1);
}

my $sum = 0; # 合計値
my @data;    # 1行分のデータ
#=====================================================================
# メイン
#
# パフォーマンスのため，1行毎に変更のあった分だけ加減する．
#=====================================================================
while (<>) {
 	chomp;                              ## 改行除去
    # データ取得
    @data = split(/\s+/);               ## 半角スペースで区切る
    if (!exists($data[$column])) {      ## 対象要素の値をチェック
        die "Input file format error.";
    }

    # バッファ内の古いデータ削除
    my $removed = 0;
 	if (@buf == $n) {
 	    $removed = shift(@buf);         ## 最古データを除去
 	}
    push(@buf, $data[$column]);         ## 新規データの追加

 	# 和 or 平均の計算
    $sum = $sum - $removed + $data[$column];
    $data[$column] = $sum / $denominator;
#    $data[$column] = $sum / @buf; # TODO: which is better ?

    # 出力
    print join(' ', @data), "\n";       ## 対象列の要素だけを変更して，一行分を出力
}
exit(0);

#---------------------------------------------------------------------
# 使い方
#---------------------------------------------------------------------
sub print_usage {
    print "average - Caluculate average of each continuous N-numbers.\n";
    print "Usage: perl $0 [-c num] [-h] [-n num] [-s] input_file\n";
}

#---------------------------------------------------------------------
# 数値かどうかチェック
#---------------------------------------------------------------------
sub is_numeric {
	my $text = shift;
	if($text =~ /^[0-9]+$/){
		return 1;
	} else {
		return 0;
	}
}

