<?php
/**
 * @package Legacy
 * @version $Id: Legacy_Controller.class.php,v 1.1.2.31.2.3 2007/03/14 09:58:48 minahito Exp $
 */

if (!defined('XOOPS_ROOT_PATH')) exit();

define("LEGACY_CONTROLLER_STATE_PUBLIC", 1);
define("LEGACY_CONTROLLER_STATE_ADMIN", 2);

define("LEGACY_XOOPS_MODULE_MANIFESTO_FILENAME", "xoops_version.php");

require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_BlockProcedure.class.php";
require_once XOOPS_ROOT_PATH . "/modules/legacy/class/Legacy_Utils.class.php";
require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_Identity.class.php";
require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_RoleManager.class.php";

require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_CacheInformation.class.php";
require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_PublicControllerStrategy.class.php";
require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_TextFilter.class.php";
require_once XOOPS_ROOT_PATH . "/modules/legacy/class/Legacy_Debugger.class.php";

/**
 * This class is a virtual controller that has the compatibility with XOOPS 2.0.x.
 * 
 * [NOTICE]
 * XOOPS 2.0.x can switch to public mode and control panel mode. This controller
 * emulates its process with using STATE. But, we may lose flexible setup by this
 * implement. Now, we are investigating the influence.
 *
 * [TODO]
 * XCube_Controller keeps a process that set up instances of some legacy classes,
 * yet. We should move its process to this controller.
 */
class Legacy_Controller extends XCube_Controller
{
	var $_mAdminModeFlag = false;
	var $_mStrategy = null;
	
	var $mDialogMode = false;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mCheckLogin = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mLogout = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mCreateLanguageManager = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mSetBlockCachePolicy = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mSetModuleCachePolicy = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mGetLanguageName = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mSetupDebugger = null;
	
	/**
	 * @public
	 * @var XCube_Delegate
	 * [Secret Agreement] In execute_redirect(), notice the redirection which directs toward user.php.
	 * @remark Only the special module should access this member property.
	 */
	var $_mNotifyRedirectToUser = null;
	
	/**
	 * @var XoopsLogger
	 */
	var $mLogger = null;
	
	function Legacy_Controller()
	{
		parent::XCube_Controller();
		
		//
		// Setup member properties as member delegates.
		//
		$this->mSetupUser->register("Legacy_Controller.SetupUser");
		
		$this->mCheckLogin =& new XCube_Delegate();
		$this->mCheckLogin->register("Site.CheckLogin");
		
		$this->mLogout =& new XCube_Delegate();
		$this->mLogout->register("Site.Logout");
		
		$this->mCreateLanguageManager =& new XCube_Delegate();
		$this->mCreateLanguageManager->register("Legacy_Controller.CreateLanguageManager");
		
		$this->mGetLanguageName =& new XCube_Delegate();
		$this->mGetLanguageName->register("Legacy_Controller.GetLanguageName");
		
		$this->mSetBlockCachePolicy =& new XCube_Delegate();
		$this->mSetModuleCachePolicy =& new XCube_Delegate();
		
		$this->mSetupDebugger =& new XCube_Delegate();
		$this->mSetupDebugger->add('Legacy_DebuggerManager::createInstance');

	    $this->mSetupTextFilter->add('Legacy_TextFilter::getInstance',XCUBE_DELEGATE_PRIORITY_FINAL-1);

		$this->_mNotifyRedirectToUser =& new XCube_Delegate();
		
		set_magic_quotes_runtime(0);	// ^^;
	}
	
	function prepare(&$root)
	{
		parent::prepare($root);
		
		//
		// Decide status. [TEST]
		//
		$this->_processHostAbstractLayer();

		$urlInfo = $this->_parseUrl();
		
		$adminStateFlag = false;
		if (count($urlInfo) >= 3) {
			if (strtolower($urlInfo[0]) == "modules" && strtolower($urlInfo[2]) == "admin"){
				$adminStateFlag = true;
			}
			elseif ($urlInfo[0] == "modules" && $urlInfo[1] == "legacy" && $urlInfo[2] == "include") {
				$adminStateFlag = true;
			}
			elseif ($urlInfo[0] == "modules" && $urlInfo[1] == "system" && substr($urlInfo[2], 0, 9) == "admin.php") {
				$adminStateFlag = true;
			}
		}
		elseif (substr($urlInfo[0], 0, 9) == "admin.php") {
			$adminStateFlag = true;
		}

		if ($adminStateFlag) {
			require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_AdminControllerStrategy.class.php";
			$this->_mStrategy =& new Legacy_AdminControllerStrategy($this);
		}
		else {
			$this->_mStrategy =& new Legacy_PublicControllerStrategy($this);
		}
	}
	
	/**
	 * @access public
	 */
	function executeCommon()
	{
		//
		// Setup Filter chain and execute the process of these filters.
		//
		$this->_setupFilterChain();
		$this->_processFilter();

		// ^^;
		$this->_setupErrorHandler();

		$this->_setupEnvironment();
		
		$this->_setupLogger();

		$this->_setupDB();

        $this->_setupLanguage();

        $this->_setupTextFilter();

		$this->_setupConfig();
		
		$this->_setupDebugger();

		$this->_processPreBlockFilter();	// What's !?

		$this->_setupSession();

		$this->_setupUser();
		
		$this->setupModuleContext();
		
		$this->_processModule();

		$this->_processPostFilter();
	}
	
