<?php
/**
 * 
 * @author keiji
 * @package aowp.aspect.weaver.command
 */
/**
 * 
 * @author keiji
 * @package aowp.aspect.weaver.command
 */
class AOWP_FunctionExecutionJoinPointWeaveCommand implements AOWP_IWeaveCommand {

	public function  weaveBeforeAdvice(AOWP_Advice &$advice, AOWP_JoinPoint &$joinPoint) {
		$functionElement = $joinPoint->getAST();
		
		// 元の処理をラッピングする関数の、作成。
		$wrappingFunctionElement = new AOWP_PHPFunctionElement(AOWP_WeavingASTHelper::getRandomName('function'));
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$wrappingFunctionElement->addParameter($functionElement->getParameterName($i));
		}
		foreach ($functionElement->innerStatements as $innerStatement) {
			$wrappingFunctionElement->setElement($innerStatement);
		}

		// ラッピング関数の重複定義を防ぐためのIf文を追加。
		$ifFunctionDeclarationElement = AOWP_WeavingASTHelper::createIfForFunctionDeclaration($wrappingFunctionElement);
		
		// 織り込み対象の関数を空にし、ラッピング関数の定義を追加。
		$functionElement->innerStatements = array();
		$functionElement->setElement($ifFunctionDeclarationElement);
		
