<?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\Plugins\SwagSecurity;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Shopware\Components\DependencyInjection\Container;
use Shopware\Plugins\ViisonCommon\Classes\Util\Util;

class RedeclareClassErrorHotifx
{
    /**
     * First version which fixes the redeclare class error.
     */
    const SWAG_SECURITY_VERSION_FIXING_REDECLARE_CLASS_ERROR = '1.1.5';

    /**
     * Contains all classes that can be replaced by the SwagSecurity plugin as keys.
     * The values are the paths to their class files.
     *
     * @var array
     */
    protected static $SWAG_SECURITY_REPLACED_CLASSES = [
        'Shopware\\Models\\Customer\\Billing' => '/engine/Shopware/Models/Customer/Billing.php',
        'Shopware\\Models\\Customer\\Customer' => '/engine/Shopware/Models/Customer/Customer.php',
        'Shopware\\Models\\Customer\\Shipping' => '/engine/Shopware/Models/Customer/Shipping.php',
        'Shopware\\Models\\Order\\Billing' => '/engine/Shopware/Models/Order/Billing.php',
        'Shopware\\Models\\Order\\Order' => '/engine/Shopware/Models/Order/Order.php',
        'Shopware\\Models\\Order\\Shipping' => '/engine/Shopware/Models/Order/Shipping.php',
        'Shopware\\Models\\Partner\\Partner' => '/engine/Shopware/Models/Partner/Partner.php',
        'Shopware\\Bundle\\CustomerSearchBundleDBAL\\ConditionHandler\\AgeConditionHandler' => '/engine/Shopware/Bundle/CustomerSearchBundleDBAL/ConditionHandler/AgeConditionHandler.php',
        'Shopware\\Bundle\\CustomerSearchBundleDBAL\\ConditionHandler\\CustomerAttributeConditionHandler' => '/engine/Shopware/Bundle/CustomerSearchBundleDBAL/ConditionHandler/CustomerAttributeConditionHandler.php',
        'Shopware\\Bundle\\CustomerSearchBundleDBAL\\ConditionHandler\\HasOrderCountConditionHandler' => '/engine/Shopware/Bundle/CustomerSearchBundleDBAL/ConditionHandler/HasOrderCountConditionHandler.php',
        'Shopware\\Bundle\\CustomerSearchBundleDBAL\\ConditionHandler\\HasTotalOrderAmountConditionHandler' => '/engine/Shopware/Bundle/CustomerSearchBundleDBAL/ConditionHandler/HasTotalOrderAmountConditionHandler.php',
        'Shopware\\Bundle\\SearchBundleDBAL\\ConditionHandler\\DynamicConditionParserTrait.php' => '/engine/Shopware/Bundle/SearchBundleDBAL/ConditionHandler/DynamicConditionParserTrait.php',
        'Shopware\\Bundle\\SearchBundleDBAL\\ConditionHandler\\ProductAttributeConditionHandler' => '/engine/Shopware/Bundle/SearchBundleDBAL/ConditionHandler/ProductAttributeConditionHandler.php',
        'Shopware\\Components\\ReflectionHelper' => '/engine/Shopware/Components/ReflectionHelper.php',
        'Shopware\\Components\\Security\\AttributeCleanerTrait' => '/engine/Shopware/Components/Security/AttributeCleanerTrait.php',
    ];

    /**
     * @var EntityManager
     */
    private $modelManager;

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

    public function __construct(EntityManager $modelManager, $shopwareRootPath)
    {
        $this->modelManager = $modelManager;
        $this->shopwareRootPath = $shopwareRootPath;
    }

    /**
     * Prevents the class redeclaration error.
     *
     * @throws \Doctrine\ORM\ORMException
     */
    public function preventRedeclareClassError()
    {
        if (!Util::isPluginInstalled('Core', 'SwagSecurity')) {
            return;
        }

        if (Util::isPluginInstalled('Core', 'SwagSecurity', static::SWAG_SECURITY_VERSION_FIXING_REDECLARE_CLASS_ERROR)) {
            return;
        }

        $driver = $this->modelManager->getConfiguration()->getMetadataDriverImpl();

        if ((!$driver instanceof AnnotationDriver)) {
            return;
        }

        foreach (static::$SWAG_SECURITY_REPLACED_CLASSES as $replacedClass => $pathToClass) {
            $this->excludeClassFromDoctrineMetadataRegeneration($driver, $replacedClass, $pathToClass);
        }
    }

    /**
     * Prevents that the specified class is required_once by Doctrine.
     *
     * @param AnnotationDriver $driver
     * @param string $replacedClass
     * @param string $pathToClass
     */
    private function excludeClassFromDoctrineMetadataRegeneration(AnnotationDriver $driver, $replacedClass, $pathToClass)
    {
        if (!class_exists($replacedClass, false)) {
            return;
        }

        // Check if the class was loaded from the SwagSecurity plugin. If that is the case, remove the
        // original class from the Doctrine meta data generation routine.
        $reflectionClass = new \ReflectionClass($replacedClass);
        $lowerFilePath = mb_strtolower($reflectionClass->getFileName());

        if (mb_strpos($lowerFilePath, 'swagsecurity') === false) {
            return;
        }

        $driver->addExcludePaths([$this->shopwareRootPath . $pathToClass]);
    }
}