	/**
	 * Subset of executeCommon() Method
	 * It'll be used when process starts with $xoopsOption['nocommon'] and
	 * This process requires connecting XOOPS Database or LEGACY constant values
	 * But it won't do any other initial settings
	 *  (eg. Session start, Permission handling)
	 *
	 * @access public
     * @param bool $connectdb set false if you don't want to connetcting XOOPS Database
	 *
	 */
    function executeCommonSubset($connectdb = true) {
        $this->_setupErrorHandler();
     	$this->_setupEnvironment();
     	if ($connectdb) {
     	    $this->_setupLogger();
     	    $this->_setupDB();
     	}
    }

	function _setupLogger()
	{
		require_once XOOPS_ROOT_PATH . '/class/logger.php';
		$this->mLogger =& XoopsLogger::instance();
		$this->mLogger->startTime();

		$GLOBALS['xoopsLogger'] =& $this->mLogger;
	}
	
	function &getLogger()
	{
		return $this->mLogger;
	}

	function _setupEnvironment()
	{
		parent::_setupEnvironment();
		require_once XOOPS_ROOT_PATH.'/include/version.php';
		
		require_once XOOPS_ROOT_PATH.'/settings/definition.inc.php';
		define("XOOPS_LEGACY_PATH",XOOPS_MODULE_PATH."/".XOOPS_LEGACY_PROC_NAME);

		require_once XOOPS_ROOT_PATH.'/include/functions.php';

		require_once XOOPS_ROOT_PATH.'/kernel/object.php';
		require_once XOOPS_ROOT_PATH.'/class/criteria.php';
		require_once XOOPS_ROOT_PATH.'/class/token.php';
		require_once XOOPS_ROOT_PATH.'/class/module.textsanitizer.php';

		require_once XOOPS_LEGACY_PATH.'/kernel/object.php';				// ToDo (here?)
		require_once XOOPS_LEGACY_PATH.'/kernel/handler.php';				// ToDo
		require_once XOOPS_ROOT_PATH.'/core/XCube_Utils.class.php';	// ToDo

		require_once XOOPS_ROOT_PATH.'/class/xoopssecurity.php';
		$GLOBALS['xoopsSecurity'] =& new XoopsSecurity();
	}

	/**
	 * [NOTICE]
	 * We set up only filters that are decided to register by us. This is not
	 * flexible. This is not the style fixed.
	 *
	 * [MEMO]
	 * For test, you can use automatic loading plug-in with writing a setting
	 * in site_custom.ini.php.
	 * 
	 * site_custom.ini.php:
	 *  [Legacy]
	 *  AutoPreload = 1
	 *
	 */
	function _setupFilterChain()
	{
		$this->_mStrategy->_setupFilterChain();
	}

	function _setupBlock()
	{
		$this->_mStrategy->setupBlock();
	}

	/**
	 * Process of Block. Fetch objects from $this->mBlockChain, render the
	 * result of the object with html data, and set those result to member
	 * property.
	 * 
	 * In this member function, the cache mechanism has to be important. If the
	 * object has its cache, this function loads the cache data instead of
	 * calling the business logic of the block.
	 *
	 * @access protected
	 */
	function _processBlock()
	{
		$i=0;
		
		//
		// Create render-target for blocks. We use reset() to re-cycle this
		// object in the foreach loop.
		//
		$context =& $this->mRoot->mContext;

		foreach ($this->_mBlockChain as $blockProcedure) {
			//
			// This is a flag indicating whether the controller needs to call
			// the logic of the block.
			//
			$usedCacheFlag = false;
			
			$cacheInfo = null;
			
			if ($this->isEnableCacheFeature() && $blockProcedure->isEnableCache()) {
				//
				// Reset the block cache information structure, and initialize.
				//
				$cacheInfo =& $blockProcedure->createCacheInfo();
				
				$this->mSetBlockCachePolicy->call(new XCube_Ref($cacheInfo));
				$filepath = $cacheInfo->getCacheFilePath();
				
				//
				// If caching is enable and the cache file exists, load and use.
				//
				if ($cacheInfo->isEnableCache() && $this->existActiveCacheFile($filepath, $blockProcedure->getCacheTime())) {
					$content = $this->loadCache($filepath);
					if ($blockProcedure->isDisplay() && !empty($content)) {
						$context->mAttributes['legacy_BlockShowFlags'][$blockProcedure->getEntryIndex()] = true;
						$context->mAttributes['legacy_BlockContents'][$blockProcedure->getEntryIndex()][] = array(
							'id' => $blockProcedure->getId(),
							'name' => $blockProcedure->getName(),
							'title'   => $blockProcedure->getTitle(),
							'content' => $content,
							'weight'  => $blockProcedure->getWeight()
						);
					}
						
					$usedCacheFlag = true;
				}
			}
			
			if (!$usedCacheFlag) {
				$blockProcedure->execute();

				$renderBuffer = null;
				if ($blockProcedure->isDisplay()) {
					$renderBuffer =& $blockProcedure->getRenderTarget();
					
					$context->mAttributes['legacy_BlockShowFlags'][$blockProcedure->getEntryIndex()] = true;
					$context->mAttributes['legacy_BlockContents'][$blockProcedure->getEntryIndex()][] = array(
							'name' => $blockProcedure->getName(),
							'title'=>$blockProcedure->getTitle(),
							'content'=>$renderBuffer->getResult(),
							'weight'=>$blockProcedure->getWeight()
					);
				}
				else {
					//
					// Dummy save
					//
					$renderBuffer =& new XCube_RenderTarget();
				}
				
				if ($this->isEnableCacheFeature() && $blockProcedure->isEnableCache() && is_object($cacheInfo) && $cacheInfo->isEnableCache()) {
					$this->cacheRenderTarget($cacheInfo->getCacheFilePath(), $renderBuffer);
				}
			}

			unset($blockProcedure);
		}
	}

