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

	public function  weaveBeforeAdvice(AOWP_Advice &$advice, AOWP_JoinPoint &$joinPoint) {
		$rootElement = $joinPoint->getAST();
		
		// 織り込みを行うPHP文の、配列を作成。
		$weavingElementArray = array();
		// includeの為のautoload関数の設定。
		$weavingElementArray[] = AOWP_WeavingASTHelper::createIncludeStatemenetElement($joinPoint->getFileFullPath());
		// アスペクトのインスタンス化。
		$aspectInstantiationElement = AOWP_WeavingASTHelper::createAspectInstantiationAST($advice->getClassNameOfAspect());
		$weavingElementArray[] = new AOWP_PHPStatementElement($aspectInstantiationElement);
		// ジョインポイントのインスタンス化。
		$joinPointInstantiationElement = AOWP_WeavingASTHelper::createJoinPointInstantiationAST($joinPoint);
		$weavingElementArray[] = new AOWP_PHPStatementElement($joinPointInstantiationElement);
		// アドバイスを実行するIf文。
		$adviceExecutionElement = AOWP_WeavingASTHelper::createAdviceExecutionAST($aspectInstantiationElement->getLeftVarialeName(),
			$advice->getIndex(), $joinPointInstantiationElement->getLeftVarialeName());
		$weavingElementArray[] = $adviceExecutionElement;

		// 対象のスクリプトファイルに、織り込みを行うASTを追加。
		$rootElement->insertElement(new AOWP_PHPTagElement(null, $weavingElementArray), 0);
	}

	public function  weaveAfterAdvice(AOWP_Advice &$advice, AOWP_JoinPoint &$joinPoint) {
		$rootElement = $joinPoint->getAST();
		$wovenElementArray = array();
		
		// 織り込みを行うPHP文を、追加。
		// includeの為のautoload関数の設定。
		$wovenElementArray[] = AOWP_WeavingASTHelper::createIncludeStatemenetElement($joinPoint->getFileFullPath());
		// アスペクトのインスタンス化。
		$aspectInstantiationElement = AOWP_WeavingASTHelper::createAspectInstantiationAST($advice->getClassNameOfAspect());
		$wovenElementArray[] = new AOWP_PHPStatementElement($aspectInstantiationElement);
		// ジョインポイントのインスタンス化。
		$joinPointInstantiationElement = AOWP_WeavingASTHelper::createJoinPointInstantiationAST($joinPoint);
		$wovenElementArray[] = new AOWP_PHPStatementElement($joinPointInstantiationElement);
		// アドバイスを実行するIf文。
		$adviceExecutionElement = AOWP_WeavingASTHelper::createAdviceExecutionAST($aspectInstantiationElement->getLeftVarialeName(),
			$advice->getIndex(), $joinPointInstantiationElement->getLeftVarialeName());
		$wovenElementArray[] = $adviceExecutionElement;
		
		// 対象のスクリプトファイルに、織り込みを行うASTを追加。
		$rootElement->setElement(new AOWP_PHPTagElement(null, $wovenElementArray));
	}

	public function  weaveAroundAdvice(AOWP_Advice &$advice, AOWP_JoinPoint &$joinPoint) {
		$rootElement = $joinPoint->getAST();
		
		// 元の処理をラッピングする関数の、作成。
		$wrappingFunctionElement = new AOWP_PHPFunctionElement(AOWP_WeavingASTHelper::getRandomName('function'));
		foreach ($rootElement->statements as $statement) {
			if ($statement !== null) {
				if ($statement instanceof AOWP_PHPInnerHTMLStatementElement) {
					$echoElement = new AOWP_PHPEchoStatementElement(null, new AOWP_Token("'" . str_replace("'", "\'", $statement->value->getValue()) . "'"));
					$wrappingFunctionElement->setElement($echoElement);
				}
				else {
					$wrappingFunctionElement->setElement($statement);
				}
			}
		}

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

		// 織り込み対象の関数を空にし、ラッピング関数の定義を追加。
		$rootElement->statements = array();
		$rootElement->setElement(new AOWP_PHPTagElement(null, array($ifFunctionDeclarationElement)));
		
		// 織り込みの実装。
		$wovenElementArray = array();
		// includeの為のautoload関数の設定。
		$wovenElementArray[] = AOWP_WeavingASTHelper::createIncludeStatemenetElement($joinPoint->getFileFullPath());
		// アスペクトのインスタンス化。
		$aspectInstantiationElement = AOWP_WeavingASTHelper::createAspectInstantiationAST($advice->getClassNameOfAspect());
		$wovenElementArray[] = new AOWP_PHPStatementElement($aspectInstantiationElement);
		// ジョインポイントのインスタンス化。
		$joinPointInstantiationElement = AOWP_WeavingASTHelper::createJoinPointInstantiationAST($joinPoint);
		$wovenElementArray[] = new AOWP_PHPStatementElement($joinPointInstantiationElement);
		// proceedの関数名を、ジョインポイントに設定。
		$joinPointProceedSetElement = new AOWP_PHPSimpleMethodCallElement($joinPointInstantiationElement->getLeftVarialeName(), 'setProceedFunctionName');
		$joinPointProceedSetElement->addArgument(AOWP_PHPArgumentElement::createStringArgument($wrappingFunctionElement->getFunctionName()));
		$wovenElementArray[] = new AOWP_PHPStatementElement($joinPointProceedSetElement);
		// アドバイスを実行するIf文。
		$wrappingFunctionCallElement = new AOWP_PHPFunctionCallElement($wrappingFunctionElement->getFunctionName());
		$adviceExecutionElement = AOWP_WeavingASTHelper::createAdviceExecutionASTForAround($aspectInstantiationElement->getLeftVarialeName(),
			$advice->getIndex(), $joinPointInstantiationElement->getLeftVarialeName(), $wrappingFunctionCallElement);
		$wovenElementArray[] = $adviceExecutionElement;
		
		// 元のコードに追加。
		$rootElement->setElement(new AOWP_PHPTagElement(null, $wovenElementArray));
	}
}
?>