<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonCommon\Classes\Document;

use Dompdf\Dompdf;
use Dompdf\Options;
use Dompdf\FontMetrics;
use Dompdf\Css\Stylesheet;
use \Enlight_Template_Manager as TemplateManager;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util;

class Renderer
{
    /**
     * The dompdf instance used for rendering the HTML into a PDF file.
     *
     * @var Dompdf
     */
    protected $dompdf;

    /**
     * The template manager, that is Smarty instance, used for rendering the template to HTML.
     *
     * @var TemplateManager
     */
    protected $templateManager;

    /**
     * The file name of the template that shall be rendered.
     *
     * @var string
     */
    protected $templatePath;

    /**
     * Contains all data that is passed to the template.
     *
     * @var array
     */
    protected $templateData = [];

    /**
     * The HTML resulting from rendering the smarty template.
     *
     * @var string
     */
    protected $html;

    /**
     * Contains the raw data of the rendered PDF file.
     *
     * @var string
     */
    protected $pdf;

    /**
     * Converts a paper size from millimeters to pt (= 1/72 inch).
     *
     * @param int $width The paper width in millimeters.
     * @param int $height The paper height in millimeters.
     * @return array An array containing the respective paper size in pixel.
     */
    public static function getPaperSizeByMillimeters($width, $height)
    {
        $inch = 25.4; // 1 inch = 25,4 mm

        return [
            0,
            0,
            $width / $inch * 72,
            $height / $inch * 72,
        ];
    }

    /**
     * Initializes both dompdf and the template manager (Smarty).
     *
     * @param TemplateManager $templateManager
     * @param string $paper (optional)
     * @param string $orientation (optional)
     * @param array $options (optional)
     * @deprecated Use new DocumentRenderingContext-Classes
     */
    public function __construct(TemplateManager $templateManager, $paper = 'A4', $orientation = 'portrait', array $options = [])
    {
        // Clone the template manager to make sure that no global settings are changed by this instance
        $this->templateManager = Util::cloneTemplateManager($templateManager);

        // Initialize dompdf
        $this->dompdf = Util::createDompdfInstance($options);
        $this->dompdf->setPaper($paper, $orientation);
    }

    /**
     * Pass dompdf options to dompdf instance.
     *
     * @deprecated just pass the correct options with the constructor instead
     *
     * @param array $options
     */
    public function setDompdfOptions(array $options)
    {
        if (!$options) {
            return;
        }

        // Set options
        $dompdfOptions = new Options();

        // Add the same default options which are set by Util::createDompdfInstance()
        $dompdfOptions->set(Util::getDompdfDefaultOptions());

        $dompdfOptions->set($options);
        $this->dompdf->setOptions($dompdfOptions);

        // Reinitialize font metrics
        $metrics = new FontMetrics($this->dompdf->getCanvas(), $this->dompdf->getOptions());
        $this->dompdf->setFontMetrics($metrics);
        $stylesheet = new Stylesheet($this->dompdf);
        $this->dompdf->setCss($stylesheet);
    }

    /**
     * Sets dompdf's paper size and orientation.
     *
     * @param string $size
     * @param string $orientation
     */
    public function setPaper($size, $orientation = 'portrait')
    {
        $this->dompdf->setPaper($size, $orientation);
    }

    /**
     * Sets the name of the template that shall be rendered.
     *
     * @param string $templatePath
     */
    public function setTemplatePath($templatePath)
    {
        $this->templatePath = $templatePath;
    }

    /**
     * @param array $templateData
     */
    public function setTemplateData($templateData)
    {
        $this->templateData = $templateData;
    }

    /**
     * Assigns the template data to the Smarty template and renders it to HTML.
     */
    public function generateHTML()
    {
        if (!$this->templatePath) {
            throw new Exception('"templatePath" not set!');
        }

        // Render the smarty template using the template manager
        $template = $this->templateManager->createData();
        $template->assign($this->templateData);
        $this->html = $this->templateManager->fetch($this->templatePath, $template);
    }

    /**
     * Renders the HTML into a PDF file using dompdf. If no HTML has been generated
     * yet, @link{self::generateHTML()} is called first.
     *
     * @return string
     */
    public function renderPDF()
    {
        // Make sure the HTML has already been generated
        if (!$this->html) {
            $this->generateHTML();
        }

        // Render the HTML into a PDF and save its file contents
        $this->dompdf->loadHtml($this->html);

        // Dompdf is currently not capable of handling SVG header informations
        // like title or desc and hence outputs related warnings to the output
        // stream. To prevent pollution of the output stream dompdf outputs are
        // captured and the output stream is cleaned after the rendering.
        ob_start();
        $this->dompdf->render();
        ob_get_clean();
        $this->pdf = $this->dompdf->output();

        return $this->pdf;
    }

    /**
     * Sends the rendered PDF to the response using the given file name.
     *
     * @param string $fileName
     * @param boolean $asAttachment (optional)
     */
    public function respondWithPDF($fileName, $asAttachment = false)
    {
        // Make sure the PDF has already been rendered
        if (!$this->pdf) {
            $this->renderPDF();
        }

        $this->dompdf->stream($fileName, [
            'Attachment' => $asAttachment,
        ]);

        // This is fugly, but unfortunately the best solution we could come up with.
        //
        // The problem is that Shopware made a change in 5.3
        // (https://github.com/VIISON/shopware/commit/0b1c6f0d0b609f03d7fc79935667a208ee4a00fe#diff-b0f8691023c0f7345c9827c5272f94fdR201)
        // which overwrites the Content-Type headers set using the PHP header() function with text/html at the end of
        // request dispatch if no headers were set on the Enlight response object. This is only a problem if headers
        // were not already sent at that point, which occurs in some cases when weird output buffering stuff prevents
        // Dompdf::stream from streaming the generated PDF to the client right away.
        //
        // die'ing here is the easiest workaround since it does not require passing the Dompdf headers back to
        // Shopware / Symfony.
        // @codingStandardsIgnoreLine
        die;
    }
}