		// 織り込みの実装。
		// includeの為のautoload関数の設定。
		$functionElement->setElement(AOWP_WeavingASTHelper::createIncludeStatemenetElement($joinPoint->getFileFullPath()));
		// アスペクトのインスタンス化。
		$aspectInstantiationElement = AOWP_WeavingASTHelper::createAspectInstantiationAST($advice->getClassNameOfAspect());
		$functionElement->setElement(new AOWP_PHPStatementElement($aspectInstantiationElement));
		// ジョインポイントのインスタンス化。
		$joinPointInstantiationElement = AOWP_WeavingASTHelper::createJoinPointInstantiationAST($joinPoint);
		$functionElement->setElement(new AOWP_PHPStatementElement($joinPointInstantiationElement));
		// 関数の引き数を、ジョインポイントに設定。
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$joinPointArgumentSetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'addArgument');
			$joinPointArgumentSetElement->addArgument(AOWP_PHPArgumentElement::createVariableArgument($functionElement->getParameterName($i)));
			$functionElement->setElement(new AOWP_PHPStatementElement($joinPointArgumentSetElement));
		}
		// アドバイスを実行するIf文。
		$adviceExecutionElement = AOWP_WeavingASTHelper::createAdviceExecutionAST($aspectInstantiationElement->getLeftVarialeName(),
			$advice->getIndex(), $joinPointInstantiationElement->getLeftVarialeName());
		$functionElement->setElement($adviceExecutionElement);
		// return文。
		$originalFunctionCallElement = new AOWP_PHPFunctionCallElement($wrappingFunctionElement->getFunctionName());
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$joinPointGetParameterElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'getArgument');
			$joinPointGetParameterElement->addArgument(AOWP_PHPArgumentElement::createStringArgument($i));
			$originalFunctionCallElement->addArgument(new AOWP_PHPArgumentElement(null, $joinPointGetParameterElement));
		}
		$returnElement = new AOWP_PHPReturnStatementElement(null, $originalFunctionCallElement);
		$functionElement->setElement($returnElement);
	}

	public function  weaveAfterAdvice(AOWP_Advice &$advice, AOWP_JoinPoint &$joinPoint) {
		$functionElement = $joinPoint->getAST();
		
		// 元の処理をラッピングする関数の、作成。
		$wrappingFunctionElement = new AOWP_PHPFunctionElement(AOWP_WeavingASTHelper::getRandomName('function'));
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$wrappingFunctionElement->addParameter($functionElement->getParameterName($i));
		}
		foreach ($functionElement->innerStatements as $innerStatement) {
			$wrappingFunctionElement->setElement($innerStatement);
		}

		// ラッピング関数の重複定義を防ぐためのIf文を追加。
		$ifFunctionDeclarationElement = AOWP_WeavingASTHelper::createIfForFunctionDeclaration($wrappingFunctionElement);

		// 織り込み対象の関数を空にし、ラッピング関数の定義を追加。
		$functionElement->innerStatements = array();
		$functionElement->setElement($ifFunctionDeclarationElement);
		
		// 織り込みの実装。
		// includeの為のautoload関数の設定。
		$functionElement->setElement(AOWP_WeavingASTHelper::createIncludeStatemenetElement($joinPoint->getFileFullPath()));
		// アスペクトのインスタンス化。
		$aspectInstantiationElement = AOWP_WeavingASTHelper::createAspectInstantiationAST($advice->getClassNameOfAspect());
		$functionElement->setElement(new AOWP_PHPStatementElement($aspectInstantiationElement));
		// ジョインポイントのインスタンス化。
		$joinPointInstantiationElement = AOWP_WeavingASTHelper::createJoinPointInstantiationAST($joinPoint);
		$functionElement->setElement(new AOWP_PHPStatementElement($joinPointInstantiationElement));
		// 元の関数を実行し、ジョインポイントに設定。
		$joinPointReturnSetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'setReturnValue');
		$originalFunctionCallElement = new AOWP_PHPFunctionCallElement($wrappingFunctionElement->getFunctionName());
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$originalFunctionCallElement->addArgument(AOWP_PHPArgumentElement::createVariableArgument($functionElement->getParameterName($i)));
		}
		$joinPointReturnSetElement->addArgument(new AOWP_PHPArgumentElement(null, $originalFunctionCallElement));
		$functionElement->setElement(new AOWP_PHPStatementElement($joinPointReturnSetElement));
		// 関数の引き数を、ジョインポイントに設定。
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$joinPointArgumentSetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'addArgument');
			$joinPointArgumentSetElement->addArgument(AOWP_PHPArgumentElement::createVariableArgument($functionElement->getParameterName($i)));
			$functionElement->setElement(new AOWP_PHPStatementElement($joinPointArgumentSetElement));
		}
		// アドバイスを実行するIf文。
		$adviceExecutionElement = AOWP_WeavingASTHelper::createAdviceExecutionAST($aspectInstantiationElement->getLeftVarialeName(),
			$advice->getIndex(), $joinPointInstantiationElement->getLeftVarialeName());
		$functionElement->setElement($adviceExecutionElement);
		// return文。
		$joinPointReturnGetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'getReturnValue');
		$returnElement = new AOWP_PHPReturnStatementElement(null, $joinPointReturnGetElement);
		$functionElement->setElement($returnElement);
	}

	public function  weaveAroundAdvice(AOWP_Advice &$advice, AOWP_JoinPoint &$joinPoint) {
		$functionElement = $joinPoint->getAST();
		
		// 元の処理をラッピングする関数の、作成。
		$wrappingFunctionElement = new AOWP_PHPFunctionElement(AOWP_WeavingASTHelper::getRandomName('function'));
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$wrappingFunctionElement->addParameter($functionElement->getParameterName($i));
		}
		foreach ($functionElement->innerStatements as $innerStatement) {
			$wrappingFunctionElement->setElement($innerStatement);
		}

		// ラッピング関数の重複定義を防ぐためのIf文を追加。
		$ifFunctionDeclarationElement = AOWP_WeavingASTHelper::createIfForFunctionDeclaration($wrappingFunctionElement);

		// 織り込み対象の関数を空にし、ラッピング関数の定義を追加。
		$functionElement->innerStatements = array();
		$functionElement->setElement($ifFunctionDeclarationElement);
		
		// 織り込みの実装。
		// includeの為のautoload関数の設定。
		$functionElement->setElement(AOWP_WeavingASTHelper::createIncludeStatemenetElement($joinPoint->getFileFullPath()));
		// アスペクトのインスタンス化。
		$aspectInstantiationElement = AOWP_WeavingASTHelper::createAspectInstantiationAST($advice->getClassNameOfAspect());
		$functionElement->setElement(new AOWP_PHPStatementElement($aspectInstantiationElement));
		// ジョインポイントのインスタンス化。
		$joinPointInstantiationElement = AOWP_WeavingASTHelper::createJoinPointInstantiationAST($joinPoint);
		$functionElement->setElement(new AOWP_PHPStatementElement($joinPointInstantiationElement));
		// proceedの関数名を、ジョインポイントに設定。
		$joinPointProceedSetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'setProceedFunctionName');
		$joinPointProceedSetElement->addArgument(AOWP_PHPArgumentElement::createStringArgument($wrappingFunctionElement->getFunctionName()));
		$functionElement->setElement(new AOWP_PHPStatementElement($joinPointProceedSetElement));
		// 関数の引き数を、ジョインポイントに設定。
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$joinPointArgumentSetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'addArgument');
			$joinPointArgumentSetElement->addArgument(AOWP_PHPArgumentElement::createVariableArgument($functionElement->getParameterName($i)));
			$functionElement->setElement(new AOWP_PHPStatementElement($joinPointArgumentSetElement));
		}
		// アドバイスを実行するIf文。
		$originalFunctionCallElement = new AOWP_PHPFunctionCallElement($wrappingFunctionElement->getFunctionName());
		for ($i = 0; $i < $functionElement->getParameterCount(); $i++) {
			$originalFunctionCallElement->addArgument(AOWP_PHPArgumentElement::createVariableArgument($functionElement->getParameterName($i)));
		}
		$adviceExecutionElement = AOWP_WeavingASTHelper::createAdviceExecutionASTForAround($aspectInstantiationElement->getLeftVarialeName(),
			$advice->getIndex(), $joinPointInstantiationElement->getLeftVarialeName(), $originalFunctionCallElement);
		$functionElement->setElement($adviceExecutionElement);
	}
}
?>