package FFFF::Module::csv;

# --------------------------------------------------------------------
# FFFF::Module::csv 
# - CSVデータの保存
#
#
# --------------------------------------------------------------------
use strict;
use base qw(FFFF::Module::Base);

require "jcode.pl";

# --------------------------------------------------------------------
# 設定ファイルの解析
#
# CONFIG => {
#           FILE => '/home/ta/{TIME:%Y_%m}.cvs',
#           SAVE => [
#                       '{TIME:%Y-%m-%d %H:%M:%S}',
#                       'id',
#                       'name',
#                       'kana',
#                       'email',
#                       '{FROM:zip1}-{FORM:zip2}',
#                       '{ENV:HTTP_USER_AGENT}',
#                       '{ENV:REMOTE_HOST}'
#                     ],
#           SEPARATE     => 'TAB'
#           CHAR_SET     => 'EUC-JP',
#           DELETE_BREAK => 1
# }
#
# --------------------------------------------------------------------
sub config {
	my $self = shift;
	my ($config) = @_;
	my %config;

	#
	# 保存する項目
	#
	$config{SAVE} = [map{@$_} map{@$_} $config->{save}];
	
	#
	# ヘッダー
	#
	if (ref $config->{header} eq "ARRAY") {
		$config{HEADER} = [map{@$_} map{@$_} $config->{header}];
	}

	#
	# 保存するファイル
	#
	$config{FILE} = $config->{file}->[0]->[0];

	#
	# 保存する項目
	#
	$config{SEPARATE} = ($config->{separate}->[0]->[0] =~ /^tab$/i)? "\t" : ",";


	#
	# 保存する文字コード
	#
	$config{CHAR_SET} = $config->{charset}->[0]->[0];
	if ($config{CHAR_SET} =~ /^Shift_JIS$/i) {
		$config{CHAR_SET} = 'sjis';
	}
	elsif ($config{CHAR_SET} =~ /^EUC-JP$/i) {
		$config{CHAR_SET} = 'euc';
	}
	elsif ($config{CHAR_SET} =~ /^ISO-2022-JP$/i) {
		$config{CHAR_SET} = 'jis';
	}
	$config{CHAR_SET} ||= 'sjis';


	#
	# 改行コード(LF, CF)を無視するかどうか
	# ディフォルト:On
	#
	$config{DELETE_BREAK} = $config->{deletebreak}->[0]->[0];
	$config{DELETE_BREAK} = ($config{DELETE_BREAK} =~ /^Off$/i)? 0 : 1;

	$self->{CONFIG} = \%config;
}

# --------------------------------------------------------------------
# execute
# - 値を取得してファイルにCSV形式で保存
#
# --------------------------------------------------------------------
sub execute {
	my $self     = shift;
	my (%form) = @_;

	my $config = $self->{CONFIG};

	#
	# フィルターのセット
	#
	$self->set_filter();


	#
	# ファイル名の設定
	#
	my $file = $config->{FILE};
	$file =~ s/{FORM:(.+?)}/$form{$1}/g;
	$file =~ s/{(\w+):(.+)}/$self->{FILTER}->execute($1, $2)/eg;


	#
	# 保存する項目の取得
	#
	my @save = $self->get_save_data(%form);


	#
	# 保存
	#
	open(CSV, ">>$file") or die "Can't Open file : $file";
	flock(CSV, 2) or die "Can't File Lock";
	seek(CSV, 0, 2);

	#
	# ファイルが 0 バイトでヘッダーが定義されていたらヘッダーを出力
	#
	if ((stat CSV)[7] == 0 and ref $config->{HEADER} eq "ARRAY") {

		my $header = join $config->{SEPARATE}, map {@$_} $config->{HEADER};
		$header = jcode::to($config->{CHAR_SET} , $header, "euc");
		print CSV "$header\n";
	}

	#
	# TAB区切り形式に変換してファイルに保存
	#
	my $line;
	if ($config->{SEPARATE} eq "\t") {
		$line = join "\t", map {s/\t//g; $_} @save;
	}

	#
	# CSV形式に変換してファイルに保存
	# http://www.din.or.jp/~ohzaki/perl.htm#CSVfromValues
	#
	else {
		$line = join ",", map {(s/"/""/g or /[\r\n,]/)? qq{"$_"} : $_} @save;
	}

	$line = jcode::to($config->{CHAR_SET}, $line, "euc");
	print CSV "$line\n";

	flock(CSV, 8);
	close(CSV);
}

# --------------------------------------------------------------------
# 保存する項目の取得
#
# --------------------------------------------------------------------
sub get_save_data {
	my $self     = shift;
	my (%form) = @_;

	my $config = $self->{CONFIG};

	#
	# 保存する項目の取得
	#
	my @save = map {@$_} $config->{SAVE};
	for my $save (@save) {

		#
		# フォームから取得
		#
		if ($save =~ /^(\w+)$/) {
			$save = $form{$1};
		}

		#
		# フィルター処理
		#
		else {
			$save =~ s/{FORM:(.+?)}/$form{$1}/g;
			$save =~ s/{(\w+):(.*?)}/$self->{FILTER}->execute($1, $2)/eg;
		}
	}

	#
	# 改行文字を取り除く
	#
	if ($config->{DELETE_BREAK} == 1) {
		for (@save) { s/\n|\r//g; }
	}

	return @save;
}

1;
__END__
=head CHANGES
0.0.4   2002/05/21
	- モジュールのオブジェクト化
	- フィルター処理のモジュール化

0.0.3   2002/05/15
	- 文字コードの指定に対応
　　　"CharSet  EUC-JP" の様に指定します。
	- strftime の %s(1970からのオフセット秒）Solarisで対応していないので
	  強引に対応。

0.0.2   2002/05/14
	- Header を指定していないとエラーになるバグ修正
	- TAB区切りに対応
	  "Separate  Tab" の様に指定します。

0.0.1   2002/05/09
	- original version
=cut

