use strict;
use warnings;


    # 使い方
    # perl metricsWithNodeWgt.pl merge_***.paj subCommunity_1_***.net subCommunity_2_***.net subCommunity_1_***.vec subCommunity_2_***.vec
    # 時期(***)が同じPajファイルとsubCommunity_1，subCommunity_2のNet,Vecファイルの5つが必要

	# Partitionを割り振るための変数
	my ($subCommunity_1,$subCommunity_2,$andman);
	# Pajファイル，Netファイル(subCommunity_1またはsubCommunity_2)を読み込んでNode情報やArcs，Partition情報をそれぞれ配列に割り振るためのフラグ
	my ($flag4PajFile,$flag4NetFile_1,$flag4NetFile_2);
	# Pajファイル，Netファイル(subCommunity_1またはsubCommunity_2)，Vecファイル(subCommunity_1,2の参加者それぞれの次数中心性の値)を一行ずつ取得するための変数
	my ($line,$line1,$line2,$line3,$line4);
	# Pajファイルの情報を取得するための変数ならびに配列
	my (@nodeNoInPajFile,@nodeNameInPajFile,@fromInPajFile,@toInPajFile,@numInPajFile,@arcListInPajFile,@partition,$arcsNumInPajFile,$nodeNumInPajFile);
	# Netファイル(subCommunity_1)の情報を取得するための変数ならびに配列
	my (@nodeNoInNetFile_1,@nodeNameInNetFile_1,@fromInNetFile_1,@toInNetFile_1,@numInNetFile_1,@arcListInNetFile_1,$arcsNumInNetFile_1,$nodeNumInNetFile_1);
	# Netファイル(subCommunity_2)の情報を取得するための変数ならびに配列
	my (@nodeNoInNetFile_2,@nodeNameInNetFile_2,@fromInNetFile_2,@toInNetFile_2,@numInNetFile_2,@arcListInNetFile_2,$arcsNumInNetFile_2,$nodeNumInNetFile_2);
	# Vecファイル(次数中心性値の一覧)内の値を取得するための配列
	my (@allCentralityInSubCommunity_1,@allCentralityInSubCommunity_2);
	# PajファイルのIDとNetファイルのIDの対応関係を確認するための変数
	my ($fromIDinSubCommunity_1,$toIDinSubCommunity_1,$fromIDinSubCommunity_2,$toIDinSubCommunity_2);
	# ループ処理で使う変数
	my ($i,$j,$m,$n,$p,$q,$s,$u,$v,$x,$y);
	# エッジを分類するための変数
	my (@sum_subCommunity_1ToAndman,@sum_subCommunity_2ToAndman,@sum_andmanToSubCommunity_1,@sum_andmanToSubCommunity_2);
	# 指標値の算出結果を保存するための変数ならびに配列
	my ($f1, $f2, $subCommunity_1To2,$subCommunity_2To1,@metrics4SubCommunity_1To2,@metrics4SubCommunity_2To1);


	# Partition情報　１：subCommunity_1の参加者　２：subCommunity_2の参加者　３：subCommunity_1かつsubCommunity_2の参加者
	$subCommunity_1 = 1;
	$subCommunity_2 = 2;
	$andman = 3;


