<?php 

namespace NPS\Repository;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use NPS\Entity\IEntity;
use NPS\Model\File;
use NPS\Factory\FileFactory;
use NPS\Entity\FileEntity;

/**
 * File repository class
 * @author Lukas Korinek
 */
final class FileRepository implements IObjectRepository
{
    /** @var EntityRepository $entityRepository */
    private $entityRepository;

    /** @var FileFactory $factory */
    private $factory;

    public function __construct(EntityManagerInterface $em, FileFactory $factory)
    {
        $this->entityRepository = $em->getRepository(FileEntity::class);
        $this->factory = $factory;
    }

    /**
     * @inheritdoc
     */
    public function getById($id)
    {
        $entity = $this->entityRepository->find($id);
        return $entity ? $this->factory->make($entity) : null;
    }

    /**
     * Gets a file by path
     * @return File|null
     */
    public function getByPath($path)
    {
        $entity = $this->entityRepository->findOneBy(['path' => $path]);
        return $entity ? $this->factory->make($entity) : null;
    }

    /**
     * Gets files by file type
     * @param int $type
     * @param int $limit
     * @param int $offset
     * @return array
     */
    public function getByType($type, $limit = 50, $offset = 0)
    {
        $entities = $this->entityRepository->findBy(['type' => $type], [], $limit, $offset);

        return array_map(function($entity){
            return $this->factory->make($entity);
        }, $entitites);
    }

    /**
     * Gets a file by tag and its original filename with extension
     * @param string $tag Tag to look for 
     * @param string $filename Original filename with extension, e.g. sound.wav
     * @return File|null
     */
    public function getByTagAndFilename($tag, $filename)
    {

        $builder = $this->entityRepository->createQueryBuilder('f');

        $builder = $builder
        ->where($builder->expr()->orX(
            $builder->expr()->like('f.tags', $builder->expr()->literal($tag)),
            $builder->expr()->like('f.tags', $builder->expr()->literal('%;' . $tag)),
            $builder->expr()->like('f.tags', $builder->expr()->literal($tag . ';%')),
            $builder->expr()->like('f.tags', $builder->expr()->literal('%;' . $tag . ';%'))
        ))->andWhere('f.filename LIKE :filename')->setParameter('filename', $filename);

        $result = $builder->getQuery()->getResult();
        return count($result) ? $this->factory->make(reset($result)) : null;
    }

    /**
     * Gets files by tag
     * @param string $tag
     * @param int $limit
     * @param int $offset
     * @return array
     */
    public function getByTag($tag, $limit = 50, $offset = 0)
    {
        $builder = $this->entityRepository->createQueryBuilder('f');

        $builder = $builder
        ->where($builder->expr()->orX(
            $builder->expr()->like('f.tags', $builder->expr()->literal($tag)),
            $builder->expr()->like('f.tags', $builder->expr()->literal('%;' . $tag)),
            $builder->expr()->like('f.tags', $builder->expr()->literal($tag . ';%')),
            $builder->expr()->like('f.tags', $builder->expr()->literal('%;' . $tag . ';%'))
        ));

        if($limit)
        {
            $builder = $builder->setMaxResults($limit);
        }

        if($offset)
        {
            $builder = $builder->setFirstResult($offset);
        }

        return array_map(function($entity){
            return $this->factory->make($entity);
        }, $builder->getQuery()->getResult());
    }

    /**
     * Gets a new image id available
     * @return int
     */
    public function getNewId()
    {
        $builder = $this->entityRepository->createQueryBuilder('f');
        return $builder->select($builder->expr()->count('f'))->getQuery()->getSingleScalarResult() + 1;
    }

}

