<?php
/**
 * MiniMVC
 *
 * Convention-based micro-framework for PHP
 *
 * @author 		Timothy J. Warren
 * @copyright	Copyright (c) 2011 - 2012
 * @link 		https://github.com/timw4mail/miniMVC
 * @license 	http://philsturgeon.co.uk/code/dbad-license 
 */

// --------------------------------------------------------------------------

/**
 * File including common framework-wide functions
 */
 
// --------------------------------------------------------------------------

/**
 * Function to run on script shutdown
 * -used to catch most fatal errors, and 
 * display them cleanly
 */
function shutdown()
{
    // Catch the last error
    $error = error_get_last();

    // types of errors that are fatal
    $fatal = array(E_ERROR, E_PARSE, E_RECOVERABLE_ERROR);

    // Display pretty error page
    if(in_array($error['type'], $fatal))
    {
        $file = str_replace(BASE_PATH, "", $error['file']);
        
        $err_msg = <<<TXT
<h2>Fatal Error: </h2>
{$error['message']}<br /><br />
<strong>File:</strong> {$file}<br /><br />
<strong>Line:</strong> {$error['line']}
TXT;
        show_error($err_msg);
    }
}

// --------------------------------------------------------------------------

/**
 * Function to search through the tree to find the necessary file
 *
 * @param string $file
 * @param string $curr_path
 * @return void
 */
function load_file($file, $curr_path="")
{
	$path = "";

	if($curr_path === "app")
	{
		$path = APP_PATH."{$file}.php";
	}
	else if($curr_path === "sys")
	{
		$path = SYS_PATH."{$file}.php";
	}
	else
	{
		$path = MOD_PATH."{$curr_path}/{$file}.php";
	}
	
	if(is_file($path))
	{
		require_once($path);
	}
}


// --------------------------------------------------------------------------

/**
 * Custom error handler
 */
function on_error($severity, $message, $filepath, $line, $context)
{
	$levels = array(
		E_ERROR				=>	'Error',
		E_WARNING			=>	'Warning',
		E_PARSE				=>	'Parsing Error',
		E_NOTICE			=>	'Notice',
		E_CORE_ERROR		=>	'Core Error',
		E_CORE_WARNING		=>	'Core Warning',
		E_COMPILE_ERROR		=>	'Compile Error',
		E_COMPILE_WARNING	=>	'Compile Warning',
		E_USER_ERROR		=>	'User Error',
		E_USER_WARNING		=>	'User Warning',
		E_USER_NOTICE		=>	'User Notice',
		E_STRICT			=>	'Strict Error'
	);

    //Make it prettier
    $message = highlight_string($message, TRUE);
    $filepath = str_replace(BASE_PATH, "", $filepath);

	$severity = (isset($levels[$severity])) ? $levels[$severity] : $severity;

	// Contain the content for buffering
	ob_start();
	
	include(APP_PATH.'/errors/error_php.php');
	
	$buffer = ob_get_contents();
	ob_end_clean();
	echo $buffer;
}

// --------------------------------------------------------------------------

/**
 * Custom exception handlererror_get_last
 */
function on_exception($exception)
{
	$message = $exception->getMessage();

	//$filepath = str_replace(BASE_PATH, "", $filepath);
	 
	// Contain the content for buffering
	ob_start();
	
	include(APP_PATH.'/errors/error_php_exception.php');
	
	$buffer = ob_get_contents();
	ob_end_clean();
	echo $buffer;
}

// --------------------------------------------------------------------------

/**
 * Utility function to check if a variable is set, and is an array or object
 *
 * @param mixed $var
 * @return bool
 */
function is_like_array(&$var)
{
	if( ! isset($var))
	{
		return FALSE;
	}

	return (is_array($var) OR is_object($var)) && ( ! empty($var));
}

// --------------------------------------------------------------------------

/**
 * General 404 function
 */
function show_404()
{
	@header('HTTP/1.1 404 Not Found', TRUE, 404);
	die('<h1>404 Not Found</h1>');
}

// --------------------------------------------------------------------------

/**
 * Fatal Error page function
 * 
 * @param string $message
 * @param int $status_code
 */
function show_error($message, $status_code=null)
{
	if( ! is_null($status_code))
	{
		@header("HTTP/1.1 {$status_code}", TRUE, (int)$status_code);
	}

	// Contain the content for buffering
	ob_start();
	
	include(APP_PATH.'/errors/error_general.php');
	
	$buffer = ob_get_contents();
	ob_end_clean();
	die($buffer);
}

// --------------------------------------------------------------------------

/**
 * Returns routable methods for the specified controller class
 *
 * @param string $controller
 * @return array
 */
