<?php

namespace Adawolfa\Nette\Application\Responses;
use Nette\Application\BadRequestException;
use Nette\Http;
use Nette\Application\IResponse;

/**
 * Response file with remote sources support.
 *
 * @author Adam Klvač <adam@klva.cz>
 */
class FileResponse implements IResponse
{

	/** @var string */
	private $file;

	/** @var string|null */
	private $name;

	/** @var string|null */
	private $contentType;

	/** @var bool */
	private $forceDownload;

	/**
	 * @param string $file
	 * @param string|null $name
	 * @param string|null $contentType
	 * @param bool $forceDownload
	 */
	public function __construct($file, $name = null, $contentType = null, $forceDownload = true)
	{
		$this->file = $file;
		$this->name = $name;
		$this->contentType = $contentType;
		$this->forceDownload = $forceDownload;
	}

	/** {@inheritdoc} */
	public function send(Http\IRequest $httpRequest, Http\IResponse $httpResponse): void
	{
		$stream = @fopen($this->file, 'rb');

		if ($stream === false) {
			throw new BadRequestException("File '{$this->file}' could not be opened.");
		}

		$name = $this->name;
		$contentType = $this->contentType;
		$charset = null;
		$length = null;

		if (isset($http_response_header)) {

			foreach ($http_response_header as $header) {

				if ($name === null && stripos($header, 'Content-Disposition:') === 0) {
					if (preg_match('#^Content-Disposition: (inline|attachment);\s*filename(\*?)=(([^\']+)\'\')?(.+)$#i', $header, $matches)) {
						if ($matches[2] === '*') {
							$name = iconv($matches[4], 'UTF-8', rawurldecode($matches[5]));
						} else {
							$name = $matches[5];
						}
					}
				}

				if ($contentType === null && stripos($header, 'Content-Type:') === 0) {
					list ($contentType, $charset) = explode(';', explode(':', $header . ';')[1]);
					$contentType = trim($contentType) ?: null;
					$charset = trim($charset) ?: null;
				}

				if ($length === null && stripos($header, 'Content-Length:') === 0) {
					$length = trim(explode(':', $header)[1]);
				}

			}

		} elseif (is_file($this->file)) {
			$length = filesize($this->file);
		}

		if ($name === null) {
			$name = basename(parse_url($this->file, PHP_URL_PATH));
		}

		if ($contentType === null) {
			$contentType = 'application/octet-stream';
		}

		$httpResponse->setHeader(
			'Content-Disposition',
			($this->forceDownload ? 'attachment' : 'inline')
			. '; filename*=UTF-8\'\''
			. rawurlencode($name)
		);

		$httpResponse->setContentType($contentType, $charset);

		if ($length !== null) {
			$httpResponse->setHeader('Content-Length', $length);
		}

		while (!feof($stream)) {
			print fread($stream, 4096);
		}

		fclose($stream);
	}

}