package SWFileVil;

#----------------------------------------
# 村データファイル制御
#----------------------------------------

#----------------------------------------
# コンストラクタ
#----------------------------------------
sub new {
	my ($class, $sow, $vid) = @_;
	require "$sow->{'cfg'}->{'DIR_LIB'}/file_player.pl";

	my %pl;
	my @pllist;
	my $self = {
		sow  => $sow,
		vid    => $vid,
		pl     => \%pl,
		pllist => \@pllist,
	};
	my %csidlist = ();
	$sow->{'csidlist'} = \%csidlist;

	return bless($self, $class);
}

#----------------------------------------
# 村データの作成
#----------------------------------------
sub createvil {
	my $self = shift;
	my $sow = $self->{'sow'};
	my $filename = &GetFNameVil($self->{'sow'}, $self->{'vid'});

	my $fh = \*VIL;
	my $file = SWFile->new($self->{'sow'}, 'vil', $fh, $filename, $self);
	$file->openfile(
		'>',
		'村データ',
		"[vid=$self->{'vid'}]",
	);
	$self->{'file'} = $file;
	$self->closevil();

	$self->{'turn'}          = 0;
	$self->{'updateddt'}     = $sow->{'time'};
	$self->{'nextupdatedt'}  = $sow->{'time'};
	$self->{'nextchargedt'}  = $sow->{'time'};
	$self->{'nextcommitdt'}  = $sow->{'time'};
	$self->{'epilogue'}      = 9999;
	$self->{'winner'}        = 0;
	$self->{'useless'}        = 0;
	$self->{'modifiedsay'}   = 0;
	$self->{'modifiedwsay'}  = 0;
	$self->{'modifiedgsay'}  = 0;
	$self->{'modifiedspsay'} = 0;
	$self->{'modifiedbsay'}  = 0;
	$self->{'cntmemo'}       = 0;
	$self->{'emulated'}      = 0;
	%{$self->{'pl'}} = ();
	@{$self->{'pllist'}} = ();
	%{$sow->{'csidlist'}} = ();
	$sow->{'turn'} = 0;

	return;
}

#----------------------------------------
# ダミーの村データの作成
#----------------------------------------
sub createdummyvil {
	my $self = shift;
	my $sow = $self->{'sow'};

	$self->{'turn'}         = 0;
	$self->{'updateddt'}    = $sow->{'time'};
	$self->{'nextupdatedt'} = $sow->{'time'};
	$self->{'nextchargedt'} = $sow->{'time'};
	$self->{'nextcommitdt'} = $sow->{'time'};
	$self->{'epilogue'}     = 9999;
	$self->{'winner'}       = 0;
	$self->{'randomtarget'} = 0;
	$self->{'showid'}       = 0;
	$self->{'emulated'}     = 1;
	%{$self->{'pl'}} = ();
	@{$self->{'pllist'}} = ();
	%{$sow->{'csidlist'}} = ();
	$sow->{'turn'} = 0;

	return;
}

