package FFFF;
use strict;

use FFFF::Session;
use FFFF::Config;
use LocalCGI;
use InputCheck;

# -------------------------------------------------------------------------
# new
#
# -------------------------------------------------------------------------
sub new {
	my $class = shift;
	my %option = @_;

	my %form = QUERY_decode();

	my $action = ($form{_action} =~ /^([\-\w]+)$/)[0];
	my $back   = ($form{_back} =~ /^([\-\w]+)$/)[0];

	return bless {
		ACTION => uc $action,
		BACK   => uc $back,
		FORM   => \%form
	}, $class;
}

# -------------------------------------------------------------------------
# 設定ファイルの読み込み
#
# -------------------------------------------------------------------------
sub readconfig {
	my $self = shift;

	my $config = FFFF::Config->read();
	$self->{CONFIG} = $config->{DATA};

	my $action = $self->{BACK} || $self->{ACTION};
	$self->{CONFIG_NOW} = $self->{CONFIG}->{ACTION}->{$action};
}

# -------------------------------------------------------------------------
# セッションデータのチェック
#
# -------------------------------------------------------------------------
sub session_check {
	my $self = shift;

	return if (ref $self->{CONFIG_NOW}->{SESSION_CHECK} ne 'ARRAY');

	my %session = $self->session_data();
	for my $action  (map {@$_} $self->{CONFIG_NOW}->{SESSION_CHECK}) {
		my $config = $self->{CONFIG}->{ACTION}->{$action};

		my $check = InputCheck->new(
			%{$config->{INPUT_CHECK}->{PLAN}}
		);

		$check->execute(%session);

		if ($check->is_error() == 1) {
			$self->{ERROR} = {
				$check->get_error(
					%{$config->{INPUT_CHECK}->{ALIAS}}
				)
			};
			$self->{CONFIG_NOW}->{TEMPLATE}->{ERROR} = $config->{TEMPLATE}->{ERROR};
			last;
		}
	}
}


# -------------------------------------------------------------------------
# 入力チェック
#
# -------------------------------------------------------------------------
sub input_check {
	my $self = shift;

	my $check = InputCheck->new(
		%{$self->{CONFIG_NOW}->{INPUT_CHECK}->{PLAN}}
	);

	$check->execute(
		%{$self->{FORM}}
	);

	if ($check->is_error() == 1) {
		$self->{ERROR} = {
			$check->get_error(
				%{$self->{CONFIG_NOW}->{INPUT_CHECK}->{ALIAS}}
			)
		};
	}
}

sub is_error {
	my $self = shift;

	return (ref $self->{ERROR} eq "HASH")? 1 : 0;
}


# -------------------------------------------------------------------------
# セッションに保存
#
# TODO:
# - セッション関係の関数の頭にそれぞれ SessionType None の処理が
#   書いてあるのがダサイ。何とかしなければ。
#
# -------------------------------------------------------------------------
sub session_set {
	my $self = shift;

	return if ($self->{CONFIG}->{SESSION_TYPE} eq 'NONE');

	my $session = FFFF::Session->new (
		SESSION_DIR  => $self->{CONFIG}->{SESSION_DIR},
		COOKIE_KEY   => $self->{CONFIG}->{COOKIE_NAME}
	);

	
	#
	# セッションを開いてから失敗したら作成
	#
	if ($self->{ACTION} eq "" or $self->{SESSION_CREATE} == 1) {
		eval {
			$session->open();
		};
		if($@){
			$session->create();
		}
	}

	#
	# セッションを開く、失敗したらエラー
	#
	else {
		$session->open() or die "Can't Open Session";
	}

	$session->cleanup(%{$self->{FORM}});
	$session->set(%{$self->{FORM}});

	$self->{SESSION} = $session;
}

sub session_data {
	my $self = shift;

	if ($self->{CONFIG}->{SESSION_TYPE} eq 'NONE') {
		return %{$self->{FORM}};
	}
	else {
		return $self->{SESSION}->get_hash();
	}
}

sub session_expire {
	my $self = shift;

	return if ($self->{CONFIG}->{SESSION_TYPE} eq 'NONE');
	return $self->{SESSION}->expire();
}

# -------------------------------------------------------------------------
# モジュールの実行
#
# -------------------------------------------------------------------------
sub exec_module {
	my $self = shift;

	for my $module_obj (@{$self->{CONFIG_NOW}->{MODULE}}) {
		$module_obj->execute(
			$self->session_data()
		);
	}
}


# -------------------------------------------------------------------------
# 画面の出力
#
# -------------------------------------------------------------------------
sub outputhtml {
	my $self = shift;

	#
	# 出力する HTMLテンプレートの取得
	#
	my $template;
	if ($self->is_error() == 0) {
		$template = $self->{CONFIG_NOW}->{TEMPLATE}->{NEXT};
	}
	else {
		$template = $self->{CONFIG_NOW}->{TEMPLATE}->{ERROR};
	}
	$template ||= $self->{CONFIG}->{DEFAULT_TEMPLATE};
	$template = $self->search_template($template);

	#
	# HIDDEN_LOOP の作成
	#
	my @hidden_loop;
	while (my ($name, $value) = each %{$self->{FORM}}) {
		
		#
		# name の 先頭が _ から始まるものはシステム変数
		#
		next if ($name =~ /^_/);
		push(@hidden_loop, {name => $name, value => $value});
	}

	OutputHtml($template,
		$self->session_data(),
		%{$self->{CONFIG}->{DEFAULT_VALUE}},
		%{$self->{FORM}},
		%{$self->{ERROR}},
		_hidden_loop => \@hidden_loop,
	);
}

# -------------------------------------------------------------------------
# 出力するテンプレートの検索
#
# -------------------------------------------------------------------------
sub search_template {
	my $self = shift;
	my ($template) = @_;

	#
	# ファイルが無かった場合 search_path を検索
	#
	my @search = @{$self->{CONFIG}->{SEARCH_PATH}};
	if (!(-e $template) and $template =~ /^\w/) {
		for my $path (@search) {
			if (-e "$path/$template") {
				$template = "$path/$template";
				last;
			}
		}
	}
	unless (-e $template) {
		my ($package, $filename) = caller();
		die "Can't locate $template in search_path (search_path: @search, package: $package)";
	}

	return $template;
}

1;

__END__
=head CHANGES
0.0.3   2002/05/21
	- SessionType が None のときの処理を追加。
	- 入力されたフォームすべてが入っている hidden_loop を出力するようにした。

0.0.2   2002/05/15
	- 設定されていない Action で入ってきた場合、セッションチェックで
	  エラーになるバグを修正

0.0.1   2002/05/09
	- original version
=cut
