<commit_before><?php

namespace Oro\Bundle\ActivityBundle\Manager;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\QueryBuilder;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;

use Oro\Bundle\ActivityBundle\Event\ActivityEvent;
use Oro\Bundle\ActivityBundle\Event\Events;
use Oro\Bundle\ActivityBundle\EntityConfig\ActivityScope;
use Oro\Bundle\ActivityBundle\Model\ActivityInterface;
use Oro\Bundle\EntityBundle\ORM\DoctrineHelper;
use Oro\Bundle\EntityBundle\ORM\EntityClassResolver;
use Oro\Bundle\EntityBundle\ORM\SqlQueryBuilder;
use Oro\Bundle\EntityConfigBundle\Config\ConfigInterface;
use Oro\Bundle\EntityConfigBundle\Provider\ConfigProvider;
use Oro\Bundle\EntityExtendBundle\Entity\Manager\AssociationManager;
use Oro\Bundle\EntityExtendBundle\Extend\RelationType;
use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper;

/**
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
 */
class ActivityManager
{
    /** @var DoctrineHelper */
    protected $doctrineHelper;

    /** @var EntityClassResolver */
    protected $entityClassResolver;

    /** @var ConfigProvider */
    protected $activityConfigProvider;

    /** @var ConfigProvider */
    protected $groupingConfigProvider;

    /** @var ConfigProvider */
    protected $entityConfigProvider;

    /** @var ConfigProvider */
    protected $extendConfigProvider;

    /** @var AssociationManager */
    protected $associationManager;

    /** @var EventDispatcherInterface */
    protected $eventDispatcher;

    /**
     * @param DoctrineHelper      $doctrineHelper
     * @param EntityClassResolver $entityClassResolver
     * @param ConfigProvider      $activityConfigProvider
     * @param ConfigProvider      $groupingConfigProvider
     * @param ConfigProvider      $entityConfigProvider
     * @param ConfigProvider      $extendConfigProvider
     * @param AssociationManager  $associationManager
     */
    public function __construct(
        DoctrineHelper $doctrineHelper,
        EntityClassResolver $entityClassResolver,
        ConfigProvider $activityConfigProvider,
        ConfigProvider $groupingConfigProvider,
        ConfigProvider $entityConfigProvider,
        ConfigProvider $extendConfigProvider,
        AssociationManager $associationManager
    ) {
        $this->doctrineHelper         = $doctrineHelper;
        $this->entityClassResolver    = $entityClassResolver;
        $this->activityConfigProvider = $activityConfigProvider;
        $this->groupingConfigProvider = $groupingConfigProvider;
        $this->entityConfigProvider   = $entityConfigProvider;
        $this->extendConfigProvider   = $extendConfigProvider;
        $this->associationManager     = $associationManager;
    }

    /**
     * @param EventDispatcherInterface $eventDispatcher
     */
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
    {
        $this->eventDispatcher = $eventDispatcher;
    }

    /**
     * Indicates whether the given entity type has any activity associations or not
     *
     * @param string $entityClass
     *
     * @return bool
     */
    public function hasActivityAssociations($entityClass)
    {
        if (!$this->activityConfigProvider->hasConfig($entityClass)) {
            return false;
        }

        $activityClassNames = $this->activityConfigProvider->getConfig($entityClass)->get('activities');

        return !empty($activityClassNames);
    }

    /**
     * Indicates whether the given entity type can be associated with the given activity or not
     *
     * @param string $entityClass
     * @param string $activityEntityClass
     *
     * @return bool
     */
    public function hasActivityAssociation($entityClass, $activityEntityClass)
    {
        if (!$this->activityConfigProvider->hasConfig($entityClass)) {
            return false;
        }

        $activityClassNames = $this->activityConfigProvider->getConfig($entityClass)->get('activities');

        return !empty($activityClassNames) && in_array($activityEntityClass, $activityClassNames);
    }

    /**
     * Associates the given target entity with the activity entity
     * If the target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object            $targetEntity
     *
     * @return bool TRUE if an association was added; otherwise, FALSE
     */
    public function addActivityTarget(ActivityInterface $activityEntity, $targetEntity)
    {
        if ($targetEntity !== null
            && $activityEntity->supportActivityTarget(get_class($targetEntity))
            && !$activityEntity->hasActivityTarget($targetEntity)
        ) {
            $activityEntity->addActivityTarget($targetEntity);

            if ($this->eventDispatcher) {
                $event = new ActivityEvent($activityEntity, $targetEntity);
                $this->eventDispatcher->dispatch(Events::ADD_ACTIVITY, $event);
            }

            return true;
        }

        return false;
    }