#----------------------------------------
# 村データの読み込み
#----------------------------------------
sub readvil {
	my $self = shift;
	my $sow = $self->{'sow'};
	my $filename = &GetFNameVil($sow, $self->{'vid'});

	# ファイルを開く
	my $fh = \*VIL;
	my $file = SWFile->new($self->{'sow'}, 'vil', $fh, $filename, $self);
	$file->openfile(
		'+<',
		'村データ',
		"[vid=$self->{'vid'}]",
	);
	$self->{'file'} = $file;

	seek($fh, 0, 0);
	my @data = <$fh>;

	# 村データの読み込み
	my $villabel = shift(@data);
	my @villabel = split(/<>/, $villabel);
	@villabel = &GetVilDataLabel() if ($villabel[0] eq '');
	@$self{@villabel} = split(/<>/, shift(@data));

	my @villabelnew = &GetVilDataLabel();
	# 移行用コード
	foreach (@villabelnew) {
		$self->{$_} = 0 if (!defined($self->{$_}));
	}
	$self{'useless'} = 0;

	$self->{'entrypwd'} = '' if (!defined($self->{'entrypwd'}));
	$self->{'entrypwd'} = '' if ($self->{'entrypwd'} eq $self->{'sow'}->{'DATATEXT_NONE'});

	my $pllabel = shift(@data);
	chomp($pllabel);
	my @pllabel = split(/<>/, $pllabel);
	%{$self->{'pl'}} = ();
	@{$self->{'pllist'}} = ();
	%{$sow->{'csidlist'}} = ();

	my $i = 0;
	my $datacnt = @data;
	while ($i < $datacnt) {
		chomp($data[$i]);
		if ($data[$i] ne '') {
			my $plsingle = SWPlayer->new($sow);
			$plsingle->readpl(\@pllabel, $data[$i]);
			$self->addpl($plsingle);
		}
		$i++;
	}

	# 参照中の村番号とログ日付番号をセット
	if (defined($sow->{'query'}->{'turn'})) {
		$sow->{'turn'} = $sow->{'query'}->{'turn'};
	} else {
		$sow->{'turn'} = $self->{'turn'};
#		$sow->{'turn'} = $self->{'epilogue'} if ($self->{'epilogue'} < $self->{'turn'});
	}

	# カレントプレイヤー（ログイン中のプレイヤー）
	$sow->{'curpl'} = $self->getpl($sow->{'uid'}) if ($self->checkentried() >= 0);

	$self->{'emulated'} = 0;

	$self->closevil();

	return;
}

#----------------------------------------
# 村データの書き込み
#----------------------------------------
sub writevil {
	my $self = shift;
	my $sow = $self->{'sow'};
	my $pl     = $self->{'pl'};
	my $pllist = $self->{'pllist'};

#	my $fh = $self->{'file'}->{'filehandle'};
#	truncate($fh, 0);
#	seek($fh, 0, 0);

	my $fh = \*TMP;
	my $tempfname = sprintf(
		"%s/%04d%s_%s_%s",
		$sow->{'cfg'}->{'DIR_VIL'},
		$self->{'vid'},
		$ENV{'REMOTE_PORT'},
		$$,
		$sow->{'cfg'}->{'FILE_VIL'},
	);
	open($fh, ">$tempfname") || $sow->{'debug'}->raise($sow->{'APLOG_WARNING'}, "村データの書き込みに失敗しました。", "cannot write vil data.");

	$self->{'entrypwd'} = $self->{'sow'}->{'DATATEXT_NONE'} if ($self->{'entrypwd'} eq '');
	my @villabel = &GetVilDataLabel();
	print $fh join("<>", @villabel). "<>\n";
	print $fh join("<>", map{$self->{$_}}@villabel). "<>\n";

	if (@$pllist > 0) {
		my @pllabel = $pllist->[0]->getdatalabel();
		print $fh join("<>", @pllabel). "<>\n";
		foreach (@$pllist) {
			next if ($_->{'delete'} > 0); # 削除
			$_->writepl($fh);
		}
	}
	close($fh);

	my $filename = &GetFNameVil($self->{'sow'}, $self->{'vid'});
	rename($tempfname, $filename);

	$self->{'entrypwd'} = '' if ($self->{'entrypwd'} eq $self->{'sow'}->{'DATATEXT_NONE'});
}

#----------------------------------------
# 村データを閉じる
#----------------------------------------
sub closevil {
	my $self = shift;
	$self->{'file'}->closefile();
}

#----------------------------------------
# プレイヤー追加
#----------------------------------------
sub addpl {
	my ($self, $plsingle) = @_;

	my $pllist = $self->{'pllist'};

	$plsingle->{'vil'} = $self;
	$self->{'pl'}->{$plsingle->{'uid'}} = $plsingle;
	$plsingle->{'pno'} = @$pllist;
	$pllist->[$plsingle->{'pno'}] = $plsingle;
	$self->{'sow'}->{'csidlist'}->{$plsingle->{'csid'}} = 1;

	return;
}

#----------------------------------------
# 指定したuidのプレイヤーデータを得る
#----------------------------------------
sub getpl {
	my ($self, $uid) = @_;
	return $self->{'pl'}->{$uid};
}

#----------------------------------------
# 指定した番号のプレイヤーデータを得る
#----------------------------------------
sub getplbypno {
	my ($self, $pno) = @_;
	return $self->{'pllist'}->[$pno];
}