############### Pajファイル，Netファイルを読み込んで必要な情報を取得 #########################


	$flag4PajFile = 0;

	# Pajファイルで必要なのは，Node情報(アドレス)とArcs情報，Partition情報
	open PAJ,$ARGV[0] or die "file open error: $ARGV[0]";
	while($line = <PAJ>){
		chomp($line);
		if($line =~ /\*Network/i){
			next;
		}
		elsif($line =~ /\*Arcs/i){
			$flag4PajFile = 1;
			next;
		}
		elsif($line =~ /\*Partition/i){
			if($line =~ /\*Partition high\.clu/i){
				last;
			}
			$flag4PajFile = 2;
			next;
		}

		# OSSコミュニティ参加者のアドレス一覧
		# $nodeNoInPajFile[0]には*Verticesが入る
		# $nodeNameInPajFile[0]にはノード数が入る
		# e.g.) 1 "aaa@aaa.co.jp"　の場合，$nodeNoInPajFile[1]=1 $nodeNamePajFile[1]="aaa@aaa.co.jp"が入る
		if($flag4PajFile == 0){
			my($nodeNoInPajFile, $nodeNameInPajFile) = split / /, $line;
			#push(@nodeNoInPajFile, $nodeNoInPajFile);
			push(@nodeNameInPajFile, $nodeNameInPajFile);
		}

		# Arcs情報の取得 e.g.) 1 2 3 ⇒　fromInPajFile=1,toInPajFile=2,numInPajFile=3
		# $fromInPajFile[0]，$toInPajFile[0]，$numInPajFile[0]から順番に保存される
		elsif($flag4PajFile == 1){
			my($fromInPajFile, $toInPajFile, $numInPajFile) = split/ /, $line;
			# from to num の3要素に分けて配列へ
			push(@fromInPajFile, $fromInPajFile);
			push(@toInPajFile, $toInPajFile);
			# ↓エッジ重み付きのときだけ必要
			#push(@numInPajFile, $numInPajFile);
			push(@arcListInPajFile,"$fromInPajFile $toInPajFile $numInPajFile");
		}

		# partition情報の取得  e.g.) IDが1の人のpartition情報はpartition[1]に格納される
		# *Partition　○○.pajの次の行が*Vertices ノード数 なので，$partition[0]には"*Vertices ノード数"の文字列が入ってる
		elsif($flag4PajFile == 2){
			push(@partition, $line);
		}
	}

	# Pajファイルの*Arcsの総行数
	$arcsNumInPajFile = @arcListInPajFile;
	# Pajファイルの全ノード数
	$nodeNumInPajFile = $nodeNameInPajFile[0];


############### Netファイル(subCommunity_1)を読み込んで指標を取得する上で必要な情報を配列に保存 #################


	$flag4NetFile_1 = 0;

	# Netファイル(subCommunity_1)で必要なのは，Node情報とArcs情報
	open NET1,$ARGV[1] or die "file open error: $ARGV[1]";
	while($line1 = <NET1>){
		chomp($line1);
		if($line1 =~ /\*Network/i){
			next;
		}
		elsif($line1 =~ /\*Arcs/i){
			$flag4NetFile_1 = 1;
			next;
		}
		
		# $nodeNoInNetFile_1[0]には*Verticesが入る
		# $nodeNameInNetFile_1[0]にはノード数が入る
		if($flag4NetFile_1 == 0){
			my($nodeNoInNetFile_1, $nodeNameInNetFile_1) = split / /, $line1;
			#push(@nodeNoInNetFile_1, $nodeNoInNetFile_1);
			push(@nodeNameInNetFile_1, $nodeNameInNetFile_1);
		}
		# Arcs情報の取得 e.g.) 1 2 3 ⇒　fromInPajFile=1,toInPajFile=2,numInPajFile=3
		# $fromInNetFile_1[0]，$toInNetFile_1[0]，$numInNetFile_1[0]から順番に保存される
		elsif($flag4NetFile_1 == 1){
			# from to num の3要素に分けて配列へ
			my($fromInNetFile_1, $toInNetFile_1, $numInNetFile_1) = split/ /, $line1;
			push(@fromInNetFile_1, $fromInNetFile_1);
			push(@toInNetFile_1, $toInNetFile_1);
			# ↓エッジ重み付きのときだけ必要
			#push(@numInNetFile_1, $numInNetFile_1);
			push(@arcListInNetFile_1,"$fromInNetFile_1 $toInNetFile_1 $numInNetFile_1");
		}
	}
	# Netファイル(subCommunity_1)の*Arcsの総行数
	$arcsNumInNetFile_1 = @arcListInNetFile_1;
	# Netファイル(subCommunity_1)の全ノード数
	$nodeNumInNetFile_1 = $nodeNameInNetFile_1[0];