	function _parseUrl()
	{
		$ret = array();
		
		$nakedRootPath=substr(strstr(XOOPS_URL,$_SERVER['HTTP_HOST']),strlen($_SERVER['HTTP_HOST'])) . "/";
		$subPath=substr(urldecode($_SERVER['REQUEST_URI']),strlen($nakedRootPath));

		return explode("/",$subPath);
	}

	function setupModuleContext($dirname = null)
	{
		if ($dirname == null) {
			//
			// Sets a module object.
			//
			$urlInfo = $this->_parseUrl();

			if (count($urlInfo) >= 2) {
				if (strtolower($urlInfo[0]) == 'modules') {
					$dirname = $urlInfo[1];
				}
			}
			elseif (substr($urlInfo[0], 0, 9) == 'admin.php') {
				$dirname = 'legacy';
			}
		}
		
		if ($dirname == null) {
			return;
		}
		
		if (!file_exists(XOOPS_ROOT_PATH . "/modules/" . $dirname . "/" . LEGACY_XOOPS_MODULE_MANIFESTO_FILENAME)) {
			return;
		}
		
		$this->_mStrategy->setupModuleContext($this->mRoot->mContext, $dirname);
		
		if ($this->mRoot->mContext->mModule != null) {
			$this->mRoot->mContext->setAttribute('legacy_pagetitle', $this->mRoot->mContext->mModule->mXoopsModule->get('name'));
		}
	}
	
	function _processModule()
	{
		if ($this->mRoot->mContext->mModule != null) {
			$module =& $this->mRoot->mContext->mModule;
			if (!$module->isActive()) {
				/**
				 * Notify that the current user accesses none-activate module
				 * controller.
				 */
				XCube_DelegateUtils::call('Legacy.Event.Exception.ModuleNotActive', $module);
				$this->executeForward(XOOPS_URL . '/');
				die();
			}
			
			if (!$this->_mStrategy->enableAccess()) {
				XCube_DelegateUtils::call('Legacy.Event.Exception.ModuleSecurity', $module);
				$this->executeRedirect(XOOPS_URL . '/user.php', 1, _NOPERM);	// TODO Depens on const message catalog.
				die();
			}
			
			$this->_mStrategy->setupModuleLanguage();
			$module->startup();
			
			$GLOBALS['xoopsModule'] =& $module->mXoopsModule;
			$GLOBALS['xoopsModuleConfig'] =& $module->mModuleConfig;
		}
		
		Legacy_Utils::raiseUserControlEvent();
	}
	
	// @todo change to refer settings ini file for HostAbstractLayer.
	function _processHostAbstractLayer()
	{
		if ( !isset($_SERVER['PATH_TRANSLATED']) && isset($_SERVER['SCRIPT_FILENAME']) ) {
			// There is this setting for CGI mode. @todo We have to confirm this.
			$_SERVER['PATH_TRANSLATED'] =& $_SERVER['SCRIPT_FILENAME'];
		} elseif ( isset($_SERVER['PATH_TRANSLATED']) && !isset($_SERVER['SCRIPT_FILENAME']) ) {
			// There is this setting for IIS Win2K. Really?
			$_SERVER['SCRIPT_FILENAME'] =& $_SERVER['PATH_TRANSLATED'];
		}

		// IIS does not set REQUEST_URI. This system defines it. But...
		if (empty($_SERVER['REQUEST_URI'])) {
			if ( !( $_SERVER[ 'REQUEST_URI' ] = @$_SERVER['PHP_SELF'] ) ) {
				$_SERVER[ 'REQUEST_URI' ] = $_SERVER['SCRIPT_NAME'];
			}
			if ( isset( $_SERVER[ 'QUERY_STRING' ] ) ) {
				$_SERVER[ 'REQUEST_URI' ] .= '?' . $_SERVER[ 'QUERY_STRING' ];
			}
		    
			// Guard for XSS string of PHP_SELF
			// @todo I must move this logic to preload plugin.
			if(preg_match("/[\<\>\"\'\(\)]/",$_SERVER['REQUEST_URI']))
				die();
		}

		// What is this!? But, old system depends this setting. We have to confirm it and modify!
		$GLOBALS['xoopsRequestUri'] = $_SERVER[ 'REQUEST_URI' ];
	}

	function _setupUser()
	{
		parent::_setupUser();

		// Set instance to global variable for compatiblity with XOOPS 2.0.x
		$GLOBALS['xoopsUser'] =& $this->mRoot->mContext->mXoopsUser;
		$GLOBALS['xoopsUserIsAdmin'] = is_object($this->mRoot->mContext->mXoopsUser) ? $this->mRoot->mContext->mXoopsUser->isAdmin(1) : false;	//@todo Remove '1'

		//
		// Set member handler to global variables for compatibility with XOOPS 2.0.x.
		//		
		$GLOBALS['xoopsMemberHandler'] =& xoops_gethandler('member');
		$GLOBALS['member_handler'] =& $GLOBALS['xoopsMemberHandler'];
	}
	
	function _setupErrorHandler()
	{
	}

	/**
	 * Create the instance of DataBase class, and set it to member property.
	 * @access protected
	 */
	function _setupDB()
	{
		if(!defined('XOOPS_XMLRPC'))
			define('XOOPS_DB_CHKREF', 1);
		else
			define('XOOPS_DB_CHKREF', 0);

		require_once XOOPS_ROOT_PATH.'/class/database/databasefactory.php';

		if ($this->mRoot->getSiteConfig('Legacy', 'AllowDBProxy') == true) {
			if ($_SERVER['REQUEST_METHOD'] != 'POST' || !xoops_refcheck(XOOPS_DB_CHKREF)) {
				define('XOOPS_DB_PROXY', 1);
			}
		}
		elseif ($_SERVER['REQUEST_METHOD'] != 'POST') {
			define('XOOPS_DB_PROXY', 1);
		}

		$this->mDB =& XoopsDatabaseFactory::getDatabaseConnection();

		$GLOBALS['xoopsDB']=&$this->mDB;
	}
	
