<?php
/**
* Is the Ctrl defined
*/
define('CTRL',true);
/**
* What is the ctrl version 
*/
define('CTRL_VERSION','2.0');
/**
* System directory handler can use to access system directory 
* <code>
* using('System.Web.UI.HtmlControls');
* </code>
*/
define('SYSTEM','System');
/**
* Class extention parameter, i think .php is good extention
*/
define('CLASS_EXT',			'.php'); 
/**
*Current system application location
*/
define('SYSTEM_PATH',		dirname(__FILE__));
/**
* Document root where is the other dirs and files
*/
define('DOCUMENT_ROOT',		$_SERVER['DOCUMENT_ROOT']);
/**
* Determing operating system
*/
if (substr(PHP_OS, 0, 3) == 'WIN') 
{
    define('OS_WINDOWS', true);
    define('OS_UNIX',    false);
    define('OS',    	'Windows');
	define('INCLUDE_PATH_SEPARATOR', ';');
}
else 
{
    define('OS_WINDOWS', false);
    define('OS_UNIX',    true);
    define('OS',    	'Unix'); // blatant assumption
	define('INCLUDE_PATH_SEPARATOR', ':');
}
/**
* All errors to show
*/
error_reporting(E_ALL);
/**
* New controlled error handler
*/
set_error_handler('ctrl_error_handler');
/**
 * Error handler.
 * This method is invoked by PHP when an error happens.
 * It displays the error if the application state is in debug;
 * otherwise, it saves the error in log.
 */
function ctrl_error_handler($errno, $errstr, $errfile, $errline) 
{
	switch($errno)
	{
		case E_USER_ERROR:
			echo '<h1>User Error</h1>';
			$msg = utf8_encode("$errstr (@line $errline in file $errfile).");
			ctrl_fatal_error($msg);
		break;
		case E_USER_WARNING:
			echo '<h1>User Warning</h1>';
			echo utf8_encode("$errstr (@line $errline in file $errfile).");
		break;
		case E_USER_NOTICE:
			echo '<h1>User Notice</h1>';
			echo utf8_encode("$errstr.");
		break;
		default:
			echo '<h1>Fatal Error</h1>';
			$msg=utf8_encode("[$errno] $errstr (@line $errline in file $errfile).");
			ctrl_fatal_error($msg);
		break;
	}
}
/**
 * Fatal error handler.
 * This method is used in places where exceptions usually cannot be raised
 * (e.g. magic methods).
 * It displays the debug backtrace if the application state is in debug;
 * otherwise, only error message is displayed.
 * @param string error message
 */
