<?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\RenderingContext;

use Shopware\Components\Model\ModelManager;
use Shopware\Components\Theme\Inheritance as ThemeInheritanceService;
use Shopware\Models\Document\Document as DocumentType;
use Shopware\Models\Document\Element;
use Shopware\Models\Shop\Locale;
use Shopware\Models\Shop\Shop;
use Shopware\Plugins\ViisonCommon\Classes\Document\PaperLayout;
use Shopware\Plugins\ViisonCommon\Classes\Document\RenderedDocument\RenderedDocumentWithDocumentType;
use Shopware\Plugins\ViisonCommon\Classes\Document\RenderingEngine\RenderingEngine;
use Shopware\Plugins\ViisonCommon\Classes\TranslationServiceFactory;
use Shopware\Plugins\ViisonCommon\Components\FileStorage\FileStorage;
use Shopware_Components_Translation;

/**
 * Rendering context for a Shopware order document.
 *
 * Provides all necessary dependencies and implementations for a shopware document type to be rendered. This includes:
 * TemplateManager, Document Containers, theme inheritance and localization
 */
class DocumentRenderingContext extends TemplateRenderingContext
{
    /**
     * @var ThemeInheritanceService
     */
    protected $themeInheritanceService = null;

    /**
     * @var DocumentType Shopware document type to use
     */
    protected $documentType;

    /**
     * @var Shop The locale to get the correct translation for the containers
     */
    protected $languageSubShop;

    /**
     * @var ModelManager
     */
    protected $modelManager;

    /**
     * @var Shopware_Components_Translation
     */
    protected $translationService;

    /**
     * @var FileStorage
     */
    private $documentFileStorage;

    /**
     * @internal Is only called by DocumentRenderingService
     *
     * @param RenderingEngine $renderingEngine
     * @param \Enlight_Template_Manager $templateManager
     * @param DocumentType $documentType
     * @param Shop $languageSubShop
     * @param ModelManager $modelManager
     * @param PaperLayout $paperLayout $paperLayout
     * @param FileStorage $documentFileStorage
     * @param ThemeInheritanceService $themeInheritanceService
     */
    public function __construct(
        RenderingEngine $renderingEngine,
        \Enlight_Template_Manager $templateManager,
        DocumentType $documentType,
        Shop $languageSubShop,
        ModelManager $modelManager,
        PaperLayout $paperLayout,
        FileStorage $documentFileStorage,
        ThemeInheritanceService $themeInheritanceService = null
    ) {
        parent::__construct($renderingEngine, $templateManager, 'documents/' . $documentType->getTemplate(), $paperLayout);
        $this->documentType = $documentType;
        $this->languageSubShop = $languageSubShop;
        $this->modelManager = $modelManager;
        $this->themeInheritanceService = $themeInheritanceService;
        $this->translationService = TranslationServiceFactory::createTranslationService();
        $this->documentFileStorage = $documentFileStorage;
    }

    /**
     * @inheritdoc
     * @return RenderedDocumentWithDocumentType
     */
    public function renderDocument()
    {
        $renderedDocument = parent::renderDocument();

        return new RenderedDocumentWithDocumentType(
            $renderedDocument->getHtml(),
            $renderedDocument->getPdf(),
            $this->documentType,
            $this->modelManager,
            $this->documentFileStorage
        );
    }

    /**
     * @inheritdoc
     */
    protected function generateHtml()
    {
        // Ensure that Shopware's user configurable document elements of the context's document type are available in
        // the document template
        $this->assignDocumentElements();

        return parent::generateHtml();
    }

    /**
     * Inherits from the shop template of a given shop by adding its inheritance graph (sequence of template folders) to
     * the context's template manager instance.
     *
     * Note: This methods requires the theme inheritance service to be set and only supports templates with
     * version >= 3 (Shopware 5 responsive template).
     *
     * @param Shop $shop
     * @throws \BadMethodCallException
     */
    public function inheritFromShopTemplate(Shop $shop)
    {
        // Get template of the main shop in case $shop is a language subshop, since language subshops don't have a
        // template
        $template = $shop->getDocumentTemplate() ?: $shop->getMain()->getDocumentTemplate();

        // Template inheritance is only supported for theme versions >= 3 and Shopware 5
        if ($template->getVersion() >= 3) {
            if (!$this->themeInheritanceService) {
                throw new \BadMethodCallException('No theme inheritance service is configured');
            }
            // Overwrite (set, not add) template directories to the themes inheritance template directories of the
            // current template. This way we don't have unwanted ExtJS/Theme directories in the manager when we only
            // care for document themes. See Shopware\Models\Shop\Order::registerTheme()
            $inheritance = $this->themeInheritanceService->getTemplateDirectories($template);
            $this->getTemplateManager()->setTemplateDir($inheritance);
        }
    }

    /**
     * Assign the document elements to the template
     *
     * Loads, translates and assigns the content of all document elements, which are assigned to the document type
     */
    private function assignDocumentElements()
    {
        $documentElements = $this->documentType->getElements();
        $documentTypeId = $this->documentType->getId();

        $containers = [];
        $documentElementTranslations = $this->translationService->read($this->languageSubShop->getId(), 'documents', 1);

        /** @var Element $documentElement */
        foreach ($documentElements as $documentElement) {
            $elementName = $documentElement->getName();

            // Translate the values and styles if there exists a translation for them
            $elementValue = $documentElementTranslations[$documentTypeId][$elementName . '_Value'] ?: $documentElement->getValue();
            $elementStyle = $documentElementTranslations[$documentTypeId][$elementName . '_Style'] ?: $documentElement->getStyle();

            // Parse the smarty in the document elements to replace snippets, variables etc.
            $elementValue = $this->templateManager->fetch('string:' . $elementValue);
            // I don't know why the 'style' is not parsed here. But shopware does not do it so we do not do it either.

            $containers[$elementName] = [
                'style' => $elementStyle,
                'value' => $elementValue,
            ];
        }

        $this->assignTemplateVar('Containers', $containers);
    }

    /**
     * @return ThemeInheritanceService
     */
    public function getThemeInheritanceService()
    {
        return $this->themeInheritanceService;
    }

    /**
     * @param ThemeInheritanceService $themeInheritanceService
     */
    public function setThemeInheritanceService(ThemeInheritanceService $themeInheritanceService)
    {
        $this->themeInheritanceService = $themeInheritanceService;
    }

    /**
     * @return DocumentType
     */
    public function getDocumentType()
    {
        return $this->documentType;
    }

    /**
     * @param DocumentType $documentType
     */
    public function setDocumentType(DocumentType $documentType)
    {
        $this->documentType = $documentType;
    }

    /**
     * @return Shop
     */
    public function getLanguageSubShop()
    {
        return $this->languageSubShop;
    }

    /**
     * @param Locale $languageSubShop
     */
    public function setLanguageSubShop(Locale $languageSubShop)
    {
        $this->languageSubShop = $languageSubShop;
    }
}