	/**
	 * Create a instance of Legacy_LanguageManager by the specified language,
	 * and set it to member properties.
	 * 
	 * [Notice]
	 * Now, this member function sets a string to the member property without
	 * language manager.
	 */
	function _setupLanguage()
	{
		require_once XOOPS_LEGACY_PATH."/kernel/Legacy_LanguageManager.class.php";
		
		$language = null;
		
		$this->mGetLanguageName->call(new XCube_Ref($language));
		
		if ($language == null) {
			$handler =& xoops_gethandler('config');
			$criteria =& new CriteriaCompo(new Criteria('conf_modid', 0));
			$criteria->add(new Criteria('conf_catid', XOOPS_CONF));
			$criteria->add(new Criteria('conf_name', 'language'));
			$configs =& $handler->getConfigs($criteria);
		
			if (count($configs) > 0) {
				$language = $configs[0]->get('conf_value', 'none');
			}
		}

		$this->mRoot->mLanguageManager =& $this->_createLanguageManager($language);
		$this->mRoot->mLanguageManager->setLanguage($language);
		$this->mRoot->mLanguageManager->prepare();

		// If you use special page, load message catalog for it.
		if (isset($GLOBALS['xoopsOption']['pagetype'])) {
			$this->mRoot->mLanguageManager->loadPageTypeMessageCatalog($GLOBALS['xoopsOption']['pagetype']);
		}
    }

	/**
	 * Factory for the language manager. At first, this member function
	 * delegates to get a instance of LanguageManager. If it can't get it, do
	 * the following process: 
	 * 
	 * 1) Try creating a instance of 'Legacy_LanguageManager_' . ucfirst($language)
	 * 2) If the class doesn't exist, try loading  'LanguageManager.class.php' 
	 *    in the specified language.
	 * 3) Re-try creating the instance.
	 * 
	 * If it can't create any instances, create a instance of
	 * Legacy_LanguageManager as default.
	 * 
	 * @access protected
	 * @param string $language 
	 * @return Legacy_LanguageManager
	 */	
	function &_createLanguageManager($language)
	{
		require_once XOOPS_LEGACY_PATH . "/kernel/Legacy_LanguageManager.class.php";

		$languageManager = null;
		
		$this->mCreateLanguageManager->call(new XCube_Ref($languageManager), $language);
		
		if (!is_object($languageManager)) {
			$className = "Legacy_LanguageManager_" . ucfirst(strtolower($language));
			
			//
			// If the class exists, create a instance. Else, load the file, and
			// try creating a instance again.
			//
			if (class_exists($className)) {
				$languageManager =& new $className();
			}
			else {
				$filePath = XOOPS_ROOT_PATH . "/language/" . $language . "/LanguageManager.class.php";
				if (file_exists($filePath)) {
					require_once $filePath;
				}
				
				if (class_exists($className)) {
					$languageManager =& new $className();
				}
				else {
					//
					// Default
					//
					$languageManager =& new Legacy_LanguageManager();
				}
			}
		}
		
		return $languageManager;
	}

	function _setupConfig()
	{
		$configHandler = &xoops_gethandler('config');
        
        $this->mRoot->mContext->mXoopsConfig =& $configHandler->getConfigsByCat(XOOPS_CONF);

		$this->mRoot->mContext->setThemeName($this->mRoot->mContext->mXoopsConfig['theme_set']);
	    $this->mRoot->mContext->mXoopsConfig['language'] = $this->mRoot->mLanguageManager->getLanguage();
		
		$this->mRoot->mContext->setAttribute('legacy_sitename', $this->mRoot->mContext->mXoopsConfig['sitename']);
		$this->mRoot->mContext->setAttribute('legacy_pagetitle', $this->mRoot->mContext->mXoopsConfig['slogan']);
		$this->mRoot->mContext->setAttribute('legacy_slogan', $this->mRoot->mContext->mXoopsConfig['slogan']);
		
		$GLOBALS['xoopsConfig'] = $this->mRoot->mContext->mXoopsConfig; // Compatiblity for 2.0.x
		$GLOBALS['config_handler'] =& $configHandler;
		
		$GLOBALS['module_handler'] =& xoops_gethandler('module');
	}

	/**
	 * Set debbuger object to member property.
	 * @return void
	 */
	function _setupDebugger()
	{
		error_reporting(0);

		$debug_mode = $this->mRoot->mContext->mXoopsConfig['debug_mode'];
		if (defined("OH_MY_GOD_HELP_ME")) {
			$debug_mode = XOOPS_DEBUG_PHP;
		}

		$this->mSetupDebugger->call(new XCube_Ref($this->mDebugger), $debug_mode);
		$this->mDebugger->prepare();

		$GLOBALS['xoopsDebugger']=&$this->mDebugger;
	}

	function _processPreBlockFilter()
    {
		$this->_mStrategy->_processPreBlockFilter();
        parent::_processPreBlockFilter();
    }
	