############### Netファイル(subCommunity_2)を読み込んで指標を取得する上で必要な情報を配列に保存 #################


	$flag4NetFile_2 = 0;

	# Netファイル(subCommunity_2)で必要なのは，Node情報とArcs情報
	open NET2,$ARGV[2] or die "file open error: $ARGV[2]";
	while($line2 = <NET2>){
		chomp($line2);
		if($line2 =~ /\*Network/i){
			next;
		}
		elsif($line2 =~ /\*Arcs/i){
			$flag4NetFile_2 = 1;
			next;
		}

		# $nodeNoInNetFile_2[0]には*Verticesが入る
		# $nodeNameInNetFile_2[0]にはノード数が入る
		if($flag4NetFile_2 == 0){
			my($nodeNoInNetFile_2, $nodeNameInNetFile_2) = split / /, $line2;
			#push(@nodeNoInNetFile_2, $nodeNoInNetFile_2);
			push(@nodeNameInNetFile_2, $nodeNameInNetFile_2);
		}
		# Arcs情報の取得 e.g.) 1 2 3 ⇒　fromInPajFile=1,toInPajFile=2,numInPajFile=3)
		# $fromInNetFile_2[0]，$toInNetFile_2[0]，$numInNetFile_2[0]から順番に保存される
		elsif($flag4NetFile_2 == 1){
			my($fromInNetFile_2, $toInNetFile_2, $numInNetFile_2) = split/ /, $line2;
			push(@fromInNetFile_2, $fromInNetFile_2);
			push(@toInNetFile_2, $toInNetFile_2);
			# ↓エッジ重み付きのときだけ必要
			#push(@numInNetFile_2, $numInNetFile_2);
			push(@arcListInNetFile_2,"$fromInNetFile_2 $toInNetFile_2 $numInNetFile_2");
		}
	}
	# Netファイル(subCommunity_2)の*Arcsの総行数
	$arcsNumInNetFile_2 = @arcListInNetFile_2;
	# Netファイル(subCommunity_2)の全ノード数
	$nodeNumInNetFile_2 = $nodeNameInNetFile_2[0];


######## subCommunity_1の参加者の次数(all)中心性値をvecファイルから取得 (i番目の人の中心性値＝metrics[i]) #######


	# $allCentralityInSubCommunity_1[0]には"*Vertices ノード数"の文字列が入るため，$allCentralityInSubCommunity_1[1]から保存される
	open MET1,$ARGV[3] or die "file open error: $ARGV[3]";
	while($line3 = <MET1>){
		chomp($line3);
		push(@allCentralityInSubCommunity_1, $line3);
	}

	#print @allCentralityInSubCommunity_1;


######## subCommunity_2の参加者の次数(all)中心性値をvecファイルから取得 (i番目の人の中心性値＝metrics[i]) #######


	# $allCentralityInSubCommunity_2[0]には"*Vertices ノード数"の文字列が入るため，$allCentralityInSubCommunity_2[1]から保存される
	open MET2,$ARGV[4] or die "file open error: $ARGV[4]";
	while($line4 = <MET2>){
		chomp($line4);
		push(@allCentralityInSubCommunity_2, $line4);
	}

	#print @allCentralityInSubCommunity_2;


