<?php
/**
 * @package XCube
 * @version $Id: XCube_Controller.class.php,v 1.1.2.15 2006/08/21 09:52:12 minahito Exp $
 */

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

require_once XOOPS_ROOT_PATH . "/class/XCube_ActionFilter.class.php";
require_once XOOPS_ROOT_PATH . "/class/XCube_BlockProcedure.class.php";
require_once XOOPS_ROOT_PATH . "/class/XCube_RenderSystem.class.php";
require_once XOOPS_ROOT_PATH . "/kernel/XCube_Delegate.class.php";

/**
 * Virtual front controller class
 */
class XCube_Controller
{
	var $mRoot;

	var $mBlockChain = array();
	var $mFilterChain = array();
	
	/**
	 * XoopsLogger Instance
	 * @access protected
	 */
	var $mLogger;
	
	/**
	 * XoopsErrorHandler instance
	 * @access protected
	 */
	var $mErrorHandler;


	/**
	 * Database instance
	 * @access protected
	 */
	var $mDB;
	
	/**
	 * Array
	 * @access protected
	 */
	var $mConfig;
	
	var $mDebugger;
	
	var $mUser;


	/**
	 * @access public
	 */
	var $mLanguage;

	var $mRenderSystem;
	
	/**
	 * Instance to implement the action process of this controller
	 * @access private
	 */
	var $mActionStrategy = null;

	/**
	 * @var string or object
	 */	
	var $mMainTheme = null;

	function XCube_Controller()
	{
		$this->mBlockChain=array();
		$this->mFilterChain=array();
	}
	
	function prepare(&$root)
	{
		$this->mRoot=&$root;
		
		$this->mRoot->setDelegateManager($this->_createDelegateManager());
		$this->mRoot->setServiceManager($this->_createServiceManager());
	}

	/**
	 * This member function is actual initialize process of web application.
	 * Some Nuke-like bases call this function at any timing.
	 *
	 * @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->_setupRenderSystem();

		$this->_processModuleController();
	}
	
	/**
	 * Create filter chain.
	 * @access protected
	 */
	function _setupFilterChain()
	{
	}

	function addActionFilter(&$filter)
	{
		$this->mFilterChain[]=&$filter;
	}

	/**
	 * Create the instance of XoopsErrorHandler class, and set it to member property.
	 * @access protected
	 */
	function _setupErrorHandler()
	{
	}

	function _setupEnvironment()
	{
	}
	
	/**
	 * Create the instance of XoopsLogger class, and set it to member property.
	 * @access private
	 */
	function _setupLogger()
	{
	}
	
	/**
	 * Create the instance of DataBase class, and set it to member property.
	 * @access protected
	 */
	function _setupDB()
	{
	}
	
	/**
	 * @access public
	 */
	function &getDB()
	{
		return $this->mDB;
	}

	function _setupLanguage()
	{
	}
	
	function _setupConfig()
	{
	}

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

	function &_createLanguageManager()
	{
		require_once XOOPS_ROOT_PATH."/class/XCube_LanguageManager.class.php";
		$languageManager=new XCube_LanguageManager($this->mConfig['language']);
		return $languageManager;
	}

	/**
	 * We need this method really??
	 */
	function _processHostAbstractLayer()
	{
	}

	/**
	 * Setup handler for session, then start session.
	 * @return void
	 */
	function _setupSession()
	{
	}
	
	function _setupUser()
	{
	}
	
	function _setupModuleController()
	{
	}
	
	/**
	 * Return module controller.
	 * @return XCube_ModuleController
	 */
	function &getModuleController()
	{
		return $this->mModuleController;
	}
	
	/**
	 * @return bool We have to return boolean in this method really??
	 * @todo move this method to Base_Controller
	 */
	function _processModuleController()
	{
	}

	/**
	 * Return logger instance.
	 * @return Object
	 */
	function &getLogger()
	{
		return $this->mLogger;
	}
	

	/**
	 * Return logger instance.
	 * @return XoopsErrorHandler
	 */
	function &getErrorHandler()
	{
		return $this->mErrorHandler;
	}