	function _processModulePreload($dirname)
	{
		//
		// Auto pre-loading for Module.
		//
		if ($this->mRoot->getSiteConfig('Legacy', 'AutoPreload') == 1) {
            $moduleHandler =& xoops_gethandler('module');
            $criteria =& new Criteria('isactive', 1);
            $moduleObjects =& $moduleHandler->getObjects($criteria);
            foreach ($moduleObjects as $moduleObject) {
                $mod_dir = $moduleObject->getVar('dirname');
                $dir = XOOPS_ROOT_PATH . '/modules/' . $mod_dir . $dirname . '/';
    			if(is_dir($dir)) {
    			    $files = glob($dir.'*.class.php');
    			    if (is_array($files)) {
						foreach($files as $file) {
							require_once $file;
							if (preg_match("/(\w+)\.class\.php/", $file, $matches)) {
								$className = ucfirst($mod_dir) . "_" . $matches[1];
						
								if (class_exists($className) && !isset($this->_mLoadedFilterNames[$className])) {
									$this->_mLoadedFilterNames[$className] = true;
									$instance =& new $className($this);
									$this->addActionFilter($instance);
								}
							}
						}
    			    }
    			}
            }
        }
	}

	function _setupSession()
	{
		$sessionHandler=&xoops_gethandler('session');
		
		session_set_save_handler( 
			array(&$sessionHandler,"open"),
			array(&$sessionHandler,"close"),
			array(&$sessionHandler, 'read'),
			array(&$sessionHandler, 'write'),
			array(&$sessionHandler, 'destroy'),
			array(&$sessionHandler, 'gc'));
		
		session_start();
	}

	
	function executeHeader()
	{
		//
		// TODO Now, I done for working admin panel.
		//
		parent::executeHeader();

		//
		//  We changed a render-system class in a pure drawing system. Therefore
		// a controller should not ask him for careful work for compatibility.
		//

		//
		// The following comment-outed line is old version process.
		//
		// $this->mRenderSystem->_processStartPage();

		require_once XOOPS_ROOT_PATH.'/include/old_theme_functions.php';
		$GLOBALS['xoopsTheme']['thename'] = $GLOBALS['xoopsConfig']['theme_set'];

		//
		// cache check
		//
		if ($this->mRoot->mContext->mModule != null && $this->isEnableCacheFeature()) {
			$cacheInfo =& $this->mRoot->mContext->mModule->createCacheInfo();
			
			$this->mSetModuleCachePolicy->call($cacheInfo);
			
			if ($this->mRoot->mContext->mModule->isEnableCache()) {
				//
				// Checks whether the cache file exists.
				//
				$xoopsModule =& $this->mRoot->mContext->mXoopsModule;
	
				$cachetime = $this->mRoot->mContext->mXoopsConfig['module_cache'][$xoopsModule->get('mid')];
				$filepath = $cacheInfo->getCacheFilePath();
				
				//
				// Checks whether the active cache file exists. If it's OK, load
				// cache and do display.
				//			
				if ($cacheInfo->isEnableCache() && $this->existActiveCacheFile($filepath, $cachetime)) {
					$renderSystem =& $this->mRoot->getRenderSystem($this->mRoot->mContext->mModule->getRenderSystemName());
					$renderTarget =& $renderSystem->createRenderTarget(XCUBE_RENDER_TARGET_TYPE_MAIN);
					$renderTarget->setResult($this->loadCache($filepath));
					
					$this->_executeViewTheme($renderTarget);
					
					exit();
				}
			}
		}

		ob_start();
	}
	
	function executeView()
	{
		if ($this->mRoot->mContext->mModule != null) {
			$renderSystem =& $this->mRoot->getRenderSystem($this->mRoot->mContext->mModule->getRenderSystemName());
			$renderTarget =& $this->mRoot->mContext->mModule->getRenderTarget();
		
			//
			//  Buffering handling of standard output for main render target is responsibility
			// of a controller. Of course all controllers do not have to implement this.
			// The following lines are movement for compatibility and the feature of
			// this controller.
			//
		
			// Wmm...
			if (is_object($renderTarget)) {
				if ($renderTarget->getTemplateName() == null) {
					if (isset($GLOBALS['xoopsOption']['template_main'])) {
						$renderTarget->setTemplateName($GLOBALS['xoopsOption']['template_main']);
					}
				}
				
				$renderTarget->setAttribute("stdout_buffer", ob_get_contents());
			}
	
			ob_end_clean();
			
			if (is_object($renderTarget)) {
				$renderSystem->render($renderTarget);
	
				//
				// Cache Control
				//
				if ($this->isEnableCacheFeature() && $this->mRoot->mContext->mModule->isEnableCache()) {
					if ($this->mRoot->mContext->mModule->mCacheInfo->isEnableCache()) {
						$this->cacheRenderTarget($this->mRoot->mContext->mModule->mCacheInfo->getCacheFilePath(), $renderTarget);
					}
				}
				else {
				}
			}
		}
		
		$this->_executeViewTheme($renderTarget);
	}
	
	/**
	 * $resultRenderTarget object The render target of content's result.
	 */
	function _executeViewTheme(&$resultRenderTarget)
	{
		//
		// Get the render-system through theme object.
		//
		$theme =& $this->_mStrategy->getMainThemeObject();
		
		$renderSystem =& $this->mRoot->getRenderSystem($theme->get('render_system'));
		$screenTarget = $renderSystem->getThemeRenderTarget($this->mDialogMode);
		
		if (is_object($resultRenderTarget)) {
			$screenTarget->setAttribute('xoops_contents', $resultRenderTarget->getResult());
		}

		$screenTarget->setTemplateName($theme->get('dirname'));

		//
		// Rendering.
		//
		$renderSystem->render($screenTarget);

		//
		// Debug Process
		//
		$isAdmin=false;
		if(is_object($this->mRoot->mContext->mXoopsUser)) {
			if($this->mRoot->mContext->mModule != null && $this->mRoot->mContext->mModule->isActive()) {
				// @todo I depend on Legacy Module Controller.
				$mid = $this->mRoot->mContext->mXoopsModule->getVar('mid');
			}
			else {
				$mid = 1;	///< @todo Do not use literal directly!
			}

			$isAdmin = $this->mRoot->mContext->mXoopsUser->isAdmin($mid);
		}

		if ($isAdmin) {
			$this->mDebugger->displayLog();
		}
	}