function ctrl_fatal_error($msg)
{
	echo '<p>'.$msg.'</p>';
	if(!function_exists('debug_backtrace'))
	{ 
		return; 
	}
	echo '<h2>Debug Backtrace</h2>';
	echo '<pre>';
	$index=-1;
	$backtrace = debug_backtrace();
	foreach($backtrace as $trace) 
	{
		$index++;
		if($index==0)
		{  // hide the backtrace of this function
			continue;
		}
		echo '#'.$index.' ';
		if(isset($trace['file']))
		{
			echo basename($trace['file']) . ':' . $trace['line']; 
		}
		else 
		{
		   echo '<PHP inner-code>'; 
		}
		echo ' -- '; 
		if(isset($trace['class']))
		{
			echo $trace['class'] . $trace['type']; 
		}
		echo $trace['function']; 
		if(isset($trace['args']) && sizeof($trace['args']) > 0) 
		{
			echo '(...)'; 
		}
		else 
		{
			echo '()'; 
		}
		echo PHP_OS."\n";
	}
	echo '</pre>';
	exit;
}
/**
* If class is called out first time then first require a file
* If u call out new class object then it will run it here
* It calls out function using that searches the class file from predefined directories
* {@source}
*/
if(!function_exists("__autoload"))
{ 
	function __autoload($class_name) 
	{
		import($class_name);
	}
}
/**
* Returns the include paths
* @return array of inluce_path
*/
function get_include_paths_array()
{
	$include_path = ini_get('include_path');
	return explode(INCLUDE_PATH_SEPARATOR, $include_path);	
}
/**
* Translates the path system.ui.web to system/ui/web
* If the string contains System then it will be replaced with the document root
* @param string 
* @returs string of directory
*/
function translate_ctrl_path($path)
{
	$dir = str_replace('.',DIRECTORY_SEPARATOR,$path);
	/*
	* If the path consist System then replace it with document root path
	*/
	if(strstr($path,SYSTEM) === false)
	{
		$dir = str_replace('/',DIRECTORY_SEPARATOR,$dir);
		$document_root = str_replace('/',DIRECTORY_SEPARATOR,DOCUMENT_ROOT);// change all / directory separators
		if(substr($dir,-1) == DIRECTORY_SEPARATOR)
		{
			$dir = $dir;
		}
		else
		{
			$dir = $document_root.DIRECTORY_SEPARATOR.$dir;
		}
	}
	else
	{
		$dir = str_replace(SYSTEM,SYSTEM_PATH,$dir);
	}
	return $dir;
}
/**
* Can we find file from include paths
* @paramr string file name
* @return boolean true|false
*/
function is_file_exists($file)
{
	$paths = get_include_paths_array();
	/**
	* Search for the file
	*/
	foreach($paths as $path)
	{
		if(is_file($path.DIRECTORY_SEPARATOR.$file))
		{
			return true;
		}
	}
	return false;
}
/**
* Loads the class file
* @param class name
* @return if require succeeded true|false
*/
function import($className)
{
	$namespaces = get_include_paths_array();
	// if class allready exists
	if(class_exists($className,false))
	{
		return true;	
	}
	$filename = $className.CLASS_EXT;
	if(is_file_exists($filename))
	{
		require_once($filename);
		return true;
	}
	return false;
}
/**
* Sets predefined direcotryes from where to require files
* Searches the class file from the predefined directories
* Can use System directory where is the frameworks source.
* Other directorys wil used DOCUMENT_ROOT
* @param string path name to include
* @return boolean true|false
* <code>
* using('Dir.Second.Third');// will use directory as /Dir/Second/Third on Unix or C:\Dir\Second\Third in Windows
* </code>
*/
function using($name)
{
	if(!$name)
	{
		return false;
	}
	$namespaces = get_include_paths_array();
	/**
	* Allready defined namespace
	*/
	if(in_array($name,$namespaces))
	{
		return true;
	}
	else
	{
		$path = translate_ctrl_path($name);
		if(is_dir($path))
		{
			ini_set('include_path',ini_get('include_path').INCLUDE_PATH_SEPARATOR.$path);
			return true;
		}
		elseif(is_file($path.CLASS_EXT))
		{
			require_once($path.CLASS_EXT);
			return true;
		}
		else
		{
			trigger_error('The namespace is invalid: '.$path, E_USER_ERROR);
		}
	}
}
/**
* Ctrl singleton
* @date 9.03.2007
* @name Ctrl
* @author Margo Poolak <margo 'dot' poolak 'at' mail 'dot' ee>
* @copyright Copyright &copy;2007 Margo Poolak. All Rights Reserved.
* @version 2.0
* @package System
* @category 
* @static
* Static methods
* Usage of this Ctrl is simple
* <code>
* <?php
* require_once('../Ctrl.php');
* Ctrl::run();
* ?>
* </code>
*/
class Ctrl
{
	/**
	* @static
	* @var string application
	* @access private
	*/
	private static $_application;
	private static $_trace = array();
	/**
	* Construct must be protected
	* @access protected
	*/
	protected function __construct()
	{
	}
	/**
	* Runs the application
	* @static
	*/
	public static function run()
	{
		self::getApplication()->run();
	}
	/**
	* Sets application only once
	* @static
	* @param object application
	* @return null;
	*/
	public static function setApplication(CtrlApplication $app)
	{
		if(isset(self::$_application))
		{
			trigger_error('The applicatin is allready set', E_USER_ERROR);
		}
		self::$_application = $app;
	}
	/**
	* If the application is not set then it will be triggered
	* @static
	* @return object the application
	*/
	public static function getApplication()
	{
		if(!isset(self::$_application))
		{
			return new CtrlApplication();
		}
		else
		{
			return self::$_application;
		}
	}
	/*
	* Trace the log
	* @static
	* @param string message
	*/
	public static function trace($msg = '')
	{
		if($msg == '')
		{
			return self::$_trace;
		}
		else
		{
			self::$_trace[] = $msg;
		}
	}
}
/**
* Using namespaces
*/
using('System');
using('System.Web');
using('System.Web.UI');
?>