#----------------------------------------
# プレイヤーデータの配列を得る
#----------------------------------------
sub getpllist {
	my $self = shift;
	return $self->{'pllist'};
}

#----------------------------------------
# 生存中のプレイヤーデータの配列を得る
#----------------------------------------
sub getlivepllist {
	my $self = shift;
	my @livepllist;
	foreach (@{$self->{'pllist'}}) {
		push(@livepllist, $_) if ($_->{'live'} eq 'live');
	}
	return \@livepllist;
}

#----------------------------------------
# アクセスしているプレイヤーが参加済みかどうかを得る
#----------------------------------------
sub checkentried {
	my $self = shift;
	my $pno = $self->{'pl'}->{$self->{'sow'}->{'uid'}}->{'pno'};
	if (defined($pno)) {
		return $pno;
	} else {
		return -1;
	}
}

#----------------------------------------
# 発言数初期化
#----------------------------------------
sub setsaycountall {
	my $self = $_[0];

	foreach (@{$self->{'pllist'}}) {
		$_->setsaycount();
	}

	return;
}

#----------------------------------------
# 発言数回復
#----------------------------------------
sub chargesaycountall {
	my $self = $_[0];

	foreach (@{$self->{'pllist'}}) {
		$_->chargesaycount();
	}

	return;
}

#----------------------------------------
# コミット済みの人数を得る
#----------------------------------------
sub getcommitedpl {
	my ($self, $cmd) = @_;
	my $sow = $self->{'sow'};

	my $getlivepllist = $self->getlivepllist();
	my $commitedpl = 0;
	foreach (@$getlivepllist) {
		$commitedpl++ if ($_->{'commit'} > 0);
	}

	return $commitedpl;
}

#----------------------------------------
# 村がエピローグに入っている／終了しているかどうか
#----------------------------------------
sub isepilogue {
	my $self = shift;
	my $result = 0;
	$result = 1 if ($self->{'turn'} >= $self->{'epilogue'});

	return $result;
}


#----------------------------------------
# 村がプロローグ中であるか
#----------------------------------------
sub isprologue {
	my $self = shift;
	my $result = 0;
	$result = 1 if ($self->{'turn'} == 0);
	return $result;
}


#----------------------------------------
# 村データラベル
#----------------------------------------
sub GetVilDataLabel {
	my @datalabel = (
		'makeruid',
		'vname',
		'vcomment',
		'trsid',
		'csid',
		'roletable',
		'updhour',
		'updminite',
		'updinterval',
		'entrylimit',
		'entrypwd',
		'rating',
		'turn',
		'vplcnt',
		'vplcntstart',
		'saycnttype',
		'epilogue',
		'updateddt',
		'nextupdatedt',
		'nextchargedt',
		'nextcommitdt',
		'scraplimitdt',
		'winner',
		'useless',
		'votetype',
		'starttype',
		'randomtarget',
		'showid',
		'noselrole',
		'cntvillager',   # 村人
		'cntwolf',       # 人狼
		'cntseer',       # 占い師
		'cntmedium',     # 霊能者
		'cntpossess',    # 狂人
		'cntguard',      # 狩人
		'cntfm',         # 共有者
		'cnthamster',    # ハムスター人間
		'cntcpossess',   # Ｃ国狂人
		'cntstigma',     # 聖痕者
		'cntfanatic',    # 狂信者
		'cntsympathy',   # 共鳴者
		'cntwerebat',    # コウモリ人間
		'cntcwolf',      # 呪狼
		'cntintwolf',    # 智狼
		'cnttrickster',  # ピクシー
		'modifiedsay',
		'modifiedwsay',
		'modifiedgsay',
		'modifiedspsay',
		'modifiedbsay',
		'cntmemo',
	);
	return @datalabel;
}

#----------------------------------------
# 村データファイル名の取得
#----------------------------------------
sub GetFNameVil {
	my ($sow, $vid) = @_;
	$vid = 0 if ($vid eq '');

	my $datafile = sprintf(
		"%s/%04d_%s",
		$sow->{'cfg'}->{'DIR_VIL'},
		$vid,
		$sow->{'cfg'}->{'FILE_VIL'},
	);
	return $datafile;
}

1;