	function &_createDelegateManager()
	{
		$delegateManager =& parent::_createDelegateManager();
		
		$file = XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_EventFunctions.class.php";
		
		$delegateManager->add('Legacypage.Notifications.Access', 'Legacy_EventFunction::notifications', $file);
		$delegateManager->add('Legacyfunction.Notifications.Select', 'Legacy_EventFunction::notifications_select', $file);
		$delegateManager->add('Legacypage.Search.Access', 'Legacy_EventFunction::search', $file);
		$delegateManager->add('Legacypage.Imagemanager.Access', 'Legacy_EventFunction::imageManager', $file);
		$delegateManager->add('Legacypage.Backend.Access', 'Legacy_EventFunction::backend', $file);
		$delegateManager->add('Legacypage.Misc.Access', 'Legacy_EventFunction::misc', $file);
		$delegateManager->add('User_UserViewAction.GetUserPosts', 'Legacy_EventFunction::recountPost', $file);
		
		return $delegateManager;
	}
	
	function &_createServiceManager()
	{
		$serviceManager =& parent::_createServiceManager();
		
		require_once XOOPS_ROOT_PATH . "/modules/legacy/service/LegacySearchService.class.php";
		$searchService =& new Legacy_SearchService();
		$searchService->prepare();
		
		$serviceManager->addService('LegacySearch', $searchService);

		return $serviceManager;
	}
	
	/**
	 * Check the login request through delegates, and set XoopsObject to member
	 * property if the login is success.
	 * 
	 * @access public
	 */
	function checkLogin()
	{
		if (!is_object($this->mRoot->mContext->mXoopsUser)) {
			$this->mCheckLogin->call(new XCube_Ref($this->mRoot->mContext->mXoopsUser));
			
			$this->mRoot->mLanguageManager->loadModuleMessageCatalog('legacy');

			if(is_object($this->mRoot->mContext->mXoopsUser)) {
				// RMV-NOTIFY
				// Perform some maintenance of notification records
				$notification_handler =& xoops_gethandler('notification');
				$notification_handler->doLoginMaintenance($this->mRoot->mContext->mXoopsUser->get('uid'));

				XCube_DelegateUtils::call("Site.CheckLogin.Success", new XCube_Ref($this->mRoot->mContext->mXoopsUser));

				//
				// Fall back process for login success.
				//
				$url = XOOPS_URL;
				if (!empty($_POST['xoops_redirect']) && !strpos(xoops_getrequest('xoops_redirect'), 'register')) {
					$parsed = parse_url(XOOPS_URL);
					$url = isset($parsed['scheme']) ? $parsed['scheme'].'://' : 'http://';
					
					if (isset($parsed['host'])) {
						$url .= isset($parsed['port']) ? $parsed['host'] . ':' . $parsed['port'] . trim(xoops_getrequest('xoops_redirect')): $parsed['host'] . trim(xoops_getrequest('xoops_redirect'));
					} else {
						$url .= xoops_getenv('HTTP_HOST') . trim(xoops_getrequest('xoops_redirect'));
					}
				}
				
				$this->executeRedirect($url, 1, XCube_Utils::formatMessage(_MD_LEGACY_MESSAGE_LOGIN_SUCCESS, $this->mRoot->mContext->mXoopsUser->get('uname')));
			}
			else {
				XCube_DelegateUtils::call("Site.CheckLogin.Fail", new XCube_Ref($this->mRoot->mContext->mXoopsUser));
				
				//
				// Fall back process for login fail.
				//
				$this->executeRedirect(XOOPS_URL . "/user.php", 1, _MD_LEGACY_ERROR_INCORRECTLOGIN);
			}
		}
		else {
			$this->executeForward(XOOPS_URL . '/');
		}
	}
	
	/**
	 * The current user logout.
	 * 
	 * @access public
	 */
	function logout()
	{
		$successFlag = false;
		$xoopsUser =& $this->mRoot->mContext->mXoopsUser;
		
		
		if (is_object($xoopsUser)) {
			$this->mRoot->mLanguageManager->loadModuleMessageCatalog('legacy');
			
			$this->mLogout->call(new XCube_Ref($successFlag), $xoopsUser);
			if ($successFlag) {
				XCube_DelegateUtils::call("Site.Logout.Success", $xoopsUser);
				$this->executeRedirect(XOOPS_URL . '/', 1, array(_MD_LEGACY_MESSAGE_LOGGEDOUT, _MD_LEGACY_MESSAGE_THANKYOUFORVISIT));
			}
			else {
				XCube_DelegateUtils::call("Site.Logout.Fail", $xoopsUser);
			}
		}
		else {
			$this->executeForward(XOOPS_URL . '/');
		}
	}

	/**
	 * @deprecated
	 * @see setStrategy()
	 */
	function switchStateCompulsory(&$strategy)
	{
		$this->setStrategy($strategy);
	}
	
