<?php

namespace XF\Mvc;

use XF\Http\Response;
use XF\Mvc\Renderer\AbstractRenderer;
use XF\Util\File;
use XF\Util\Xml;

use function get_class;

class View
{
	/**
	 * @var AbstractRenderer
	 */
	protected $renderer;

	/**
	 * @var Response
	 */
	protected $response;

	/**
	 * @var string
	 */
	protected $templateName = '';

	/**
	 * @var array
	 */
	protected $params = [];

	public function __construct(AbstractRenderer $renderer, Response $response, $templateName = '', array $params = [])
	{
		$this->renderer = $renderer;
		$this->response = $response;
		$this->templateName = $templateName;
		$this->params = $params;
	}

	public function getTemplateName()
	{
		return $this->templateName;
	}

	public function getParams()
	{
		return $this->params;
	}

	public function renderTemplate($templateName, array $params = [])
	{
		$templater = $this->renderer->getTemplater();

		if (!strpos($templateName, ':') && strpos($this->templateName, ':'))
		{
			[$type] = $templater->getTemplateTypeAndName($templateName);
			$templateName = $type . ':' . $templateName;
		}

		return $templater->renderTemplate($templateName, $params);
	}

	protected function isException($e)
	{
		return ($e instanceof \Exception || $e instanceof \Throwable);
	}

	protected function renderExceptionHtml($e, &$error = null)
	{
		$traceHtml = '';

		if ($this->isException($e))
		{
			/** @var \Throwable $e */
			$rootDir = \XF::getRootDirectory();
			$message = str_replace($rootDir, '', $e->getMessage());
			$error = '<b>' . get_class($e) . '</b>: ' . htmlspecialchars($message) . ' in <b>'
				. File::stripRootPathPrefix($e->getFile()) . '</b> at line <b>' . $e->getLine() . '</b>';

			foreach ($e->getTrace() AS $traceEntry)
			{
				$function = (isset($traceEntry['class']) ? $traceEntry['class'] . $traceEntry['type'] : '') . $traceEntry['function'];
				if (isset($traceEntry['file']) && isset($traceEntry['line']))
				{
					$fileLine = ' <span>in</span> <b>'
						. File::stripRootPathPrefix($traceEntry['file'])
						. "</b> <span>at line</span> <b>$traceEntry[line]</b>";
				}
				else
				{
					$fileLine = '';
				}
				$traceHtml .= "\t<li><b>" . htmlspecialchars($function) . "()</b>" . $fileLine . "</li>\n";
			}
		}
		else
		{
			$error = 'Unknown';
		}

		return "<div class=\"blockMessage blockMessage--error\"><div><div>$error</div> <ol>\n$traceHtml</ol></div></div>";
	}

	protected function renderExceptionXml($e)
	{
		$document = new \DOMDocument('1.0', 'utf-8');
		$document->formatOutput = true;

		$rootNode = $document->createElement('errors');
		$document->appendChild($rootNode);

		if ($this->isException($e))
		{
			/** @var \Exception $e */
			$exceptionMessage = $e->getMessage();

			$errorNode = Xml::createDomElement(
				$document,
				'error',
				$exceptionMessage
			);
			$errorNode->setAttribute(
				'file',
				File::stripRootPathPrefix($e->getFile())
			);
			$errorNode->setAttribute('line', $e->getLine());
			$rootNode->appendChild($errorNode);

			$traceNode = $document->createElement('trace');

			foreach ($e->getTrace() AS $trace)
			{
				$function = (isset($trace['class']) ? $trace['class'] . $trace['type'] : '') . $trace['function'];

				if (!isset($trace['file']))
				{
					$trace['file'] = '';
				}
				if (!isset($trace['line']))
				{
					$trace['line'] = '';
				}

				$entryNode = $document->createElement('entry');
				$entryNode->setAttribute('function', $function);
				$entryNode->setAttribute(
					'file',
					File::stripRootPathPrefix($trace['file'])
				);
				$entryNode->setAttribute('line', $trace['line']);

				$traceNode->appendChild($entryNode);
			}

			$rootNode->appendChild($traceNode);
		}
		else
		{
			$rootNode->appendChild($document->createElement('error', 'Unknown error, trace unavailable'));
		}

		return $document;
	}
}
