<?php
namespace OCA\Memento\Controller;

require_once __DIR__ . '/findMementos.php';

use DateTime;

use OCP\IRequest;
use OCP\IServerContainer;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\DataDisplayResponse;

use findMementos;

class TimeGateController extends Controller {
	private $userFolder;

	public function __construct(
		$AppName,
		IRequest $request,
		$UserId,
		IServerContainer $serverContainer
	) {
		parent::__construct($AppName, $request);
		$this->userFolder = $serverContainer->getUserFolder($UserId);
	}

	/**
	 * @NoAdminRequired
	 * @NoCSRFRequired
	 */
	public function timeGate($url) {
		$matchingMementos = findMementos($this->userFolder, $url);

		// Choose one of the matched mementos, if any.
		if (count($matchingMementos) === 0) {
			// No matches. :(
			$message = "<h1>No snapshots found for requested URL. :(</h1>";
			return new DataDisplayResponse($message, 404);
		} else if (count($matchingMementos) === 1) {
			// One match; no need to choose.
			$chosenMemento = $matchingMementos[0];
		} else {
			// Multiple matches: choose based on requested date.
			$acceptDatetimeHeader = $this->request->getHeader('Accept-Datetime');
			if ($acceptDatetimeHeader) {
				try {
					$requestedDatetime = DateTime::createFromFormat(DateTime::RFC1123, $acceptDatetimeHeader)
						->getTimestamp();
				} catch (Exception $e) {
					return new DataDisplayResponse("Invalid Accept-Datetime header.", 400);
				}
			} else {
				// Not sending the header means requesting the most recent version.
				$requestedDatetime = time();
			}
			// Pick the one closest to the requested date (either before or after it).
			$chosenMemento = minBy($matchingMementos,
				function ($matchingMemento) use ($requestedDatetime) {
					return abs($matchingMemento['datetime'] - $requestedDatetime);
				}
			);
		}

		// Send a 302 Found redirect pointing to the chosen memento.
		$response = new RedirectResponse($chosenMemento['mementoUrl']);
		$response->setStatus(302);
		$response->addHeader('Vary', 'accept-datetime');
		$response->addHeader('Link', "<{$chosenMemento['originalUrl']}>; rel=\"original\"");
		return $response;
	}
}

function minBy($array, $iteratee) {
	// is there any simpler way for this in php?
	$values = array_map($iteratee, $array);
	$argmin = array_search(min($values), $values);
	return $array[$argmin];
}