<?php

use Typemill\Events\OnSettingsLoaded;
use Typemill\Events\OnPluginsLoaded;
use Typemill\Events\OnSessionSegmentsLoaded;
use Typemill\Events\OnRolesPermissionsLoaded;
use Typemill\Events\OnResourcesLoaded;

/****************************
* HIDE ERRORS BY DEFAULT	  *
****************************/

ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(E_ALL);

/****************************
* CREATE EVENT DISPATCHER	*
****************************/

$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();

/************************
* LOAD SETTINGS			*
************************/

$settings = Typemill\Settings::loadSettings();

/****************************
* HANDLE DISPLAY ERRORS 	  *
****************************/

if(isset($settings['settings']['displayErrorDetails']) && $settings['settings']['displayErrorDetails']) 
{
	ini_set('display_errors', 1);
	ini_set('display_startup_errors', 1);	
}

/************************
* INITIATE SLIM 		*
************************/

$app = new \Slim\App($settings);

/************************
*  GET SLIM CONTAINER	*
************************/

$container = $app->getContainer();

/************************
* Create URI 			*
************************/

# get uri and delete username and password from uri
$uri = \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER))->withUserInfo('');

/************************
* LOAD & UPDATE PLUGINS *
************************/

$plugins 		= new Typemill\Plugins();
$pluginNames	= $plugins->load();
$pluginSettings = $routes = $middleware	= array();

foreach($pluginNames as $pluginName)
{
	$className	= $pluginName['className'];
	$name		= $pluginName['name'];
		
	# check if plugin is in the settings already
	if(isset($settings['settings']['plugins'][$name]))
	{
		# if so, add the settings to temporary plugin settings
		$pluginSettings[$name] = $settings['settings']['plugins'][$name];
		
		# and delete them from original settings
		unset($settings['settings']['plugins'][$name]);
	}
	else
	{
		# if not, it is a new plugin. Add it and set active to false
		$pluginSettings[$name] = ['active' => false];
		
		# and set flag to refresh the settings
		$refreshSettings = true;
	}
	
	# if the plugin is activated, add routes/middleware and add plugin as event subscriber
	if($pluginSettings[$name]['active'])
	{
		$routes 		= $plugins->getNewRoutes($className, $routes);
		$middleware		= $plugins->getNewMiddleware($className, $middleware);
		
		$dispatcher->addSubscriber(new $className($container));
	}
}

# if plugins in original settings are not empty now, then a plugin has been removed
if(!empty($settings['settings']['plugins'])){ $refreshSettings = true; }

# update the settings in all cases
$settings['settings']['plugins'] = $pluginSettings;

# if plugins have been added or removed
if(isset($refreshSettings))
{
	# update the settings in the container
	$container->get('settings')->replace($settings['settings']);
	
	# update stored settings file
	$refreshSettings = Typemill\settings::updateSettings($settings['settings']);
}

# dispatch the event onPluginsLoaded
$dispatcher->dispatch('onPluginsLoaded', new OnPluginsLoaded($pluginNames));

# dispatch settings event and get all setting-updates from plugins
$dispatcher->dispatch('onSettingsLoaded', new OnSettingsLoaded($settings))->getData();


/**********************************
* 	LOAD ROLES AND PERMISSIONS 	  *
**********************************/

# load roles and permissions
$rolesAndPermissions = Typemill\Settings::loadRolesAndPermissions();

# dispatch roles so plugins can enhance them
$rolesAndPermissions = $dispatcher->dispatch('onRolesPermissionsLoaded', new OnRolesPermissionsLoaded($rolesAndPermissions))->getData();

# load resources
$resources = Typemill\Settings::loadResources();

# dispatch roles so plugins can enhance them
$resources = $dispatcher->dispatch('onResourcesLoaded', new OnResourcesLoaded($resources))->getData();

# create acl-object
$acl = Typemill\Settings::createAcl($rolesAndPermissions, $resources);

# add acl to container
$container['acl'] = function($c) use ($acl)
{
	return $acl;
};

/******************************
* ADD DISPATCHER TO CONTAINER *
******************************/

$container['dispatcher'] = function($container) use ($dispatcher)
{
	return $dispatcher;
};

/************************
* 	DECIDE FOR SESSION	*
************************/

$session_segments 	= array('setup', 'tm/', 'api/', '/setup', '/tm/', '/api/');

# let plugins add own segments for session, eg. to enable csrf for forms
$client_segments 	= $dispatcher->dispatch('onSessionSegmentsLoaded', new OnSessionSegmentsLoaded([]))->getData();
$session_segments	= array_merge($session_segments, $client_segments);

$container['flash']	= false;
$container['csrf'] 	= false;


/************************************
* ADD ASSET-FUNCTION FOR PLUGINS	*
************************************/

$container['assets'] = function($c) use ($uri)
{
	return new \Typemill\Assets($uri->getBaseUrl());
};