	/**
	 * CAUTION!!
	 * This method has a special mission.
	 * Because this method changes state after executeCommon, this resets now property.
	 * It depends on XCube_Controller steps.
	 *
	 * @param Legacy_AbstractControllerStrategy $strategy
	 */
	function setStrategy(&$strategy)
	{
		if ($strategy->mStatusFlag != $this->_mStrategy->mStatusFlag) {
			$this->_mStrategy =& $strategy;
			
			//
			// The following line depends on XCube_Controller process of executeCommon.
			// But, There is no other method.
			//
			$this->setupModuleContext();
			$this->_processModule();
		}
	}

	/**
	 * Set bool flag to dialog mode flag.
	 * If you set true, executeView() will use Legacy_DialogRenderTarget class as
	 * render target.
	 * @param $flag bool
	 */
	function setDialogMode($flag)
	{
		$this->mDialogMode = $flag;
	}

	/**
	 * Return dialog mode flag.
	 * @return bool
	 */
	function getDialogMode()
	{
		return $this->mDialogMode;
	}
	
	/**
	 *  Return current module object. But, it's decided by the rules of the state.
	 *  Preferences page, Help page and some pages returns the specified module by
	 * dirname. It's useful for controlling a theme. 
	 * 
	 * @return XoopsModule
	 */
	function &getVirtualCurrentModule()
	{
		$ret =& $this->_mStrategy->getVirtualCurrentModule();
		return $ret;
	}
	