	/**
	 * Usually this member function is called after executeCommon(). But, some
	 * cases don't call this. Therefore, the page controller type base should
	 * not write the indispensable code here. For example, this is good to call
	 * blocks.
	 *
	 * @return void
	 */
	function executeHeader()
	{
		$this->_setupBlock();
		$this->_processBlock();
	}

	/**
	 * This method only show you the concept process of this system.
	 * @return void
	 */
	function execute()
	{
		// $this->executeCommon();
		// $this->executeHeader();
	}
	
	function getConfig($id=null)
	{
		if($id) {
			return $this->mConfig[$id];
		}
		else {
			return $this->mConfig;
		}
	}
	
	
	function _processFilter()
	{
		for ($i = 0; $i < count($this->mFilterChain); $i++) {
			$this->mFilterChain[$i]->preFilter();
		}
	}
	
	function _setupBlock()
	{
	}

	function _processBlock()
	{
		$i=0;
		foreach($this->mBlockChain as $blockProcedure) {
			$blockProcedure->execute($this,$this->getUser());
			if($blockProcedure->hasResult()) {
				$this->mRenderSystem->renderBlock($blockProcedure);
			}
			unset($blockProcedure);
		}
	}

	function _processPreBlockFilter()
	{
		for ($i = 0; $i < count($this->mFilterChain); $i++) {
			$this->mFilterChain[$i]->preBlockFilter();
		}
	}
	
	function _processPostFilter()
	{
		foreach (reverse(array_keys($this->mFilterChain)) as $key) {
			$this->mFilterChain[$key]->postFilter();
		}
	}
	
	/**
	 * Create an instance of delegate manager and return it.
	 * 
	 * @return XCube_DelegateManager
	 */
	function &_createDelegateManager()
	{
		$delegateManager =& new XCube_DelegateManager();
		return $delegateManager;
	}

	function &_createServiceManager()
	{
		require_once XOOPS_ROOT_PATH . "/class/XCube_ServiceManager.class.php";
		$serviceManager =& new XCube_ServiceManager();
		return $serviceManager;
	}

	function &getDebugger()
	{
		return $this->mDebugger;
	}
	
	/**
	 * Set the main theme.
	 * 
	 * [Notice]
	 * Some of sub-classes of XCube_Controller may use object to specify theme.
	 * So this class uses references.
	 * 
	 * @var string or object
	 */
	function setMainTheme(&$theme)
	{
		$this->mMainTheme =& $theme;
	}
	
	/**
	 * Return the main theme.
	 * 
	 * @return string or object
	 * @see XCube_Controller::setMainTheme()
	 */
	function &getMainTheme()
	{
		return $this->mMainTheme;
	}
	
	function executeView()
	{
	}
	
	function setActionStrategy(&$actionStrategy)
	{
		$this->mActionStrategy=&$actionStrategy;
		$this->mActionStrategy->prepare($this);
	}

	/**
	 * @access protected
	 */
	function _processAction()
	{
		if($this->mActionStrategy!==null)	// is_object
			$this->mActionStrategy->execute($this);
	}
	
	function executeAction()
	{
		$this->_processAction();
	}
	
	/**
	 * TODO We may change this name to forward()
	 */
	function executeForward($url, $time = 0, $message = null)
	{
		// check header output
		header("location: " . $url);
		exit();
	}

	/**
	 * Redirect to the specified URL with displaying message.
	 * 
	 * @param string  $url      Can't use html tags.
	 * @param int     $time
	 * @param string  $message
	 */
	function executeRedirect($url, $time = 1, $message = null)
	{
		$this->executeForward($url, $time, $message);
	}

	/**
	 * This is utility member function for the sub-class controller. Load files
	 * with the rule from $path, and add the instance of the sub-class to the
	 * chain.
	 *
	 * @access protected
	 * @param $path string Absolute path.
	 */
	function _executePreload($path)
	{
		$path = $path . "/";
		
		if (is_dir($path)) {
			if ($handler = opendir($path)) {
				while (($file = readdir($handler)) !== false) {
					if (preg_match("/(\w+)\.class\.php/", $file, $matches)) {
						require_once $path . $file;
						$className = $matches[1];
						
						if (class_exists($className)) {
							$instance =& new $className($this);
							$this->addActionFilter($instance);
						}
					}
				}
				closedir($handler);
			}
		}
	}
}

?>