<?php
/*****************************************************************************
 * Dispatcher.php
 * Contains key class Dispatcher.
 *
 * Kabuki CMS (C) 2013-2015, Aaron van Geffen
 *****************************************************************************/

class Dispatcher
{
	public static function route()
	{
		$possibleActions = [
			'albums' => 'ViewPhotoAlbums',
			'editasset' => 'EditAsset',
			'edituser' => 'EditUser',
			'login' => 'Login',
			'logout' => 'Logout',
			'managecomments' => 'ManageComments',
			'manageerrors' => 'ManageErrors',
			'managetags' => 'ManageTags',
			'manageusers' => 'ManageUsers',
			'people' => 'ViewPeople',
			'resetpassword' => 'ResetPassword',
			'suggest' => 'ProvideAutoSuggest',
			'timeline' => 'ViewTimeline',
			'uploadmedia' => 'UploadMedia',
		];

		// Work around PHP's FPM not always providing PATH_INFO.
		if (empty($_SERVER['PATH_INFO']) && isset($_SERVER['REQUEST_URI']))
		{
			if (strpos($_SERVER['REQUEST_URI'], '?') === false)
				$_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'];
			else
				$_SERVER['PATH_INFO'] = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
		}

		// Nothing in particular? Just show the root of the album list.
		if (empty($_SERVER['PATH_INFO']) || $_SERVER['PATH_INFO'] == '/')
		{
			return new ViewPhotoAlbum();
		}
		// An album, person, or any other tag?
		elseif (preg_match('~^/(?<tag>.+?)(?:/page/(?<page>\d+))?/?$~', $_SERVER['PATH_INFO'], $path) && Tag::matchSlug($path['tag']))
		{
			$_GET = array_merge($_GET, $path);
			return new ViewPhotoAlbum();
		}
		// Look for an action...
		elseif (preg_match('~^/(?<action>[a-z]+)(?:/page/(?<page>\d+))?/?~', $_SERVER['PATH_INFO'], $path) && isset($possibleActions[$path['action']]))
		{
			$_GET = array_merge($_GET, $path);
			return new $possibleActions[$path['action']]();
		}
		else
			throw new NotFoundException();
	}

	public static function dispatch()
	{
		// Let's try to find our bearings!
		try
		{
			$page = self::route();
			$page->showContent();
		}
		// Something wasn't found?
		catch (NotFoundException $e)
		{
			self::trigger404();
		}
		// Or are they just sneaking into areas they don't belong?
		catch (NotAllowedException $e)
		{
			if (Registry::get('user')->isGuest())
				self::kickGuest();
			else
				self::trigger403();
		}
		catch (UserFacingException $e)
		{
			$debug_info = ErrorHandler::getDebugInfo($e->getTrace());
			ErrorHandler::display($e->getMessage(), $debug_info, false);
		}
		catch (Exception $e)
		{
			ErrorHandler::handleError(E_USER_ERROR, 'Unspecified exception: ' . $e->getMessage(), $e->getFile(), $e->getLine());
		}
		catch (Error $e)
		{
			ErrorHandler::handleError(E_USER_ERROR, 'Fatal error: ' . $e->getMessage(), $e->getFile(), $e->getLine());
		}
	}

	/**
	 * Kicks a guest to a login form, redirecting them back to this page upon login.
	 */
	public static function kickGuest()
	{
		$form = new LogInForm('Log in');
		$form->adopt(new Alert('', 'You need to be logged in to view this page.', 'error'));
		$form->setRedirectUrl($_SERVER['REQUEST_URI']);

		$page = new MainTemplate('Login required');
		$page->appendStylesheet(BASEURL . '/css/admin.css');
		$page->adopt($form);
		$page->html_main();
		exit;
	}

	public static function trigger400()
	{
		header('HTTP/1.1 400 Bad Request');
		$page = new MainTemplate('Bad request');
		$page->adopt(new DummyBox('Bad request', '<p>The server does not understand your request.</p>'));
		$page->html_main();
		exit;
	}

	public static function trigger403()
	{
		header('HTTP/1.1 403 Forbidden');
		$page = new MainTemplate('Access denied');
		$page->adopt(new DummyBox('Forbidden', '<p>You do not have access to the page you requested.</p>'));
		$page->html_main();
		exit;
	}

	public static function trigger404()
	{
		header('HTTP/1.1 404 Not Found');
		$page = new MainTemplate('Page not found');

		if (Registry::has('user') && Registry::get('user')->isAdmin())
		{
			$page->appendStylesheet(BASEURL . '/css/admin.css');
			$page->adopt(new AdminBar());
		}

		$page->adopt(new DummyBox('Well, this is a bit embarrassing!', '<p>The page you requested could not be found. Don\'t worry, it\'s probably not your fault. You\'re welcome to browse the website, though!</p>', 'errormsg'));
		$page->addClass('errorpage');
		$page->html_main();
		exit;
	}
}