	/**
	 * This member function works to redirect as well as redirect_header().
	 * But, this member function handles raw values which hasn't been converted
	 * by htmlspecialchars(). Therefore, if user calls this function with the
	 * wrong value, some problems may be raised. If you can't understand the
	 * difference, use not this function but redirect_header().
	 * 
	 * @param string $url          redirect URL. Don't use user's variables or request.
	 * @param int    $time         waiting time (sec)
	 * @param string $message      This string doesn't include tags.
	 * @param bool   $addRedirect  A value indicationg whether this method adds URL automatically for user.php.
	 * 
	 * @todo We'll change this function to delegate.
	 * @remark This method encode $url and $message directly without its template, to share the template with old function.
	 */
	function executeRedirect($url, $time = 1, $message = null, $addRedirect = true)
	{
		global $xoopsConfig, $xoopsRequestUri;

		//
		// Check the following by way of caution.
		//
		if (preg_match("/(javascript|vbscript):/si", $url)) {
			$url = XOOPS_URL;
		}
		
		$displayMessage = "";
		if (is_array($message)) {
			foreach (array_keys($message) as $key) {
				$message[$key] = htmlspecialchars($message[$key], ENT_QUOTES);
			}
			$displayMessage = implode("<br/>", $message);
		}
		else {
			$displayMessage = $message;
		}
		
		$url = htmlspecialchars($url, ENT_QUOTES);
		
		// XOOPS2 Compatibility
		if ($addRedirect && strstr($url, 'user.php')) {
			$this->_mNotifyRedirectToUser->call(new XCube_Ref($url));
		}
		
		if (defined('SID') && (! isset($_COOKIE[session_name()]) || ($xoopsConfig['use_mysession'] && $xoopsConfig['session_name'] != '' && !isset($_COOKIE[$xoopsConfig['session_name']])))) {
			if (!strstr($url, '?')) {
				$url .= '?' . SID;
			}
			else {
				$url .= '&amp;' . SID;
			}
		}

		if (!defined('XOOPS_CPFUNC_LOADED')) {
			require_once XOOPS_ROOT_PATH.'/class/template.php';
			$xoopsTpl = new XoopsTpl();
			$xoopsTpl->assign('xoops_sitename', htmlspecialchars($xoopsConfig['sitename'], ENT_QUOTES));
			$xoopsTpl->assign('sitename', htmlspecialchars($xoopsConfig['sitename'], ENT_QUOTES));
			$xoopsTpl->assign('langcode', _LANGCODE);
			$xoopsTpl->assign('charset', _CHARSET);
			$xoopsTpl->assign('time', $time);

			$xoopsTpl->assign('url', $url);
			$xoopsTpl->assign('message', $displayMessage);
			$xoopsTpl->assign('lang_ifnotreload', sprintf(_IFNOTRELOAD, $url));
			$GLOBALS['xoopsModuleUpdate'] = 1;
			$xoopsTpl->display('db:system_redirect.html');
		} else {
			$url = preg_replace("/&amp;/i", '&', htmlspecialchars($url, ENT_QUOTES));
			echo '
			<html>
			<head>
			<title>'.htmlspecialchars($xoopsConfig['sitename']).'</title>
			<meta http-equiv="Content-Type" content="text/html; charset='._CHARSET.'" />
			<meta http-equiv="Refresh" content="'.$time.'; url='.$url.'" />
			<style type="text/css">
					body {background-color : #fcfcfc; font-size: 12px; font-family: Trebuchet MS,Verdana, Arial, Helvetica, sans-serif; margin: 0px;}
					.redirect {width: 70%; margin: 110px; text-align: center; padding: 15px; border: #e0e0e0 1px solid; color: #666666; background-color: #f6f6f6;}
					.redirect a:link {color: #666666; text-decoration: none; font-weight: bold;}
					.redirect a:visited {color: #666666; text-decoration: none; font-weight: bold;}
					.redirect a:hover {color: #999999; text-decoration: underline; font-weight: bold;}
			</style>
			</head>
			<body>
			<div align="center">
			<div class="redirect">
			<span style="font-size: 16px; font-weight: bold;">'.$displayMessage.'</span>
			<hr style="height: 3px; border: 3px #E18A00 solid; width: 95%;" />
			<p>'.sprintf(_IFNOTRELOAD, $url).'</p>
			</div>
			</div>
			</body>
			</html>';
		}
		
		exit();
	}
	
	/**
	 * Gets a value indicating whether the controller can use a cache mechanism.
	 * @return bool
	 */	
	function isEnableCacheFeature()
	{
		return $this->_mStrategy->isEnableCacheFeature();
	}

	/**
	 * Gets a value indicating wheter a cache file keeps life time. If
	 * $cachetime is 0 or the specific cache file doesn't exist, gets false.
	 * 
	 * @param string $filepath  a file path of the specific cache file.
	 * @param int    $cachetime cache active duration. (Sec)
	 * @return bool
	 */
	function existActiveCacheFile($filepath, $cachetime)
	{
		if ($cachetime == 0) {
			return false;
		}
		
		if (!file_exists($filepath)) {
			return false;
		}
		
		return ((time() - filemtime($filepath)) <= $cachetime);
	}
	
	/**
	 * Save the content of $renderTarget to $filepath.
	 * @param string $filepath a file path of the cache file.
	 * @param XCube_RenderTarget $renderBuffer
	 * @return bool success or failure.
	 */	
	function cacheRenderTarget($filepath, &$renderTarget)
	{
		$fp = fopen($filepath, "wb");
		if ($fp) {
			fwrite($fp, $renderTarget->getResult());
			fclose($fp);
			return true;
		}
		
		return false;
	}
	
	/**
	 * Loads $filepath and gets the content of the file.
	 * @return string the content or null.
	 */
	function loadCache($filepath)
	{
		if (file_exists($filepath)) {
			return file_get_contents($filepath);
		}
		
		return null;
	}
	
	function &_createContext()
	{
		require_once XOOPS_ROOT_PATH . "/modules/legacy/kernel/Legacy_HttpContext.class.php";
		
		$context =& new Legacy_HttpContext();
		$request =& new XCube_HttpRequest();
		$context->setRequest($request);
		
		return $context;
	}
	
	/**
	 * Gets URL of preference editor by this controller.
	 * @public
	 * @param XoopsModule $module
	 * @return string absolute URL
	 */
	function getPreferenceEditUrl(&$module)
	{
		if (is_object($module)) {
			return XOOPS_MODULE_URL . '/legacy/admin/index.php?action=PreferenceEdit&confmod_id=' . $module->get('mid');
		}

		return null;
	}
	
	/**
	 * Gets URL of help viewer by this controller.
	 * @public
	 * @param XoopsModule $module
	 * @return string absolute URL
	 */
	function getHelpViewUrl(&$module)
	{
		if (is_object($module)) {
			return XOOPS_MODULE_URL . '/legacy/admin/index.php?action=Help&dirname=' . $module->get('dirname');
		}

		return null;
	}
}

/**
 * @abstract
 */
class Legacy_AbstractControllerStrategy
{
	/**
	 * @var Legacy_Controller
	 */
	var $mController = null;
	
	var $mStatusFlag;
	
	function Legacy_AbstractControllerStrategy(&$controller)
	{
		$this->mController =& $controller;
	}
	
	function _setupFilterChain()
	{
		$primaryPreloads = $this->mController->mRoot->getSiteConfig('Legacy.PrimaryPreloads');
		foreach ($primaryPreloads as $className => $classPath) {
			if (file_exists(XOOPS_ROOT_PATH . $classPath)) {
				require_once XOOPS_ROOT_PATH . $classPath;
				if (class_exists($className) && !isset($this->_mLoadedFilterNames[$className])) {
					$this->_mLoadedFilterNames[$className] = true;
					$filter =& new $className($this->mController);
					$this->mController->addActionFilter($filter);
					unset($filter);
				}
			}
		}

		//
		// Auto pre-loading.
		//
		if($this->mController->mRoot->getSiteConfig('Legacy', 'AutoPreload') == 1) {
			$this->mController->_processPreload(XOOPS_ROOT_PATH . "/preload");
		}
	}

	/**
	 * Create some instances for the module process.
	 * Because Legacy_ModuleContext needs XoopsModule instance, this function
	 * kills the process if XoopsModule instance can't be found. Plus, in the
	 * case, raises 'Legacy.Event.Exception.XoopsModuleNotFound'.
	 * 
	 * @param Legacy_HttpContext $context
	 * @param string $dirname
	 */	
	function setupModuleContext(&$context, $dirname)
	{
		$handler =& xoops_gethandler('module');
		$module =& $handler->getByDirname($dirname);

		if (!is_object($module)) {
			XCube_DelegateUtils::call('Legacy.Event.Exception.XoopsModuleNotFound', $dirname);
			$this->mController->executeRedirect(XOOPS_URL . '/', 1, "You can't access this URL.");	// TODO need message catalog.
			die();
		}
		
		$context->mModule =& Legacy_Utils::createModule($module);
		$context->mXoopsModule =& $context->mModule->getXoopsModule();
		$context->mModuleConfig = $context->mModule->getModuleConfig();
		
		//
		// Load Roles
		//
		$this->mController->mRoot->mRoleManager->loadRolesByMid($context->mXoopsModule->get('mid'));
	}

	function setupBlock()
	{
	}
	
	function _processPreBlockFilter()
	{
		$this->mController->_processModulePreload('/preload');
	}

	/**
	 * @return XoopsModule
	 * @see Legacy_Controller::getVirtualCurrentModule()
	 */	
	function &getVirtualCurrentModule()
	{
		$ret = null;
		return $ret;
	}
	
	/**
	 * Gets a value indicating whether the controller can use a cache mechanism.
	 */	
	function isEnableCacheFeature()
	{
	}
	
	/**
	 * Gets a value indicating whether the current user can access to the current module.
	 * @return bool
	 */
	function enableAccess()
	{
	}
	
	function setupModuleLanguage()
	{
	}
}

?>