<?php
/**
 * Wikimedia Jahresbericht 2017
 *
 * Copyright (c) 2017 Atelier Disko - All rights reserved.
 *
 * Use of this source code is governed by the AGPL v3
 * license that can be found in the LICENSE file.
 */

define('PROJECT_CONTEXT', 'dev');
define('PROJECT_APP_PATH', __DIR__);
define('PROJECT_DOMAIN', 'wmde-bericht2017.test');

if (PROJECT_CONTEXT === 'dev') {
	error_reporting(E_ALL);
	ini_set('display_errors', true);
} else {
	ini_set('display_errors', false);
}

$routes = [];
$helpers = [];
$viewVars = [];
$scripts = [];

$lang = 'de';
$path = $_SERVER['REQUEST_URI'];
$isCanonical = false;

// Configure g11n stack early and strip locale from URL.
if (preg_match('#^/(de|en)(/.*)?#', $path, $matches)) {
	$isCanonical = true;
	$lang = $matches[1];

	if (isset($matches[2])) {
		$path = '/' . ltrim($matches[2], '/');
	} else {
		$path = '/';
	}
}

//
// Helpers
//

// Used to construct URLs in the view.
$helpers['url'] = function($goal, $lang) {
	$path = $lang . '/' . trim($goal, '/');
	return '/' . trim($path, '/');
};

// Used to construct a URL for switching the language, but
// staying on the same page.
$helpers['switchLanguageFromUrl'] = function($lang) use ($path) {
	return rtrim('/' . ($lang === 'de' ? 'en' : 'de') . '' . $path, '/');
};

$helpers['formatNumber'] = function($number, $lang) {
	if ($lang !== 'de') {
		return number_format($number);
	}
	return number_format($number, 0, ',', '.');
};

//
// Scripts
//
$scripts[] = 'views/layouts/default';

// Constructs a script path for the current page path. And will check if a script under
// that name is present in the filesystem. If not simply returns `null` otherwise
// it returns the script path, good for constructing the full script URL.
//
// Does not support pages with underscores.
$fragment = null;

if (!ltrim($path, '/')) {
	$fragment = 'pages/home';
} elseif (strpos($path, '/report') === 0)  {
	// Sub-pages all use the same JS file, so we don't need to duplicate logic.
	$fragment = 'pages/report';
} elseif (strpos($path, '/finance') === 0)  {
	// Sub-pages all use the same JS file, so we don't need to duplicate logic.
	$fragment = 'pages/finance';
} else {
	$fragment = 'pages/' . ltrim($path, '/');
}

if (file_exists(PROJECT_APP_PATH . '/assets/js/views/' . $fragment . '.js')) {
	$scripts[] = "views/{$fragment}";
}

//
// Routes
//

$routes['#^/$#'] = function() {
	$reports = require PROJECT_APP_PATH .'/data/reports.php';
	$achievements = require PROJECT_APP_PATH .'/data/achievements.php';

	return compact('reports', 'achievements') + [
		'hasBlackHeader' => false
	];
};
$routes['#^/finance#'] = function($path) {
	return ['hasBlackHeader' => $path !== '/finance'];
};
$routes['#^/report$#'] = function($path, $query, $matches) {
	$filter = isset($query['filter']) ? $query['filter'] : null;

	$reports = require PROJECT_APP_PATH .'/data/reports.php';
	$filters = require PROJECT_APP_PATH .'/data/report_filters.php';

	if ($filter) {
		$reports = array_filter($reports, function($v) use ($filter) {
			return $v['category'] === $filter;
		});
		foreach ($filters as $f) {
			if ($f['name'] === $filter) {
				$filter = $f;
				break;
			}
		}
	}

	return compact('reports', 'filter', 'filters') + [
		'hasBlackHeader' => false
	];
};
$routes['#^/report/(.*)$#'] = function($path, $query, $matches) {
	$achievements = require PROJECT_APP_PATH .'/data/achievements.php';
	$achievements = array_values(array_filter($achievements, function($v) use ($path) {
		return $v['url'] === $path;
	}));

	$reports = require PROJECT_APP_PATH .'/data/reports.php';
	$report = null;

	foreach ($reports as $_report) {
		if ($_report['name'] === $matches[1]) {
			$report = $_report;
			break;
		}
	}
	return compact('report', 'achievements') + [
		'hasBlackHeader' => true
	];
};

//
// Functions
//

// Matches current request against registered routes and
// returns view variables.
$matchRoute = function($path, $routes) {
	$query = parse_url($path, PHP_URL_QUERY);
	parse_str($query, $query);

	$path = parse_url($path, PHP_URL_PATH);

	foreach ($routes as $regex => $handler) {
		if (preg_match($regex, $path, $matches)) {
			return $handler($path, $query, $matches);
		}
	}
	return false;
};

$renderView = function($viewVars, $scripts, $helpers, $_path, $_lang) {
	$_viewFileFromURI = function($path, $lang) {
		// $path may contain query string
		$path = parse_url($path, PHP_URL_PATH);

		$viewBase = PROJECT_APP_PATH . '/views/pages/' . $lang;
		$viewName = str_replace('/', '_', trim($path, '/'));

		$viewFile = $viewBase . '/' . $viewName . '.php';
		$viewFile = realpath($viewFile);

		if ($viewName === '') {
			return $viewBase . '/home.php';
		}

		// Prevent directory traversal attack
		// see http://stackoverflow.com/a/4205278
		if ($viewFile === false || strpos($viewFile, $viewBase) !== 0) {
			return false;
		}
		return $viewFile;
	};
	$_viewFile = $_viewFileFromURI($_path, $_lang);

	if ($_viewFile === false || trim($_path, '/') === 'home') {
		return false;
	}
	extract($helpers, EXTR_SKIP);
	extract($viewVars, EXTR_SKIP);

	require PROJECT_APP_PATH . '/views/elements/' . $_lang . '/header.php';
	require $_viewFile;
	require PROJECT_APP_PATH . '/views/elements/' . $_lang . '/footer.php';
};

//
// Handle the request
//
$viewVars += compact('lang', 'isCanonical', 'path');

if (($viewVars += $matchRoute($path, $routes)) === false) {
	header('HTTP/1.1 404 Not Found');
	exit();
}
if ($renderView($viewVars, $scripts, $helpers, $path, $lang) === false) {
	header('HTTP/1.1 404 Not Found');
	exit();
}

?>
