<?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\Installation\AclResource;

use Doctrine\ORM\EntityManager;
use Shopware\Models\User\Privilege;
use Shopware\Models\User\Resource;
use Shopware\Models\User\Rule;

class AclResourceRemover
{

    /**
     * @var ResourceHelper
     */
    private $helper;

    /**
     * @var \Shopware_Components_Acl
     */
    private $acl;

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

    public function __construct(AclResourceHelper $helper, \Shopware_Components_Acl $acl, EntityManager $entityManager)
    {
        $this->helper = $helper;
        $this->acl = $acl;
        $this->entityManager = $entityManager;
    }

    /**
     * If it exists, deletes the Resource with name $resourceName and all related privileges and rules.
     * @return void
     */
    public function deleteResource($resourceName)
    {
        $entityManager = $this->entityManager;

        /* Use a transaction because we only want to delete either everything regarding this resource, or nothing to
         * prevent leaving the sytem in a half-configured state. */
        $entityManager->beginTransaction();
        try {
            $this->deleteResourceTransaction($resourceName);
            $entityManager->commit();
        } catch (\Exception $e) {
            $entityManager->rollback();
            throw $e;
        }
    }

    /**
     * @see AclResourceRemover::deleteResource
     * @return void
     */
    private function deleteResourceTransaction($resourceName)
    {
        $entityManager = $this->entityManager;

        $resource = $this->helper->findResourceByName($resourceName);
        if ($resource === null) {
            return; // We won't attempt to remove things that are not there.
        }

        $privileges = $this->helper->findPrivilegesByResourceId($resource->getId());
        $rules = $this->helper->findRulesForPrivileges($privileges, $resource->getId());

        /* Delete existing ACL rules and privileges regarding the Resource.
         * \Shopware_Components_Acl::deleteResource (which we call later) deletes them as well, but does not detach
         * them from Doctrine's EntityManager. Hence, at a later stage, they may be discovered again and Doctrine
         * complains about them not being marked for persisting. */

        // Delete Privileges for the Resource.
        foreach ($privileges as $privilege) {
            $entityManager->remove($privilege);
        }

        // Delete Rules for the Resource.
        foreach ($rules as $rule) {
            $entityManager->remove($rule);
        }
        $entityManager->flush(array_merge($privileges, $rules));

        $this->acl->deleteResource($resourceName);
    }
}
