<?php
/**
 * 
 * @author keiji
 * @package aowp.aspect.pointcut
 */
/**
 * ポイントカット記述子の組み合わせを実現するクラスです。
 * {@link Pointcut::orAnd}、{@link Pointcut::opOr}を呼び出した時に、
 * {@link Pointcut}クラスの中で内部的に、このクラスのインスタンスが生成されており、
 * 通常、プログラマがこのインスタンスを直接使う事は少ないかと思います。
 * 
 * @author keiji
 * @package aowp.aspect.pointcut
 */
class AOWP_PointcutComposition extends AOWP_Pointcut {
	
	const AND_SIGN = '&';
	const OR_SIGN = '|';
	
	private $_leftPC;
	private $_rightPC;
	private $_sign;
	
	public function __construct(AOWP_Pointcut $leftPC, AOWP_Pointcut $rightnPC, $sign) {
		$this->_leftPC = $leftPC;
		$this->_rightPC = $rightnPC;
		$this->_sign = $sign;
	}
	
	public function setAdvice(AOWP_Advice $advice) {
		$this->_leftPC->setAdvice($advice);
		$this->_rightPC->setAdvice($advice);
	}

	/**
	 * ド・モルガンの定理に基づいて、
	 * 左辺と右辺のそれぞれのポイントカットにNotを適用します。
	 * @code
	 * 
	 * @see aspect/pointcut/AOWP_Pointcut#opNot()
	 */
	public function opNot() {
		$this->_sign = $this->_sign === AOWP_PointcutComposition::AND_SIGN ?
			$this->_sign = AOWP_PointcutComposition::OR_SIGN :
			$this->_sign = AOWP_PointcutComposition::AND_SIGN;
		$this->_leftPC->opNot();
		$this->_rightPC->opNot();
	}
	
	/**
	 * @code
	 * 
	 * @see aspect/pointcut/AOWP_Pointcut#_isJoinPointShadow()
	 */
	protected function _isJoinPointShadow(AOWP_JoinPoint $joinPoint) {
		if ($this->_sign === AOWP_PointcutComposition::AND_SIGN) {
			return $this->_leftPC->isJoinPointShadow($joinPoint) &&
				$this->_rightPC->isJoinPointShadow($joinPoint);
		}
		else if ($this->_sign === AOWP_PointcutComposition::OR_SIGN) {
			return $this->_leftPC->isJoinPointShadow($joinPoint) ||
				$this->_rightPC->isJoinPointShadow($joinPoint);
		}
	}
	public function isJoinPointShadow(AOWP_JoinPoint $joinPoint) {
		return $this->_isJoinPointShadow($joinPoint);
	}

	public function isHavePointcut(AOWP_Pointcut $pointcut) {
		return $this->_leftPC->isHavePointcut($pointcut) || $this->_rightPC->isHavePointcut($pointcut);
	}
	
	
	/**
	 * @code
	 * 
	 * @see aspect/pointcut/AOWP_Pointcut#_runtimeMatch()
	 */
	protected function _runtimeMatch(AOWP_JoinPoint $joinPoint) {
		if ($this->_sign === AOWP_PointcutComposition::AND_SIGN) {
			return $this->_leftPC->runtimeMatch($joinPoint) &&
				$this->_rightPC->runtimeMatch($joinPoint);
		}
		else if ($this->_sign === AOWP_PointcutComposition::OR_SIGN) {
			return $this->_leftPC->runtimeMatch($joinPoint) ||
				$this->_rightPC->runtimeMatch($joinPoint);
		}
	}
	public function runtimeMatch(AOWP_JoinPoint $joinPoint) {
		return $this->_runtimeMatch($joinPoint);
	}
	
}
?>