############## 指標値を算出するための前準備 (アンドマンのエッジを入次数と出次数とに分ける) ###########


	# andman(Partition = 3)から出ているエッジか、andmanに入っているエッジかで分けて考える
	for($j=0;$j<$arcsNumInPajFile;$j++){
		# andman ⇔　andmanだけを抽出
		# subCommunity_1内でのやりとりなのかsubCommunity_2内でのやりとりなのかを区別する
		# まずは，メッセージの送信者($from)と受信者($to)がともにandmanであるかどうか調べる
		if(($partition[$fromInPajFile[$j]] == $andman) && ($partition[$toInPajFile[$j]] == $andman)){

			# ちゃんとandman同士のやりとりを抽出できてるかの確認f(^ ^;)
			#print $arcListInPajFile[$j];
			#print $fromInPajFile[$j],"\n";
			#print $toInPajFile[$j],"\n";

			# 送信者・受信者がともにsubCommunity_1の参加者の場合
			# PajファイルでのIDとNetファイル(subCommunity_1)でのIDの対応関係を調べる
			for($m=1;$m<=$nodeNumInNetFile_1;$m++){
				# ここではメッセージ送信者($from)のIDの対応関係を調べる
				if($nodeNameInPajFile[$fromInPajFile[$j]] eq $nodeNameInNetFile_1[$m]){
					# PajファイルでIDが$fromInPajFile[$j]の人は，Netファイル(subCommunity_1)ではIDが$fromIDinSubCommunity_1
					$fromIDinSubCommunity_1 = $m;
				}
			}
			for($m=1;$m<=$nodeNumInNetFile_1;$m++){
				# ここではメッセージ受信者($to)のIDの対応関係を調べる
				if($nodeNameInPajFile[$toInPajFile[$j]] eq $nodeNameInNetFile_1[$m]){
					# PajファイルでIDが$toInPajFile[$j]の人は，Netファイル(subCommunity_1)ではIDが$toIDinSubCommunity_1
					$toIDinSubCommunity_1 = $m;
				}
			}
			for($n=1;$n<$arcsNumInNetFile_1;$n++){
				unless(!defined($fromIDinSubCommunity_1) || !defined($toIDinSubCommunity_1)){
					if($fromInNetFile_1[$n] == $fromIDinSubCommunity_1 && $toInNetFile_1[$n] == $toIDinSubCommunity_1){
						# 条件に一致したエッジのノード重み(次数中心性)を順次加算していく
						# メッセージの送信者($from)をandmanとした場合　andman⇒subCommunity_1(出次数)
						$sum_andmanToSubCommunity_1[$fromInPajFile[$j]] += $allCentralityInSubCommunity_1[$toIDinSubCommunity_1];
						# メッセージの受信者($to)をandmanとした場合　subCommunity_1⇒andman(入次数)
						$sum_subCommunity_1ToAndman[$toInPajFile[$j]] += $allCentralityInSubCommunity_1[$fromIDinSubCommunity_1];
						# ↓エッジ重み付きのときはこっち
						#$sum_andmanToSubCommunity_1[$fromInPajFile[$j]] += $numInNetFile_1[$n];
						#$sum_subCommunity_1ToAndman[$toInPajFile[$j]] += $numInNetFile_1[$n];
					}
				}
			}

			# 送信者・受信者がともにsubCommunity_2の参加者の場合
			for($p=1;$p<=$nodeNumInNetFile_2;$p++){
				# PajファイルでのIDとNetファイル(subCommunity_2)でのIDの対応関係を調べる
				# ここではメッセージ送信者($from)のIDの対応関係を調べる
				if($nodeNameInPajFile[$fromInPajFile[$j]] eq $nodeNameInNetFile_2[$p]){
					# PajファイルでIDが$fromInPajFile[$j]の人は，Netファイル(subCommunity_2)ではIDが$fromIDinSubCommunity_2
					$fromIDinSubCommunity_2 = $p;
				}
			}
			for($p=1;$p<=$nodeNumInNetFile_2;$p++){
				# ここではメッセージ受信者($to)のIDの対応関係を調べる
				if($nodeNameInPajFile[$toInPajFile[$j]] eq $nodeNameInNetFile_2[$p]){
					# PajファイルでIDが$toInPajFile[$j]の人は，Netファイル(subCommunity_2)ではIDが$toIDinSubCommunity_2
					$toIDinSubCommunity_2 = $p;
				}
			}
			for($q=1;$q<$arcsNumInNetFile_2;$q++){
				unless(!defined($fromIDinSubCommunity_2) || !defined($toIDinSubCommunity_2)){
					if($fromInNetFile_2[$q] == $fromIDinSubCommunity_2 && $toInNetFile_2[$q] == $toIDinSubCommunity_2){
						# 条件に一致したエッジのノード重み(次数中心性)を順次加算していく
						# メッセージの送信者($from)をandmanとした場合　andman⇒subCommunity_2(出次数)
						$sum_andmanToSubCommunity_2[$fromInPajFile[$j]] += $allCentralityInSubCommunity_2[$toIDinSubCommunity_2];
						# メッセージの受信者($to)をandmanとした場合　subCommunity_2⇒andman(入次数)
						$sum_subCommunity_2ToAndman[$toInPajFile[$j]] += $allCentralityInSubCommunity_2[$fromIDinSubCommunity_2];
						# ↓エッジ重み付きのときはこっち
						#$sum_andmanToSubCommunity_2[$fromInPajFile[$j]] += $numInNetFile_2[$q];
						#$sum_subCommunity_2ToAndman[$toInPajFile[$j]] += $numInNetFile_2[$q];
					}
				}
			}
		}

		# andman ⇒ subCommunity_1 or subCommunity_2の参加者の場合(出次数)
		elsif($partition[$fromInPajFile[$j]] == $andman){
			# andman ⇒ subCommunity_1 のパターン
			if($partition[$toInPajFile[$j]] == $subCommunity_1){
				for($u=1;$u<=$nodeNumInNetFile_1;$u++){
					if($nodeNameInPajFile[$toInPajFile[$j]] eq $nodeNameInNetFile_1[$u]){
						# PajファイルでIDが$toInPajFile[$j]の人は，Netファイル(subCommunity_1)ではIDが$u
						# 条件に一致したエッジのノード重み(次数中心性)を順次加算していく
						$sum_andmanToSubCommunity_1[$fromInPajFile[$j]] += $allCentralityInSubCommunity_1[$u];
					}
				}
			}

			# andman ⇒ subCommunity_2 のパターン
			elsif($partition[$toInPajFile[$j]] == $subCommunity_2){
				for($v=1;$v<=$nodeNumInNetFile_2;$v++){
					if($nodeNameInPajFile[$toInPajFile[$j]] eq $nodeNameInNetFile_2[$v]){
						# PajファイルでIDが$toInPajFile[$j]の人は，Netファイル(subCommunity_2)ではIDが$v
						# 条件に一致したエッジのノード重み(次数中心性)を順次加算していく
						$sum_andmanToSubCommunity_2[$fromInPajFile[$j]] += $allCentralityInSubCommunity_2[$v];
					}
				}
			}
		}

		# subCommunity_1 or subCommunity_2 の参加者 ⇒ andman　の場合(入次数)
		elsif($partition[$toInPajFile[$j]] == $andman){
			# subCommunity_1 ⇒ andman のパターン
			if($partition[$fromInPajFile[$j]] == $subCommunity_1){
				for($x=1;$x<=$nodeNumInNetFile_1;$x++){
					if($nodeNameInPajFile[$fromInPajFile[$j]] eq $nodeNameInNetFile_1[$x]){
						# PajファイルでIDが$fromInPajFile[$j]の人は，Netファイル(subCommunity_1)ではIDが$x
						# 条件に一致したエッジのノード重み(次数中心性)を順次加算していく
						$sum_subCommunity_1ToAndman[$toInPajFile[$j]] += $allCentralityInSubCommunity_1[$x];
					}
				}
			}

			# subCommunity_2 ⇒ andman のパターン
			elsif($partition[$fromInPajFile[$j]] == $subCommunity_2){
				for($y=1;$y<=$nodeNumInNetFile_2;$y++){
					if($nodeNameInPajFile[$fromInPajFile[$j]] eq $nodeNameInNetFile_2[$y]){
						# PajファイルでIDが$fromInPajFile[$j]の人は，Netファイル(subCommunity_2)ではIDが$y
						# 条件に一致したエッジのノード重み(次数中心性)を順次加算していく
						$sum_subCommunity_2ToAndman[$toInPajFile[$j]] += $allCentralityInSubCommunity_2[$y];
					}
				}
			}
		}
	}


