<?php
/**
 * Enter description here...
 *
 * @package aowp.aspect.weaver
 */

/**
 * Enter description here...
 *
 * @package aowp.aspect.weaver
 */
class AOWP_Weaver {
	
	private $_RemainingAspectTasks = array();
	private $_allChachedASTFileNameArray = array();
	private $_RemainingASTTasks = array();
	private $_nowWeavingAspect = null;
	
	const SERIARIZE_FILENAME = 'AOWP_Weaver';
	
	public function __construct() {
		AOWP_AspectManager::clearCache();
		AOWP_AspectManager::loadUserDefineAspect();
		$this->_allChachedASTFileNameArray = AOWP_ASTManager::getAllCachedASTFileName();
		AOWP_Logger::logging('[Weaver] ' . count($this->_allChachedASTFileNameArray) . ' cached AST');
//		AOWP_AspectManager::refleshWeaverGenerateAspect();
//		AOWP_GeneratedAspectNameManager::reflesh();
//		foreach (AOWP_AspectManager::getAllAspects() as $aspect) {
//			$aspect->generateAspect();
//		}
		$this->_RemainingAspectTasks = AOWP_AspectManager::getAllAspects();
		AOWP_Logger::logging('[Weaver] ' . count($this->_RemainingAspectTasks) . ' aspects');
	}
	
	public function getRemainingAspectTaskNum() {
		return count($this->_RemainingAspectTasks);
	}
	public function getRemainingASTTaskNum() {
		return count($this->_RemainingASTTasks);
	}
	public function getAllASTNum() {
		return count($this->_allChachedASTFileNameArray);
	}
	
	public function weaveNext() {
		if (count($this->_RemainingASTTasks) === 0) {
			$this->_RemainingASTTasks = $this->_allChachedASTFileNameArray;
			$this->_nowWeavingAspect = array_shift($this->_RemainingAspectTasks);
			AOWP_Logger::logging('[Weave] Now ' . get_class($this->_nowWeavingAspect) . ' is woven');
		}
		$aspect = $this->_nowWeavingAspect;
		// Initialize per-application aspect instance.
		if ($aspect instanceof AOWP_PerApplicationAspect) {
			AOWP_AspectInstanceManager::releaseInstance($aspect);
		}
		$cachedASTFileName = array_shift($this->_RemainingASTTasks);
		AOWP_Logger::setStartTime(2);
		$parseResult = &AOWP_ASTManager::getWovenASTFile($cachedASTFileName);
		if ($parseResult !== null && isset($parseResult->root)) {
			$this->weaveAspectToOnePHPFile($parseResult->root, $aspect, AOWP_ASTManager::getSourcePath($cachedASTFileName));
			AOWP_ASTManager::saveWeaveCache($cachedASTFileName, $parseResult);
			AOWP_Logger::logging('[Weave] Weave ' . get_class($aspect), 2);
			AOWP_Logger::logging('[Weave] Weave ' . $cachedASTFileName, 2);
		}
		else {
			AOWP_Logger::logging('[Weave] Failed to weave ' . $cachedASTFileName, 2);
			exit();
		}
		$parseResult->releaseInstance();
		$parseResult = null;
		return array(get_class($aspect), $cachedASTFileName);
	}
	
	public function weaveAllAspect(){
		AOWP_ASTManager::refleshWovenAST();
		AOWP_Logger::logging('[Weave] Reflesh cached woven AST');
		while (!$this->isEndWeaving()) {
			$this->weaveNext();
		}
		
		// For counting join point shadows.
		JoinPointShadowCounter::saveCount();
	}
	
	public function isEndWeaving() {
		return ($this->_RemainingAspectTasks === array()) && ($this->_RemainingASTTasks === array());
	}
	
	public function seriarize(){
		$serializeFilePath = $this->getSerializeFilePath();
		$seriarizeContent = serialize($this);
		AOWP_PHPFileManager::saveFile($serializeFilePath, $seriarizeContent);
	}
	
	public function getSerializeFilePath(){
		return AOWP_ConfigurationManager::getRuntimeDataFolder() . DIRECTORY_SEPARATOR . AOWP_Weaver::SERIARIZE_FILENAME;
	}

	/**
	 * 
	 * @param $element
	 * @param $aspect
	 * @param string $filePath
	 * @return void
	 */
	public static function weaveAspectToOnePHPFile(AOWP_PHPElement &$element, AOWP_Aspect $aspect, $filePath) {
//		AOWP_Logger::logging('Weaving> ' . get_class($element));
		foreach ($element->getChildren() as $childElement) {
			AOWP_Weaver::weaveAspectToOnePHPFile($childElement, $aspect, $filePath);
		}
		$joinPoint = AOWP_JoinPointCreator::createJoinPoint($element, $filePath);
		if ($joinPoint !== null) {
			foreach ($aspect->getAllAdviceArray() as $advice) {
				if ($advice->isJoinPointShadow($joinPoint)) {
					
					// For counting join point shadows.
					require_once dirname(__FILE__) . '/../../../experiment/JoinPointShadowCounter.class.php';
					JoinPointShadowCounter::count($aspect);
					file_put_contents(dirname(__FILE__) . '/exit_jp_log.txt', get_class($aspect) . ': ' . get_class($joinPoint) . ': ' . $filePath . "\n", FILE_APPEND); 
					
					AOWP_WeaveCommand::weaveAdvice($advice, $joinPoint);
				}
			}
		}
	}
}
?>