package FFFF::Module::db;

# --------------------------------------------------------------------
# FFFF::Module::db 
#
#
# --------------------------------------------------------------------
use strict;
use DBI;

use base qw(FFFF::Module::Base);
use FFFF::Module::Filter;

# --------------------------------------------------------------------
# 設定ファイルの解析
#
# CONFIG => {
#          DATA_SOURCE => 'dbi:Pg:dbname=4f'
#          USER_NAME   => 'user',
#          PASSWORD    => 'passwd',
#          INSERT => [
#                       {
#                          TABLE  => 'staff'
#                          COLUMN => {
#                                         id       => 'id',
#                                         kana     => 'kana',
#                                         email    => 'email',
#                                         name     => 'name'
#                                         mod_date => '{DB:now()}',
#                                    },
#                      },
#                   ],
#          DELETE_BREAK => 0,
# };
#
# --------------------------------------------------------------------
sub config {
	my $self = shift;
	my ($config) = @_;
	my %config;

	#
	# DB
	#
	$config{DATA_SOURCE} = $config->{datasource}->[0]->[0];
	$config{USER_NAME}   = $config->{username}->[0]->[0];
	$config{PASSWORD}    = $config->{password}->[0]->[0];


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


	#
	# INSERT TABLE
	#
	my @insert;
	while (my($table, $data) = each %{$config->{insert}}) {
		
		for my $col_ref (@$data) {

			#
			# カラムの配列、VALUES句の配列、BIND変数の配列を作成
			#
			my (@col, @bind, @value);
			while (my ($col, $value) = each %$col_ref) {
				my $bind = $value->[0]->[0];

				if ($bind =~ /^{DB:(.+?)}$/) {
					push(@col, $col);
					push(@value, $1);
				}
				else {
					push(@col, $col);
					push(@value, '?');
					push(@bind, $bind );
				}
			}

			push(@insert, {
					SQL  => "INSERT INTO $table (" .  join(',', @col) . ") VALUES (" . join(',', @value) . ")",
					BIND => \@bind,
				}
			);
		}
	}
	$config{INSERT} = \@insert;

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

# --------------------------------------------------------------------
# execute
# - 値を取得してDBにデータを格納
#
# --------------------------------------------------------------------
sub execute {
	my $self   = shift;
	my (%form) = @_;;

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

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

	#
	# DB に接続
	#
	my $dbh = DBI->connect(
		$config->{DATA_SOURCE},
		$config->{USER_NAME},
		$config->{PASSWORD},
		{ RaiseError => 1, AutoCommit => 0 }
	) or die $DBI::errstr;


	#
	# データベースに格納
	#
	for my $insert (map {@$_} $config->{INSERT}) {

		#
		# BIND変数のセット
		#
		my @bind = map {@$_} $insert->{BIND};
		for my $bind (@bind) {

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

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

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

		#
		# DBに格納
		#
		my $sth = $dbh->prepare($insert->{SQL});
		$sth->execute(@bind);
	}

	#
	# DBから切断
	#
	$dbh->commit();
	$dbh->disconnect();
}

1;

=head CHANGES
0.0.3   2002/05/22
    - モジュールのオブジェクト化
    - フィルター処理のモジュール化

0.0.2   2002/05/16
    - strftime の %s(1970からのオフセット秒）Solarisで対応していないので
      強引に対応。

0.0.1   2002/05/09
    - original version
=cut
