<?php
/**
 * Update MetaTags when saving TaggableContentInterface entity
 *
 * @author Elze Kool <info@visualmedia.nl>
 */

namespace VisualM\TagManagerBundle\Doctrine\EventListener;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use VisualM\TagManagerBundle\Content\TaggableContentInterface;
use VisualM\TagManagerBundle\Entity\MetaTag;
use VisualM\TagManagerBundle\Model\MetaTagCollection;


/**
 * Update MetaTags when saving TaggableContentInterface entity
 *
 * @author Elze Kool <info@visualmedia.nl>
 */
class MetaTagCollectionSubscriber implements EventSubscriber, ContainerAwareInterface
{
    use ContainerAwareTrait;
    
    /**
     * Needs Flush
     * @var bool
     */
    private $needsFlush = false;

    /**
     * Collections before saving object
     * used to determine which objects are removed
     * @var array
     */
    private $presetCollections = [];

    
    /**
     * Specifies the list of events to listen
     *
     * @return array
     */
    public function getSubscribedEvents()
    {
        return array(
            'postLoad',
            'postPersist',
            'postUpdate',
            'postFlush'
        );
    }

    /**
     * PostLoad event
     *
     * @param LifecycleEventArgs $args Event Data
     */
    public function postLoad(LifecycleEventArgs $args)
    {
        if (!($args->getEntity() instanceof TaggableContentInterface)) {
            return;
        }

        if ($args->getEntity()->getMetaTagCollection() === null) {
            $args->getEntity()->setMetaTagCollection(new MetaTagCollection());
        }
    }

    /**
     * Entity after load callback. Used in determining which tags are removed
     * 
     * @param TaggableContentInterface $entity Entity
     */
    public function afterLoad(TaggableContentInterface $entity)
    {
		if ($entity->getMetaTagCollection() === null) {
			$entity->setMetaTagCollection(new MetaTagCollection());
		}
        $this->presetCollections[spl_object_hash($entity)] = $entity->getMetaTagCollection()->getMetaTags()->toArray();
    }

    /**
     * Class with TaggableContentInterface is added or updated
     *
     * @param LifecycleEventArgs $args Event Data
     */
    protected function onTaggableContentInterfaceUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        /* @var $entity TaggableContentInterface */
		
		if ($entity->getMetaTagCollection() === null) {
			return;
		}

        // Remove tags that are not available anymore
        if (isset($this->presetCollections[spl_object_hash($entity)])) {
            foreach($this->presetCollections[spl_object_hash($entity)] as $meta_tag) {
                if (!$entity->getMetaTagCollection()->getMetaTags()->contains($meta_tag)) {
                    $args->getEntityManager()->remove($meta_tag);
                    $this->needsFlush = true;
                }
            }
            unset($this->presetCollections[spl_object_hash($entity)]);
        }

        // Add/update tags provided
        foreach($entity->getMetaTagCollection()->getMetaTags() as $meta_tag) {
            /* @var $meta_tag MetaTag */
            $meta_tag->setContentId($entity->getContentId());
            $meta_tag_preset = $meta_tag->getMetaTagPreset();

            if ($meta_tag_preset->getInhoud() != $meta_tag->getInhoud()) {
                $meta_tag->setInhoudGewijzigd(true);
            } else if ($meta_tag_preset->getInhoudIsExpression() != $meta_tag->getInhoudIsExpression()) {
                $meta_tag->setInhoudGewijzigd(true);
            }

            if ($meta_tag_preset->getZichtbaar() != $meta_tag->getZichtbaar()) {
                $meta_tag->setZichtbaarGewijzigd(true);
            } else if ($meta_tag_preset->getZichtbaarIsExpression() != $meta_tag->getZichtbaarIsExpression()) {
                $meta_tag->setZichtbaarGewijzigd(true);
            }

            $args->getEntityManager()->persist($meta_tag);
            $this->needsFlush = true;
        }
    }



    /**
     * postPersist event
     *
     * @param LifecycleEventArgs $args Event Data
     */
    public function postPersist(LifecycleEventArgs $args)
    {
        if ($args->getEntity() instanceof TaggableContentInterface) {
            $this->onTaggableContentInterfaceUpdate($args);
        }
    }

    /**
     * postUpdate event
     *
     * @param LifecycleEventArgs $args Event Data
     */
    public function postUpdate(LifecycleEventArgs $args)
    {
        if ($args->getEntity() instanceof TaggableContentInterface) {
            $this->onTaggableContentInterfaceUpdate($args);
        }
    }


    public function postFlush(PostFlushEventArgs $eventArgs)
    {
        if ($this->needsFlush) {
            $this->needsFlush = false;
            $eventArgs->getEntityManager()->flush();
        }
    }

    
}
