<?php

namespace Port\Doctrine;

use Doctrine\Persistence\ObjectManager;
use Doctrine\ORM\Internal\Hydration\IterableResult;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Port\Reader\CountableReader;

/**
 * Reads entities through the Doctrine ORM
 *
 * @author David de Boer <david@ddeboer.nl>
 */
class DoctrineReader implements CountableReader
{
    /**
     * @var ObjectManager
     */
    protected $objectManager;

    /**
     * @var string
     */
    protected $objectName;

    /**
     * @var IterableResult
     */
    protected $iterableResult;

    /** @var QueryBuilder */
    protected $queryBuilder;

    /**
     * @param ObjectManager $objectManager
     * @param string $objectName e.g. YourBundle:YourEntity
     */
    public function __construct(ObjectManager $objectManager, $objectName)
    {
        $this->objectManager = $objectManager;
        $this->objectName = $objectName;
    }

    public function setQueryBuilder(QueryBuilder $queryBuilder)
    {
        $this->queryBuilder = $queryBuilder;

        return $this;
    }

    protected function getQueryBuilder()
    {
        if ($this->queryBuilder === null) {
            $this->queryBuilder = $this->objectManager->createQueryBuilder()
                ->from($this->objectName, 'o');
        }

        return clone $this->queryBuilder;
    }

    /**
     * {@inheritdoc}
     */
    public function getFields()
    {
        return $this->objectManager->getClassMetadata($this->objectName)
            ->getFieldNames();
    }

    /**
     * {@inheritdoc}
     */
    public function current()
    {
        return current($this->iterableResult->current());
    }

    /**
     * {@inheritdoc}
     */
    public function next()
    {
        $this->iterableResult->next();
    }

    /**
     * {@inheritdoc}
     */
    public function key()
    {
        return $this->iterableResult->key();
    }

    /**
     * {@inheritdoc}
     */
    public function valid()
    {
        return $this->iterableResult->valid();
    }

    /**
     * {@inheritdoc}
     */
    public function rewind()
    {
        if (!$this->iterableResult) {
            $query = $this->getQueryBuilder()->select('o')->getQuery();

            $this->iterableResult = $query->iterate([], Query::HYDRATE_ARRAY);
        }

        $this->iterableResult->rewind();
    }

    /**
     * {@inheritdoc}
     */
    public function count()
    {
        $query = $this->getQueryBuilder()->select('count(o)')->getQuery();

        return $query->getSingleScalarResult();
    }
}