    /**
     * Associates the given target entities with the activity entity
     * If some target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object|object[]   $targetEntities
     *
     * @return bool TRUE if at least one association was added; otherwise, FALSE
     */
    public function addActivityTargets(ActivityInterface $activityEntity, array $targetEntities)
    {
        $hasChanges = false;

        foreach ($targetEntities as $targetEntity) {
            if ($this->addActivityTarget($activityEntity, $targetEntity)) {
                $hasChanges = true;
            }
        }

        return $hasChanges;
    }

    /**
     * Removes an association of the given target entity with the activity entity
     * If the target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object            $targetEntity
     *
     * @return bool TRUE if an association was removed; otherwise, FALSE
     */
    public function removeActivityTarget(ActivityInterface $activityEntity, $targetEntity)
    {
        if ($targetEntity !== null
            && $activityEntity->supportActivityTarget(get_class($targetEntity))
            && $activityEntity->hasActivityTarget($targetEntity)
        ) {
            $activityEntity->removeActivityTarget($targetEntity);
            if ($this->eventDispatcher) {
                $event = new ActivityEvent($activityEntity, $targetEntity);
                $this->eventDispatcher->dispatch(Events::REMOVE_ACTIVITY, $event);
            }

            return true;
        }

        return false;
    }

    /**
     * Removes an association of the given $oldTargetEntity and associates the given $newTargetEntity
     * with the activity entity
     * If some target entity has no association with the given activity entity it will be skipped
     *<commit_msg>CRM-4449: Move Context grid to the Activity Bundle - add setActivityTargets method to ActivityManager<commit_after><?php

namespace Oro\Bundle\ActivityBundle\Manager;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\QueryBuilder;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;

use Oro\Bundle\ActivityBundle\Event\ActivityEvent;
use Oro\Bundle\ActivityBundle\Event\Events;
use Oro\Bundle\ActivityBundle\EntityConfig\ActivityScope;
use Oro\Bundle\ActivityBundle\Model\ActivityInterface;
use Oro\Bundle\EntityBundle\ORM\DoctrineHelper;
use Oro\Bundle\EntityBundle\ORM\EntityClassResolver;
use Oro\Bundle\EntityBundle\ORM\SqlQueryBuilder;
use Oro\Bundle\EntityConfigBundle\Config\ConfigInterface;
use Oro\Bundle\EntityConfigBundle\Provider\ConfigProvider;
use Oro\Bundle\EntityExtendBundle\Entity\Manager\AssociationManager;
use Oro\Bundle\EntityExtendBundle\Extend\RelationType;
use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper;

/**
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
 */
class ActivityManager
{
    /** @var DoctrineHelper */
    protected $doctrineHelper;

    /** @var EntityClassResolver */
    protected $entityClassResolver;

    /** @var ConfigProvider */
    protected $activityConfigProvider;

    /** @var ConfigProvider */
    protected $groupingConfigProvider;

    /** @var ConfigProvider */
    protected $entityConfigProvider;

    /** @var ConfigProvider */
    protected $extendConfigProvider;

    /** @var AssociationManager */
    protected $associationManager;

    /** @var EventDispatcherInterface */
    protected $eventDispatcher;

    /**
     * @param DoctrineHelper      $doctrineHelper
     * @param EntityClassResolver $entityClassResolver
     * @param ConfigProvider      $activityConfigProvider
     * @param ConfigProvider      $groupingConfigProvider
     * @param ConfigProvider      $entityConfigProvider
     * @param ConfigProvider      $extendConfigProvider
     * @param AssociationManager  $associationManager
     */
    public function __construct(
        DoctrineHelper $doctrineHelper,
        EntityClassResolver $entityClassResolver,
        ConfigProvider $activityConfigProvider,
        ConfigProvider $groupingConfigProvider,
        ConfigProvider $entityConfigProvider,
        ConfigProvider $extendConfigProvider,
        AssociationManager $associationManager
    ) {
        $this->doctrineHelper         = $doctrineHelper;
        $this->entityClassResolver    = $entityClassResolver;
        $this->activityConfigProvider = $activityConfigProvider;
        $this->groupingConfigProvider = $groupingConfigProvider;
        $this->entityConfigProvider   = $entityConfigProvider;
        $this->extendConfigProvider   = $extendConfigProvider;
        $this->associationManager     = $associationManager;
    }

