<?php
/**
 * @package Legacy
 * @version $Id: Legacy_Controller.class.php,v 1.1.2.80 2006/10/02 14:23:29 minahito Exp $
 */

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

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

require_once XOOPS_ROOT_PATH . "/modules/base/kernel/Legacy_BlockProcedure.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 $mXoopsUser;

	var $_mAdminModeFlag = false;
	var $_mStrategy = null;
	
	var $mDialogMode = false;
	
	/**
	 * @todo Rename this with "mModule"
	 */
	var $mModuleController = null;
	
	/**
	 * @var XCube_Deleagate
	 */
	var $mSiteLogin = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mGetCountUnreadPM = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mGetPMInboxUrl = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mCheckLogin = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mLogout = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mCreateLanguageManager = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mCheckEnableBlockCache = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mCheckEnableModuleCache = null;

	/**
	 * @var XCube_Delegate
	 */
	var $mGetBlockCacheFilePath = null;
	
	/**
	 * @var XCube_Delegate
	 */
	var $mGetLanguageName = null;
	
	var $mBlockShowFlags = array();
	var $mBlockContents = array();
	
	/**
	 * @deprecated
	 */
	var $mRenderSystem = null;
	
	function Legacy_Controller()
	{
		//
		// Setup member properties as member delegates.
		//
		$this->mSiteLogin =& new XCube_Delegate();
		$this->mSiteLogin->register("Site.Login");
		
		$this->mGetCountUnreadPM =& new XCube_Delegate();
		$this->mGetPMInboxUrl =& new XCube_Delegate();
		
		$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->mCheckEnableBlockCache =& new XCube_Delegate();
		$this->mCheckEnableModuleCache =& new XCube_Delegate();
		$this->mGetModuleCacheFilePath =& new XCube_Delegate();
		$this->mGetBlockCacheFilePath =& new XCube_Delegate();

		set_magic_quotes_runtime(0);	// ^^;
		
		//
		// Decide status. [TEST]
		//
		$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] == "system" && substr($urlInfo[2], 0, 9) == "admin.php") {
				$adminStateFlag=true;
			}
		}
		elseif(substr($urlInfo[0], 0, 9) == "admin.php") {
			$adminStateFlag=true;
		}

		$this->_mStrategy = $adminStateFlag ?  new Legacy_AdminControllerStrategy($this) : 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->_setupConfig();
		
		$this->_setupDebugger();

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

		$this->_processHostAbstractLayer();

		$this->_setupSession();

		$this->_setupUser();

		$this->_setupModuleController();

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

		$GLOBALS['xoopsLogger']=&$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_BASE_PATH",XOOPS_MODULE_PATH."/".XOOPS_BASE_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_BASE_PATH."/kernel/object.php";				// ToDo (here?)
		require_once XOOPS_BASE_PATH."/kernel/handler.php";				// ToDo
		require_once XOOPS_ROOT_PATH."/class/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.
		//
		
		//
		// TODO We should use RenderSystem to create a render-target.
		//
		$renderTarget =& new XCube_RenderTarget();
		$renderTarget->setType(XCUBE_RENDER_TARGET_TYPE_BLOCK);
		
		$cacheInfo =& new Legacy_BlockCacheInformation();

		foreach ($this->mBlockChain as $blockProcedure) {
			$renderTarget->reset();
			
			//
			// This is a flag indicating whether the controller needs to call
			// the logic of the block.
			//
			$usedCacheFlag = false;
			
			if ($this->isEnableCacheFeature()) {
				//
				// Reset the block cache information structure, and initialize.
				//
				$cacheInfo->reset();
				$cacheInfo->setBlock($blockProcedure->mAdapteeBlockObject);	//< FIXME
				$this->mCheckEnableBlockCache->call(new XCube_Ref($cacheInfo));

				$filepath = $this->getBlockCacheFilePath($cacheInfo);
				
				//
				// 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 ($content != null) {
						$this->mBlockShowFlags[$blockProcedure->getEntryIndex()] = true;
						$this->mBlockContents[$blockProcedure->getEntryIndex()][] = array(
							'name' => $blockProcedure->getName(),
							'title'   => $blockProcedure->getTitle(),
							'content' => $content,
							'weight'  => $blockProcedure->getWeight()
						);
						
						$usedCacheFlag = true;
					}
				}
			}
			
			if (!$usedCacheFlag) {
				$renderSystem =& $this->mRoot->getRenderSystem($blockProcedure->getRenderSystemName());
				
				$blockProcedure->execute($this, $this->getXoopsUser(), $renderTarget);

				if (!$blockProcedure->hasResult()) {
					continue;
				}
				
				$renderSystem->renderBlock($renderTarget);
				
				$this->mBlockShowFlags[$blockProcedure->getEntryIndex()] = true;
				$this->mBlockContents[$blockProcedure->getEntryIndex()][] = array(
						'name' => $blockProcedure->getName(),
						'title'=>$blockProcedure->getTitle(),
						'content'=>$renderTarget->getResult(),
						'weight'=>$blockProcedure->getWeight()
				);

				if ($this->isEnableCacheFeature() && $blockProcedure->getCacheTime() > 0 && $cacheInfo->isEnableCache()) {
					$this->cacheRenderTarget($this->getBlockCacheFilePath($cacheInfo), $renderTarget);
				}
			}

			unset($blockProcedure);
		}
	}

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

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

	function _setupModuleController()
	{
		$this->_mStrategy->setupModuleController();
	}

	function _processModuleController()
	{
		$this->mModuleController->prepare();

		if ($this->mModuleController->isModuleProcess()) {
			if (!$this->mModuleController->isActive()) {
				/**
				 * Notify that the current user accesses none-activate module
				 * controller.
				 */
				XCube_DelegateUtils::call('Legacy.Event.ModuleNotActive');
				$this->executeForward(XOOPS_URL);
				die();
			}

   			if (!$this->mModuleController->hasPermission()) {
				$this->executeRedirect(XOOPS_URL . '/',1,_NOPERM);	// TODO Depens on const message catalog.
   			}

			$this->mModuleController->setupLanguage();
			
			$GLOBALS['xoopsModule'] =& $this->mModuleController->mModuleObject;			// TODO
			$GLOBALS['xoopsModuleConfig'] = $this->mModuleController->getConfig();
		}
	}

	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()
	{
		$this->mSiteLogin->call(new XCube_Ref($this->mXoopsUser));
		
		$this->mUser =& new XCube_UserAccount();
		if (is_object($this->mXoopsUser)) {
			$this->mUser->_mId = $this->mXoopsUser->get('uid');	//< FIXME
			$this->mUser->setGuest(false);
			$this->mUser->setService(false);
		}
		else {
			$this->mUser->_mId = 0;	//< FIXME
			$this->mUser->setGuest(true);
			$this->mUser->setService(false);
		}
		
		// Set instance to global variable for compatiblity with XOOPS 2.0.x
		$GLOBALS['xoopsUser'] =& $this->mXoopsUser;
		$GLOBALS['xoopsUserIsAdmin'] = is_object($this->mXoopsUser) ? $this->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);
			}
		}

		$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_BASE_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_BASE_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->mConfig=&$configHandler->getConfigsByCat(XOOPS_CONF);

		$this->setMainTheme($this->mConfig['theme_set']);
	    $this->mConfig['language'] = $this->mRoot->mLanguageManager->getLanguage();
	    
		$GLOBALS['xoopsConfig']=&$this->mConfig;
		$GLOBALS['config_handler'] =& $configHandler;
	}

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

		require_once XOOPS_BASE_PATH . "/class/DebuggerManager.class.php";
		
		$debug_mode = $this->mConfig['debug_mode'];
		if (defined("OH_MY_GOD_HELP_ME")) {
			$debug_mode = XOOPS_DEBUG_PHP;
		}

		$this->mDebugger =& Legacy_DebuggerManager::getInstance($debug_mode);
		$this->mDebugger->prepare();

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

	function _processPreBlockFilter()
    {
		$this->_mStrategy->_processPreBlockFilter();
        parent::_processPreBlockFilter();
    }
	
	function _executeModulePreload($dirname)
	{
		//
		// Auto pre-loading for Module.
		//
		if ($this->mRoot->getSiteConfig('Legacy', 'AutoPreload') == 1) {
            $moduleHandler =& xoops_gethandler('module');
            $moduleObjects =& $moduleHandler->getObjects();
            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)) {
									$instance =& new $className($this);
									$this->addActionFilter($instance);
								}
							}
						}
    			    }
    			}
            }
        }
	}

	function _setupSession()
	{
		global $xoopsDB;

		$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
		//
		$cacheInfo =& $this->mModuleController->createCacheInfo();
		
		$this->mCheckEnableModuleCache->call(new XCube_Ref($cacheInfo));
		
		if ($this->isEnableCacheFeature() && $this->mModuleController->hasCacheConfig()) {
			//
			// Checks whether the cache file exists.
			//
			$xoopsModule =& $this->mModuleController->getXoopsModule();

			$cachetime = $this->mConfig['module_cache'][$xoopsModule->get('mid')];
			$filepath = $this->getModuleCacheFilePath($cacheInfo);
			
			//
			// 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->mModuleController->getDependRenderSystem());
				$renderTarget =& $renderSystem->createRenderTarget(XCUBE_RENDER_TARGET_TYPE_MAIN);
				$renderTarget->setResult($this->loadCache($filepath));
				
				$this->_executeViewTheme($renderTarget);
				
				exit(0);
			}
		}

		ob_start();
	}
	
	/**
	 * @var string $theme
	 */	
	function setMainTheme($theme)
	{
		$this->mMainTheme = $theme;
		$this->mConfig['theme_set'] = $theme;
	}
	
	function executeView()
	{
		$renderSystem =& $this->mRoot->getRenderSystem($this->mModuleController->getDependRenderSystem());
		$renderTarget =& $this->mModuleController->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.
		//
		

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

		// 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->renderWithTarget($renderTarget);

			//
			// Cache Control
			//
			if ($this->isEnableCacheFeature() && $this->mModuleController->hasCacheConfig()) {
				if ($this->mModuleController->mCacheInfo->isEnableCache()) {
					$this->cacheRenderTarget($this->getModuleCacheFilePath($this->mModuleController->mCacheInfo), $renderTarget);
				}
			}
			else {
			}
		}
		
		$this->_executeViewTheme($renderTarget);
	}
	
	/**
	 * $resultRenderTarget object The render target of content's result.
	 */
	function _executeViewTheme(&$resultRenderTarget)
	{
		//
		// Theme Control
		//
		$screenTarget = $this->mDialogMode ? new Legacy_DialogRenderTarget() : new Legacy_ThemeRenderTarget();
		
		if (is_object($resultRenderTarget)) {
			$screenTarget->setAttribute('xoops_contents', $resultRenderTarget->getResult());
		}

		//
		// Get the render-system through theme object.
		//
		$theme =& $this->_mStrategy->getMainThemeObject();

		$renderSystem =& $this->mRoot->getRenderSystem($theme->get('render_system'));
		$screenTarget->setTemplateName($theme->get('dirname'));

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

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

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

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

	function &_createDelegateManager()
	{
		$delegateManager =& parent::_createDelegateManager();
		
		$file = XOOPS_ROOT_PATH . "/modules/base/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/base/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->mXoopsUser)) {
			$this->mCheckLogin->call(new XCube_Ref($this->mXoopsUser));
			
			$this->mRoot->mLanguageManager->loadModuleMessageCatalog('base');

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

				XCube_DelegateUtils::call("Site.CheckLogin.Success", new XCube_Ref($this->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_BASE_MESSAGE_LOGIN_SUCCESS, $this->mXoopsUser->get('uname')));
			}
			else {
				XCube_DelegateUtils::call("Site.CheckLogin.Fail", new XCube_Ref($this->mXoopsUser));
				
				//
				// Fall back process for login fail.
				//
				$this->executeRedirect(XOOPS_URL . "/user.php", 1, _MD_BASE_ERROR_INCORRECTLOGIN);
			}
		}
		else {
			$this->executeForward(XOOPS_URL);
		}
	}
	
	/**
	 * The current user logout.
	 * 
	 * @access public
	 */
	function logout()
	{
		$successFlag = false;
		$xoopsUser =& $this->getXoopsUser();
		
		
		if (is_object($xoopsUser)) {
			$this->mRoot->mLanguageManager->loadModuleMessageCatalog('base');
			
			$this->mLogout->call(new XCube_Ref($successFlag), $xoopsUser);
			if ($successFlag) {
				XCube_DelegateUtils::call("Site.Logout.Success", $xoopsUser);
				$this->executeRedirect(XOOPS_URL . '/', 1, array(_MD_BASE_MESSAGE_LOGGEDOUT, _MD_BASE_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->_setupModuleController();
			$this->_processModuleController();
		}
	}

	function &getXoopsUser()
	{
		return $this->mXoopsUser;
	}

	/**
	 * 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;
	}
	
	/**
	 * Return URL of pm inbox. This is X2 fixed feature.
	 * 
	 * @param $uid int ID of the user
	 * @return string if any functions don't return value, return null.
	 */
	function getPMInboxUrl($uid)
	{
		$url = null;
		$this->mGetPMInboxUrl->call(new XCube_Ref($url), $uid);
		
		return $url;
	}

	/**
	 * Return counts of unread pm. This is X2 fixed feature.
	 * 
	 * @param $uid int ID of the user
	 * @return int
	 */
	function getCountUnreadPM($uid)
	{
		$count = 0;
		$this->mGetCountUnreadPM->call(new XCube_Ref($count), $uid);
		
		return $count;
	}

	/**
	 * 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.
	 * 
	 * @todo We'll change this function to delegate.
	 */
	function executeRedirect($url, $time = 1, $message = null)
	{
		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);
		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('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);
	}
	
	/**
	 * Gets a file path of a cache file for module contents.
	 * @param Legacy_ModuleCacheInformation $cacheInfo
	 * @return string
	 */
	function getModuleCacheFilePath(&$cacheInfo)
	{
		$filepath = null;
		$this->mGetModuleCacheFilePath->call(new XCube_Ref($filepath), $cacheInfo);
		
		if (!$filepath) {
			$id = md5(XOOPS_SALT . $cacheInfo->mURL . "(" . implode("_", $cacheInfo->mIdentityArr) . ")" . implode("_", $cacheInfo->mGroupArr));
			$filepath = XOOPS_CACHE_PATH . "/" . $id . ".cache.html";
		}
		
		return $filepath;
	}

	/**
	 * Gets a file path of a cache file for module contents.
	 * @param Legacy_BlockCacheInformation $cacheInfo
	 * @return string
	 */
	function getBlockCacheFilePath(&$cacheInfo)
	{
		$filepath = null;
		$this->mGetBlockCacheFilePath->call(new XCube_Ref($filepath), $cacheInfo);
		
		if (!$filepath) {
			$id = md5(XOOPS_SALT . $cacheInfo->mBlock->get('bid') . "(" . implode("_", $cacheInfo->mIdentityArr) . ")" . implode("_", $cacheInfo->mGroupArr));
			$filepath = XOOPS_CACHE_PATH . "/" . $id . ".cache.html";
		}
		
		return $filepath;
	}

	/**
	 * 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;
	}
}

/**
 * @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)) {
					$filter =& new $className($this->mController);
					$this->mController->addActionFilter($filter);
					unset($filter);
				}
			}
		}

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

	/**
	 * Create a instance of ModuleController, and set it to mModuleController
	 * property of $controller.
	 * 
	 * @param $controller Legacy_Controller
	 */
	function setupModuleController()
	{
	}

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

	/**
	 * @return XoopsModule
	 * @see Legacy_Controller::getVirtualCurrentModule()
	 */	
	function &getVirtualCurrentModule()
	{
		$ret = null;
		return $ret;
	}
	
	function &getMainThemeObject()
	{
	}

	/**
	 * Gets a value indicating whether the controller can use a cache mechanism.
	 */	
	function isEnableCacheFeature()
	{
	}
}

class Legacy_PublicControllerStrategy extends Legacy_AbstractControllerStrategy
{
	var $mStatusFlag = LEGACY_CONTROLLER_STATE_PUBLIC;
	
	function Legacy_PublicControllerStrategy(&$controller)
	{
		parent::Legacy_AbstractControllerStrategy($controller);
		
		if (!defined("LEGACY_DEPENDENCE_RENDERER")) {
			define("LEGACY_DEPENDENCE_RENDERER", "Legacy_RenderSystem");
		}
	}

	function setupModuleController()
	{
		require_once XOOPS_BASE_PATH . "/kernel/Legacy_ModuleController.class.php";
		$this->mController->mModuleController =& new Legacy_ModuleController($this->mController);
	}

	function setupBlock()
	{
		$showFlag =0;
		$mid=0;

		if($this->mController->mModuleController->isModuleProcess()) {
			$showFlag = (preg_match("/index\.php$/i", xoops_getenv('PHP_SELF')) && $this->mController->mConfig['startpage'] == $this->mController->mModuleController->mModuleObject->getVar('dirname'));
			$mid = $this->mController->mModuleController->mModuleObject->getVar('mid');
		}
		else {
			//
			// If you does not have module_contoller, this request is to toppage or other pages of toppage.
			//
			$mid = preg_match("/index\.php$/i", xoops_getenv('PHP_SELF')) ? -1 : 0;
		}

        $blockHandler =& xoops_gethandler('block');
		$showCenterFlag = (SHOW_CENTERBLOCK_LEFT | SHOW_CENTERBLOCK_CENTER | SHOW_CENTERBLOCK_RIGHT);
		$showRightFlag = SHOW_SIDEBLOCK_RIGHT;
		$showFlag = SHOW_SIDEBLOCK_LEFT | $showRightFlag | $showCenterFlag;
		$groups = is_object($this->mController->mXoopsUser) ? $this->mController->mXoopsUser->getGroups() : XOOPS_GROUP_ANONYMOUS;

		$blockObjects=&$blockHandler->getBlocks($groups, $mid, $showFlag);
		foreach($blockObjects as $blockObject) {
			$this->mController->mBlockChain[] =& new Legacy_AdaptBlockProcedure($blockObject);
			unset($blockObject);
		}
	}

	function &getMainThemeObject()
	{
		// [TODO]
		// Because get() of the virtual handler is heavy, we have to consider
		// the new solution about this process.
		//
		$handler =& xoops_getmodulehandler('theme', 'base');
		$theme =& $handler->get($this->mController->getMainTheme());
		
		return $theme;
	}
	
	function isEnableCacheFeature()
	{
		return true;
	}
}

class Legacy_AdminControllerStrategy extends Legacy_AbstractControllerStrategy
{
	var $mStatusFlag = LEGACY_CONTROLLER_STATE_ADMIN;
	
	/**
	 * @var XCube_Delegate
	 * @param XCube_Controller &$controller
	 */
	var $mSetupBlock = null;
	
	/**
	 *  If this array includes current action, getVirtualCurrentModule() returns
	 * the module object that specified by dirname.
	 * 
	 * @access private
	 */
	var $_mSpecialActions = array("Help", "CommentList");

	function Legacy_AdminControllerStrategy(&$controller)
	{
		global $xoopsOption;
		
		parent::Legacy_AbstractControllerStrategy($controller);
		
		//
		// TODO We have to develop complated-switching-controller-mechanizm.
		//
		if (!defined("LEGACY_DEPENDENCE_RENDERER")) {
			define("LEGACY_DEPENDENCE_RENDERER", "Legacy_AdminRenderSystem");
		}

		//
		// Cover the spec of admin.php of the system module, for the compatibility.
		//
		if (isset($_REQUEST['fct']) && $_REQUEST['fct'] == "users") {
			$GLOBALS['xoopsOption']['pagetype'] = "user";
		}		
		
		$this->mSetupBlock =& new XCube_Delegate();
		$this->mSetupBlock->register('Legacy_AdminControllerStrategy.SetupBlock');
	}

	function _setupFilterChain()
	{
		parent::_setupFilterChain();

		//
		// Auto pre-loading.
		//
		if($this->mController->mRoot->getSiteConfig('Legacy', 'AutoPreload') == 1) {
			$this->mController->_executePreload(XOOPS_ROOT_PATH . "/preload/admin");
		}
	}
	
	function setupModuleController()
	{
		require_once XOOPS_BASE_PATH . "/kernel/Legacy_AdminModuleController.class.php";
		$this->mController->mModuleController =& new Legacy_AdminModuleController($this->mController);
	}

	function setupBlock()
	{
		require_once XOOPS_BASE_PATH . "/admin/blocks/AdminActionSearch.class.php";
		require_once XOOPS_BASE_PATH . "/admin/blocks/AdminSideMenu.class.php";
		$this->mController->mBlockChain[] =& new Legacy_AdminActionSearch();
		$this->mController->mBlockChain[] =& new Legacy_AdminSideMenu();
		
		$this->mSetupBlock->call(new XCube_Ref($this->mController));
	}

	function _processPreBlockFilter()
	{
		parent::_processPreBlockFilter();
		$this->mController->_executeModulePreload('/admin/preload/');
	}

	function &getVirtualCurrentModule()
	{
		$module = null;
		
		if ($this->mController->mModuleController->isModuleProcess()) {
			$module =& $this->mController->mModuleController->getXoopsModule();
			
			if ($module->get('dirname') == "base" && isset($_REQUEST['dirname'])) {
				if (in_array(xoops_getrequest('action'), $this->_mSpecialActions)) {
					$handler =& xoops_gethandler('module');
					$module =& $handler->getByDirname(xoops_getrequest('dirname'));
				}
			}
			elseif ($module->get('dirname') == "base" && xoops_getrequest('action') == 'PreferenceEdit' && isset($_REQUEST['confmod_id'])) {
				$handler =& xoops_gethandler('module');
				$module =& $handler->get(intval(xoops_getrequest('confmod_id')));
			}
		}

		return $module;
	}

	function &getMainThemeObject()
	{
		$handler =& xoops_getmodulehandler('theme', 'base');
		$theme =& $handler->create();
		
		//
		// TODO Load manifesto here.
		//
		$theme->set('dirname', $this->mController->mRoot->mSiteConfig['Legacy']['Theme']);
		$theme->set('render_system', 'Legacy_AdminRenderSystem');
		
		return $theme;
	}
	
	function isEnableCacheFeature()
	{
		return false;
	}
}

?>