<?php
/**
 * MetaTagCollection FormType
 *
 * @author Elze Kool <info@visualmedia.nl>
 */

namespace VisualM\TagManagerBundle\Form\Type;

use RuntimeException;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use VisualM\TagManagerBundle\Content\TaggableContentInterface;
use VisualM\TagManagerBundle\Doctrine\EventListener\MetaTagCollectionSubscriber;
use VisualM\TagManagerBundle\Entity\MetaTag;
use VisualM\TagManagerBundle\Entity\MetaTagRepository;
use VisualM\TagManagerBundle\Entity\MetaTagSetRepository;
use VisualM\TagManagerBundle\Model\MetaTagCollection;
use VisualM\TagManagerBundle\Util\TaggableManagerRegistry;

/**
 * MetaTagCollection FormType
 *
 * @author Elze Kool <info@visualmedia.nl>
 */
class MetaTagCollectionType extends AbstractType
{
    /**
     * Taggable Manager Registry
     * @var TaggableManagerRegistry
     */
    protected $taggableManagerRegistry;

    /**
     * MetaTagSet Manager
     * @var MetaTagSetRepository
     */
    protected $metaTagSetManager;

    /**
     * MetaTag Manager
     * @var MetaTagRepository
     */
    protected $metaTagManager;

    /**
     * MetaTagCollectionSubscriber
     * @var MetaTagCollectionSubscriber
     */
    protected $metaTagCollectionSubscriber;
    
    /**
     * Constructor
     *
     * @param TaggableManagerRegistry     $taggableManagerRegistry Taggable Manager Registry
     * @param MetaTagSetRepository        $metaTagSetManager                MetaTagSet Manager
     * @param MetaTagRepository           $metaTagManager                   MetaTag Manager
     * @param MetaTagCollectionSubscriber $metaTagCollectionSubscriber      MetaTagCollectionSubscriber     
     */
    public function __construct(
        TaggableManagerRegistry $taggableManagerRegistry,
        MetaTagSetRepository $metaTagSetManager,
        MetaTagRepository $metaTagManager,
        MetaTagCollectionSubscriber $metaTagCollectionSubscriber
    ) {
        $this->taggableManagerRegistry = $taggableManagerRegistry;
        $this->metaTagSetManager = $metaTagSetManager;
        $this->metaTagManager = $metaTagManager;
        $this->metaTagCollectionSubscriber = $metaTagCollectionSubscriber;
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if ($options['content_name'] === null) {
            throw new RuntimeException("content_name option not provided");
        } else if (null === ($this->taggableManagerRegistry->getManager($options['content_name']))) {
            throw new RuntimeException(sprintf("TaggableContentManager for %s is not registrated with the TaggableManagerRegistry", $options['content_name']));
        }

        // Preset data needed for event handler
        $meta_tag_set_manager = $this->metaTagSetManager;
        $meta_tag_manager = $this->metaTagManager;
        $meta_tag_collection_subscriber = $this->metaTagCollectionSubscriber;
        $content_name = $options['content_name'];

        // Add event listener to add/load metaTags into collection
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use (
            $meta_tag_manager,
            $meta_tag_set_manager,
            $content_name,
            $meta_tag_collection_subscriber
        ) {

            $form = $event->getForm();
            $data = $event->getData();
            
            // Get content item from parent form
            if (null === ($content = $form->getParent()->getData())) {
                throw new RuntimeException('No parent form data found');
            } else if (!($content instanceof TaggableContentInterface)) {
                throw new RuntimeException(sprintf('Content class %s does not implement TaggableContentInterface', get_class($content)));
            }
            /* @var $content TaggableContentInterface */

            // For entities from the database the MetaTagCollection is initialized by the MetaTagCollectionSubscriber
            // and for new entities this should be done in the constructor. Make sure this is done correctly
            if ($data === null) {
				$data = new MetaTagCollection();
				$event->setData($data);
            }

            // Check if content has an contentId already
            if ($content->getContentId() !== null) {
                foreach($meta_tag_manager->getIndex(['content_id' => $content->getContentId()]) as $meta_tag) {
                    $data->getMetaTags()->add($meta_tag);
                }
            }

            // Add MetaTags that should be added automaticly
            foreach($meta_tag_set_manager->getIndex() as $meta_tag_set) {

                // Check if tagset is default for this content type
                if (!in_array($content_name, $meta_tag_set->getContentTypes())) { continue; }

                foreach($meta_tag_set->getMetaTagPresets() as $meta_tag_preset) {

                    // Check if preset is already added to content
                    foreach($data->getMetaTags() as $meta_tag) {
                        if ($meta_tag->getMetaTagPreset()->getId() === $meta_tag_preset->getId()) {
                            continue 2;
                        }
                    }

                    // Create new tag from preset
                    $meta_tag = new MetaTag();
                    $meta_tag->setAutoAdded(true);
                    $meta_tag->setInhoud($meta_tag_preset->getInhoud());
                    $meta_tag->setInhoudIsExpression($meta_tag_preset->getInhoudIsExpression());
                    $meta_tag->setInhoudGewijzigd(false);
                    $meta_tag->setZichtbaar($meta_tag_preset->getZichtbaar());
                    $meta_tag->setZichtbaarIsExpression($meta_tag_preset->getZichtbaarIsExpression());
                    $meta_tag->setZichtbaarGewijzigd(false);
                    $meta_tag->setMetaTagPreset($meta_tag_preset);
                    $data->getMetaTags()->add($meta_tag);

                }
            }

            // Push completly loaded object into subscriber so that it knows
            // which tags are deleted
            $meta_tag_collection_subscriber->afterLoad($content);

            // Add metaTags to form
            $form->add('metaTags', CollectionType::class, array(
                'entry_type' => MetaTagType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => true,
                'label' => false,
                'prototype' => true
            ));

        });
        
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'meta_tag_collection';
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'VisualM\TagManagerBundle\Model\MetaTagCollection',
            'translation_domain' => 'forms',
            'content_name' => null
        ));

    }

}