    /**
     * @param EventDispatcherInterface $eventDispatcher
     */
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
    {
        $this->eventDispatcher = $eventDispatcher;
    }

    /**
     * Indicates whether the given entity type has any activity associations or not
     *
     * @param string $entityClass
     *
     * @return bool
     */
    public function hasActivityAssociations($entityClass)
    {
        if (!$this->activityConfigProvider->hasConfig($entityClass)) {
            return false;
        }

        $activityClassNames = $this->activityConfigProvider->getConfig($entityClass)->get('activities');

        return !empty($activityClassNames);
    }

    /**
     * Indicates whether the given entity type can be associated with the given activity or not
     *
     * @param string $entityClass
     * @param string $activityEntityClass
     *
     * @return bool
     */
    public function hasActivityAssociation($entityClass, $activityEntityClass)
    {
        if (!$this->activityConfigProvider->hasConfig($entityClass)) {
            return false;
        }

        $activityClassNames = $this->activityConfigProvider->getConfig($entityClass)->get('activities');

        return !empty($activityClassNames) && in_array($activityEntityClass, $activityClassNames);
    }

    /**
     * Associates the given target entity with the activity entity
     * If the target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object            $targetEntity
     *
     * @return bool TRUE if an association was added; otherwise, FALSE
     */
    public function addActivityTarget(ActivityInterface $activityEntity, $targetEntity)
    {
        if ($targetEntity !== null
            && $activityEntity->supportActivityTarget(get_class($targetEntity))
            && !$activityEntity->hasActivityTarget($targetEntity)
        ) {
            $activityEntity->addActivityTarget($targetEntity);

            if ($this->eventDispatcher) {
                $event = new ActivityEvent($activityEntity, $targetEntity);
                $this->eventDispatcher->dispatch(Events::ADD_ACTIVITY, $event);
            }

            return true;
        }

        return false;
    }

    /**
     * Associates the given target entities with the activity entity
     * If some target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object|object[]   $targetEntities
     *
     * @return bool TRUE if at least one association was added; otherwise, FALSE
     */
    public function addActivityTargets(ActivityInterface $activityEntity, array $targetEntities)
    {
        $hasChanges = false;

        foreach ($targetEntities as $targetEntity) {
            if ($this->addActivityTarget($activityEntity, $targetEntity)) {
                $hasChanges = true;
            }
        }

        return $hasChanges;
    }

    /**
     * Removes all activity entity associations and associates with the given target entities
     * If some target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object|object[]   $targetEntities
     *
     * @return bool TRUE if at least one association was changed; otherwise, FALSE
     */
    public function setActivityTargets(ActivityInterface $activityEntity, array $targetEntities)
    {
        $hasChanges = false;

        $oldTargetEntities = $activityEntity->getActivityTargetEntities();

        foreach ($oldTargetEntities as $oldTargetEntity) {
            if (!in_array($oldTargetEntity, $targetEntities)) {
                $this->removeActivityTarget($activityEntity, $oldTargetEntity);
                $hasChanges = true;
            }
        }

        if ($this->addActivityTargets($activityEntity, $targetEntities)) {
            $hasChanges = true;
        }

        return $hasChanges;
    }

    /**
     * Removes an association of the given target entity with the activity entity
     * If the target entity has no association with the given activity entity it will be skipped
     *
     * @param ActivityInterface $activityEntity
     * @param object            $targetEntity
     *
     * @return bool TRUE if an association was removed; otherwise, FALSE
     */
    public function removeActivityTarget(ActivityInterface $activityEntity, $targetEntity)
    {
        if ($targetEntity !== null
            && $activityEntity->supportActivityTarget(get_class($targetEntity))
            && $activityEntity->hasActivityTarget($targetEntity)
        ) {
            $activityEntity->removeActivityTarget($targetEntity);
            if ($this->eventDispatcher) {
                $event = new ActivityEvent($activityEntity, $targetEntity);
                $this->eventDispatcher->dispatch(Events::REMOVE_ACTIVITY, $event);
            }

            return true;
        }

        return false;
    }

    /**
     * Removes an association of the given $oldTargetEntity and associates the given $newTargetEntity
     * with the activity entity
     * If some target entity has no association with the given activity entity it will be skipped
     *
{'fraction_non_alphanumeric': 0.08745972249621885, 'fraction_numerical': 0.00026303675938712433, 'mean_word_length': 2.967649360813984, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3399262', 'n_tokens_mistral': 3760, 'n_tokens_neox': 3658, 'n_words': 924}