function controller_methods($controller)
{
	$methods = get_class_methods($controller);
	$num = count($methods);
	
	for($i=0; $i < $num; $i++)
	{
		$skip_methods = array(
			'load_file',
			'on_error',
			'on_exception',
			'show_404',
			'show_error',
			'controller_methods',
			'route',
			'site_url',
			'load_view',
			'get_instance',
		);
	
		// If the method starts with an underscore, or
		// is in the blacklist of methods, it is not callable
		if($methods[$i]{0} === "_" || in_array($methods[$i], $skip_methods))
		{
			unset($methods[$i]);
		}
	}

	return $methods;
}

// --------------------------------------------------------------------------

/**
 * Calls the appropriate module/controller/function based on the url
 */
function route()
{
	$pi = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : null;

	// Load the routes config file
	$routes = require_once(APP_PATH.'config/routes.php');

	// Set the default route
	$module = $routes['default_module'];
	$controller = $routes['default_controller'];
	$func = "index";
	$route_set = FALSE;
    
    // If it isn't the index page
	if( ! empty($pi) && $pi !== "/")
	{
		//Remove trailing slash and begining slash
		$pi = trim($pi, '/');
	
		// URL matches the route exactly? Cool, that was easy
		if(isset($routes[$pi]))
		{
			list($module, $controller, $func) = explode("/", $routes[$pi]);
			$route_set = TRUE;
		}
		else
		{
			$custom_routes = $routes;
			
			// Skip required routes
			unset($custom_routes['default_module']);
			unset($custom_routes['default_controller']);
			unset($custom_routes['404_handler']);
		
			foreach($custom_routes as $uri => $map)
			{
				if(preg_match("`{$uri}`i", $pi))
				{
					list($module, $controller, $func) = explode("/", $map);
					$route_set = TRUE;
					break;
				}
			}
		}
		
		// Doesn't match a predefined route? 
		// Match on module/controller/method, controller/method, or method
		if( ! $route_set)
		{
			$num_segments = 0;
		
			if(strpos($pi, '/') === FALSE  &&  ! empty($pi))
			{
				$num_segments = 1;
			}
			else
			{
				$segments = explode('/', $pi);
				$num_segments = count($segments);
			}
			
			if($num_segments === 1)
			{
				$func = $pi;
			}
			
			if($num_segments === 2)
			{
				list($controller, $func) = $segments;
			}
			
			if($num_segments >= 3)
			{
				list($module, $controller, $func) = $segments;
			}
		}
	}
	
	$path = MOD_PATH."{$module}/controllers/{$controller}.php";
	
	if(is_file($path))
	{
		require_once($path);
		
		// Get the list of valid methods for that controller
		$methods = controller_methods($controller);
		
		if(in_array($func, $methods))
		{
			$class = new $controller;
			
			return call_user_func(array($class, $func));
		}

        // Function doesn't exist...404
		show_404();
		die();
	}
	
	// If it gets here, it's still a 404
	show_404();
}

// --------------------------------------------------------------------------

/**
 * Returns a full url from a url segment
 *
 * @param string $segment
 * @return string
 */
function site_url($segment)
{
	return $url = BASEURL . URL_INDEX_FILE . $segment;
}

// --------------------------------------------------------------------------

/**
 * Wrapper function to simplify using curl
 *
 * @param string $url
 * @param array $options
 * @return mixed
 */
function do_curl($url, $options=array())
{
	$cookie = tempnam ("/tmp", "CURLCOOKIE");
	$ch = curl_init($url);
	
	//Use the user's User Agent and Cookies
	$opts= array(
		CURLOPT_USERAGENT => $_SERVER['HTTP_USER_AGENT'],
		CURLOPT_COOKIEJAR => $cookie,
		CURLOPT_FOLLOWLOCATION => TRUE,
		CURLOPT_ENCODING => "",
		CURLOPT_RETURNTRANSFER => TRUE,
		CURLOPT_AUTOREFERER => TRUE,
		CURLOPT_SSL_VERIFYPEER => FALSE,
		CURLOPT_CONNECTTIMEOUT => 10,
		CURLOPT_TIMEOUT => 10,
		CURLOPT_MAXREDIRS => 10,
		CURLOPT_PROTOCOLS => array(CURLPROTO_HTTP,CURLPROTO_HTTPS)
	);
	
	//Set default options
	curl_setopt_array($ch, $opts);
	
	//Set additional options
	curl_setopt_array($ch, $options);
	
	return curl_exec($ch);
}

// --------------------------------------------------------------------------

// Load Most Common libraries
require_once('miniMVC.php');
require_once('output.php');
require_once('page.php');
require_once('db.php');
require_once('r.php');

// End of common.php