/********************************
*  MOVE TO MIDDLEWARE NEXT TIME *
********************************/

# if website is restricted to registered user
if( ( isset($settings['settings']['access']) && $settings['settings']['access'] ) || ( isset($settings['settings']['pageaccess']) && $settings['settings']['pageaccess'] ) )
{
	# activate session for all routes
	$session_segments = [$uri->getPath()];
}

foreach($session_segments as $segment)
{
	if(substr( $uri->getPath(), 0, strlen($segment) ) === $segment)
	{	
		// configure session
		ini_set('session.cookie_httponly', 1 );
		ini_set('session.use_strict_mode', 1);
		ini_set('session.cookie_samesite', 'lax');
		if($uri->getScheme() == 'https')
		{
			ini_set('session.cookie_secure', 1);
			session_name('__Secure-typemill-session');
		}
		else
		{
			session_name('typemill-session');
		}
		
		// add csrf-protection
		$container['csrf'] = function ($c)
		{
			$guard = new \Slim\Csrf\Guard();
			$guard->setPersistentTokenMode(true);
			$guard->setfailurecallable(function ($request, $response, $next)
			{
				$request = $request->withattribute("csrf_result", false);
				return $next($request, $response);
			});

			return $guard;
		};
		
		// add flash to container
		$container['flash'] = function () 
		{
			return new \Slim\Flash\Messages();
		};
		
		// start session
		session_start();
	}
}

/************************
* 	LOAD TWIG VIEW		*
************************/

$container['view'] = function ($container) use ($uri)
{
	$path = array($container->get('settings')['themePath'], $container->get('settings')['authorPath']);
	
	$cache = ( isset($container->get('settings')['twigcache']) && $container->get('settings')['twigcache'] ) ? $container->get('settings')['rootPath'] . '/cache/twig' : false;

    $view = new \Slim\Views\Twig( $path, [
		'cache' => $cache,
		'autoescape' => false,
		'debug' => true
    ]);
    
    # Instantiate and add Slim specific extension
    $router = $container->get('router');

    $view->addExtension(new Slim\Views\TwigExtension($router, $uri));
	$view->addExtension(new Twig_Extension_Debug());
    $view->addExtension(new Typemill\Extensions\TwigUserExtension());
	$view->addExtension(new Typemill\Extensions\TwigMarkdownExtension());
	$view->addExtension(new Typemill\Extensions\TwigMetaExtension());	
	$view->addExtension(new Typemill\Extensions\TwigPagelistExtension());	

	# if session route, add flash messages and csrf-protection
	if($container['flash'])
	{
		$view->getEnvironment()->addGlobal('flash', $container->flash);
		$view->addExtension(new Typemill\Extensions\TwigCsrfExtension($container['csrf']));
		$view->addExtension(new Typemill\Extensions\TwigCaptchaExtension());
	}

	/******************************
	* LOAD TRANSLATIONS           *
	******************************/
    $pieces = explode('/',trim($uri->getPath(),'/'));
    if( ($pieces[0] === 'tm' OR $pieces[0] === 'setup') )
  	{
    	# Admin environment labels
    	$labels = Typemill\Translations::loadTranslations('admin');
  	} else {
    	# User environment labels
    	# For now it is useless, but it will prove useful in the future
    	$labels = Typemill\Translations::loadTranslations('user');
  	}
  	$view['translations'] = $labels;
	$view->addExtension(new Typemill\Extensions\TwigLanguageExtension( $labels ));

	return $view;
};

/************************
* 	ADD MIDDLEWARE  	*
************************/

foreach($middleware as $pluginMiddleware)
{
	$middlewareClass 	= $pluginMiddleware['classname'];
	$middlewareParams	= $pluginMiddleware['params'];
	if(class_exists($middlewareClass))
	{
		$app->add(new $middlewareClass($middlewareParams));
	}
}

if($container['flash'])
{
	$app->add(new \Typemill\Middleware\ValidationErrorsMiddleware($container['view']));
	$app->add(new \Typemill\Middleware\SecurityMiddleware($container['router'], $container['settings'], $container['flash']));
	$app->add(new \Typemill\Middleware\OldInputMiddleware($container['view']));
	$app->add($container->get('csrf'));	
}

/********************************
*  ASSET MIDDLEWARE FOR TWIG	*
********************************/

$app->add(new \Typemill\Middleware\assetMiddleware($container));

/********************************
*  PROXY DETECTION FOR REQUEST	*
********************************/

if(isset($settings['settings']['proxy']) && $settings['settings']['proxy'])
{
	$trustedProxies = ( isset($settings['settings']['trustedproxies']) && !empty($settings['settings']['trustedproxies']) ) ? explode(",", $settings['settings']['trustedproxies']) : [];
	$app->add(new RKA\Middleware\ProxyDetection($trustedProxies));	
}

/************************
* 	ADD ROUTES			*
************************/

require __DIR__ . '/Routes/Api.php';
require __DIR__ . '/Routes/Web.php';