################################################### 指標値を算出 #############################################


	# 仲介の流れで切り分ける
	# metrics4SubCommunity1To2(subCommunity_1⇒andman⇒subCommunity_2)とmetrics4SubCommunity2To1(subCommunity_2⇒andman⇒subCommunity_1)の2パターン

	for($s=1;$s<=$nodeNumInPajFile;$s++){
		# andmanであるかどうかをまず判断する
		if($partition[$s] == $andman){
			# andmanαがsubCommunity_1から向けられている入次数とsubCommunity_2へに対して向けている出次数をもとに計算する
			# 両方の値があった場合にのみ，両者をかけ合わせることでsubCommunity_1⇒andmanα⇒subCommunity_2の流れを考える
			# 自身を除くそれぞれのコミュニティ参加者の総数（$nodeNumInNetFile_1 - 1 または $nodeNumInNetFile_2 - 1)で正規化
			# 要するに理論上の最大値(自身を除く他の参加者全てとつながったときが最大値)で正規化するということ
			if(defined($sum_subCommunity_1ToAndman[$s]) && defined($sum_andmanToSubCommunity_2[$s])){
				$f1 = $sum_subCommunity_1ToAndman[$s];
				$f2 = $sum_andmanToSubCommunity_2[$s];
				$subCommunity_1To2 = (2 * $f1 * $f2) / ($f1 + $f2);
				$metrics4SubCommunity_1To2[$s] = "$subCommunity_1To2\n";
			}
			# andmanαがsubCommunity_2から向けられている入次数とsubCommunity_1へに対して向けている出次数をもとに計算する
			# 両方の値があった場合にのみ，両者をかけ合わせることでsubCommunity_2⇒andmanα⇒subCommunity_1の流れを考える
			if(defined($sum_subCommunity_2ToAndman[$s]) && defined($sum_andmanToSubCommunity_1[$s])){
				$f1 = $sum_subCommunity_2ToAndman[$s];
				$f2 = $sum_andmanToSubCommunity_1[$s];
				$subCommunity_2To1 = (2 * $f1 * $f2) / ($f1 + $f2);
				$metrics4SubCommunity_2To1[$s] = "$subCommunity_2To1\n";
			}

			# subCommunity_1⇒andmanの後、subCommunity_2へのやりとりがなかった　または 入次数・出次数ともに0のとき
			if(!(defined($sum_subCommunity_1ToAndman[$s]) && defined($sum_andmanToSubCommunity_2[$s]))){
				$metrics4SubCommunity_1To2[$s] =  "0\n";
			}
			# subCommunity_2⇒andmanの後、subCommunity_1へのやりとりがなかった　または 入次数・出次数ともに0のとき
			if(!(defined($sum_subCommunity_2ToAndman[$s]) && defined($sum_andmanToSubCommunity_1[$s]))){
				$metrics4SubCommunity_2To1[$s] =  "0\n";
			}
		}
		# andman以外の人　※とりあえずこうしておくことで，アンドマンには何らかの値が入ることになる
		else{
			$metrics4SubCommunity_1To2[$s] =  "0\n";
			$metrics4SubCommunity_2To1[$s] =  "0\n";
		}
	}


############## ファイルの出力 ###########################################################################


	# ファイル名の取得　(読み込んだファイルが○○_年月.pajであればファイルの"年月"の部分だけ取得)
	# Pajファイルの名前の付け方を変更した場合はここも変更しないとOutputされない
	$ARGV[0] =~ s/.*(\d{6}).*/$1/;

	$metrics4SubCommunity_1To2[0] = "*Vertices $nodeNumInPajFile\n";
	$metrics4SubCommunity_2To1[0] = "*Vertices $nodeNumInPajFile\n";

	# subCommunity_1⇒andman⇒subCommunity_2の仲介の流れで1つのファイルを作成
	# 1行目に*Vertices ノード数が書かれているけど，それより下は指標値のみが書かれている
	open OUT,">nodeWgtCB_1To2_".$1.".vec";
	print OUT @metrics4SubCommunity_1To2;
	close OUT;

	# subCommunity_2⇒andman⇒subCommunity_1の仲介の流れで1つのファイルを作成
	# 1行目に*Vertices ノード数が書かれているけど，それより下は指標値のみが書かれている
	open OUT,">nodeWgtCB_2To1_".$1.".vec";
	print OUT @metrics4SubCommunity_2To1;
	close OUT;


