<?php


namespace Webapp\Core\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Serializer\Filter\GroupFilter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Shared\Authentication\Entity\Site;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Webapp\Core\Validator\UniqueAttributeInParent;

/**
 * Class GeneratorVariable
 * @package Webapp\Core\Entity
 * @ApiResource(
 *     collectionOperations={
 *         "get"={},
 *         "post"={
 *              "security_post_denormalize"="is_granted('ROLE_PLATFORM_MANAGER', object.getSite())",
 *              "denormalization_context"={"groups"={"generator_variable_post"}}
 *          },
 *     },
 *     itemOperations={
 *          "get"={},
 *          "patch"={
 *              "security_post_denormalize"="is_granted('ROLE_PLATFORM_MANAGER', object.getSite())",
 *              "denormalization_context"={"groups"={"generator_variable_post"}}
 *          },
 *          "delete"={
 *              "security"="is_granted('ROLE_PLATFORM_MANAGER', object.getSite()) and is_granted('GENERATOR_VARIABLE_DELETE', object)"
 *          }
 *     }
 * )
 * @ApiFilter(SearchFilter::class, properties={"site": "exact", "generatorVariable": "exact", "project": "exact", "projectData.sessions": "exact", "projectData": "exact"})
 * @ApiFilter(GroupFilter::class, arguments={"whitelist"={"project_explorer_view", "connected_variables"}})
 *
 * @ORM\Entity()
 * @ORM\Table(name="variable_generator", schema="webapp")
 */
class GeneratorVariable extends AbstractVariable
{
    /**
     * @var string
     *
     * @ORM\Column(type="string", nullable=false)
     * @Groups({"project_explorer_view", "generator_variable_post", "semi_automatic_variable", "webapp_data_view", "data_explorer_view", "connected_variables", "data_entry_synthesis", "project_synthesis", "variable_synthesis", "fusion_result", "webapp_data_path", "webapp_data_fusion"})
     * @Assert\NotBlank
     * @UniqueAttributeInParent(parentsAttributes={"site.generatorVariables", "project.generatorVariables", "project.simpleVariables"})
     */
    protected string $name;

    /**
     * @var Site|null
     *
     * @ORM\ManyToOne(targetEntity="Shared\Authentication\Entity\Site", inversedBy="generatorVariables")
     * @Groups({"generator_variable_post"})
     */
    protected ?Site $site;

    /**
     * @var string
     *
     * @ORM\Column(type="string")
     * @Groups({"generator_variable_post"})
     */
    private $generatedPrefix;

    /**
     * @var bool
     *
     * @ORM\Column(type="boolean")
     * @Groups({"generator_variable_post"})
     */
    private $numeralIncrement;

    /**
     * @var bool
     *
     * @ORM\Column(type="boolean")
     * @Groups({"generator_variable_post"})
     */
    private $pathWayHorizontal;

    /**
     * @var bool
     *
     * @ORM\Column(type="boolean")
     * @Groups({"generator_variable_post"})
     */
    private $directCounting;

    /**
     * @var Collection<array-key, SimpleVariable> | array<SimpleVariable>
     *
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\SimpleVariable", mappedBy="generatorVariable", cascade={"persist", "remove"}, orphanRemoval=true)
     * @Groups({"project_explorer_view", "generator_variable_post", "data_explorer_view", "webapp_data_view"})
     */
    private $generatedSimpleVariables;

    /**
     * @var Collection<array-key, GeneratorVariable> | array<GeneratorVariable>
     *
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\GeneratorVariable", mappedBy="generatorVariable", cascade={"persist", "remove"}, orphanRemoval=true)
     * @Groups({"project_explorer_view", "generator_variable_post", "data_explorer_view", "webapp_data_view"})
     */
    private $generatedGeneratorVariables;

    /**
     * @var GeneratorVariable|null
     *
     * @ORM\ManyToOne(targetEntity="Webapp\Core\Entity\GeneratorVariable",inversedBy="generatedGeneratorVariables")
     * @Groups({"data_entry_synthesis"})
     */
    protected ?GeneratorVariable $generatorVariable;

    /**
     * @var Project|null
     *
     * @ORM\ManyToOne(targetEntity="Webapp\Core\Entity\Project", inversedBy="generatorVariables")
     * @Groups({"generator_variable_post"})
     */
    protected ?Project $project;

    /**
     * @var Collection | array<Test>
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Test",mappedBy="variableGenerator", cascade={"persist", "remove"}, orphanRemoval=true)
     * @Groups({"project_explorer_view", "project_synthesis", "variable_synthesis"})
     */
    protected $tests;

    /**
     * @var ProjectData|null
     *
     * @Groups({"variable_synthesis"})
     * @ORM\ManyToOne(targetEntity="Webapp\Core\Entity\ProjectData", inversedBy="generatorVariables")
     */
    protected ?ProjectData $projectData;

    /**
     * @var Collection | array<VariableConnection>
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\VariableConnection", mappedBy="projectGeneratorVariable", cascade={"persist", "remove"}, orphanRemoval=true)
     * @Groups({"project_explorer_view", "connected_variables", "project_synthesis"})
     */
    protected $connectedVariables;

    public function __construct($name, $shortName, $repetitions, $pathLevel, $mandatory, $generatedPrefix, $numeralIncrement, $pathWayHorizontal, $directCounting)
    {
        parent::__construct();
        $this->name = $name; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->shortName = $shortName; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->repetitions = $repetitions; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->pathLevel = $pathLevel; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->mandatory = $mandatory; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->generatedPrefix = $generatedPrefix; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->numeralIncrement = $numeralIncrement; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->pathWayHorizontal = $pathWayHorizontal; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->directCounting = $directCounting; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->generatedSimpleVariables = new ArrayCollection();
        $this->generatedGeneratorVariables = new ArrayCollection();
        $this->site = null;
        $this->project = null;
        $this->generatorVariable = null;
        $this->projectData = null;
    }

    /**
     * @return mixed
     * @Groups("project_explorer_view")
     */
    public function getId()
    {
        return parent::getId();
    }

    /**
     * @return mixed
     * @Groups("project_synthesis")
     */
    public function getGeneratedVariables()
    {
        return array_merge(
            $this->getGeneratedSimpleVariables()->toArray(),
            $this->getGeneratedGeneratorVariables()->toArray());
    }

    /**
     * @return string
     */
    public function getGeneratedPrefix(): string
    {
        return $this->generatedPrefix;
    }

    /**
     * @param string $generatedPrefix
     * @return GeneratorVariable
     */
    public function setGeneratedPrefix(string $generatedPrefix): GeneratorVariable
    {
        $this->generatedPrefix = $generatedPrefix;
        return $this;
    }

    /**
     * @return bool
     */
    public function isNumeralIncrement(): bool
    {
        return $this->numeralIncrement;
    }

    /**
     * @param bool $numeralIncrement
     * @return GeneratorVariable
     */
    public function setNumeralIncrement(bool $numeralIncrement): GeneratorVariable
    {
        $this->numeralIncrement = $numeralIncrement;
        return $this;
    }

    /**
     * @return bool
     */
    public function isPathWayHorizontal(): bool
    {
        return $this->pathWayHorizontal;
    }

    /**
     * @param bool $pathWayHorizontal
     * @return GeneratorVariable
     */
    public function setPathWayHorizontal(bool $pathWayHorizontal): GeneratorVariable
    {
        $this->pathWayHorizontal = $pathWayHorizontal;
        return $this;
    }

    /**
     * @return bool
     */
    public function isDirectCounting(): bool
    {
        return $this->directCounting;
    }

    /**
     * @param bool $directCounting
     * @return GeneratorVariable
     */
    public function setDirectCounting(bool $directCounting): GeneratorVariable
    {
        $this->directCounting = $directCounting;
        return $this;
    }

    /**
     * @return Collection|SimpleVariable[]
     */
    public function getGeneratedSimpleVariables()
    {
        return $this->generatedSimpleVariables;
    }

    /**
     * @param Collection|SimpleVariable[] $generatedSimpleVariables
     * @return GeneratorVariable
     */
    public function setGeneratedSimpleVariables($generatedSimpleVariables)
    {
        $this->generatedSimpleVariables = $generatedSimpleVariables;
        foreach ($generatedSimpleVariables as $generatedSimpleVariable){
            $generatedSimpleVariable->setGeneratorVariable($this);
        }
        return $this;
    }

    /**
     * @param SimpleVariable $generatedSimpleVariable
     * @return GeneratorVariable
     */
    public function addGeneratedSimpleVariable($generatedSimpleVariable)
    {
        if(!$this->generatedSimpleVariables->contains($generatedSimpleVariable)){
            $this->generatedSimpleVariables->add($generatedSimpleVariable);
            $generatedSimpleVariable->setGeneratorVariable($this);
        }
        return $this;
    }

    /**
     * @param SimpleVariable $generatedSimpleVariable
     * @return GeneratorVariable
     */
    public function removeGeneratedSimpleVariable($generatedSimpleVariable)
    {
        if($this->generatedSimpleVariables->contains($generatedSimpleVariable)){
            $this->generatedSimpleVariables->removeElement($generatedSimpleVariable);
            $generatedSimpleVariable->setGeneratorVariable(null);
        }
        return $this;
    }

    /**
     * @return Collection|GeneratorVariable[]
     */
    public function getGeneratedGeneratorVariables()
    {
        return $this->generatedGeneratorVariables;
    }

    /**
     * @param Collection|GeneratorVariable[] $generatedGeneratorVariables
     * @return GeneratorVariable
     */
    public function setGeneratedGeneratorVariables($generatedGeneratorVariables)
    {
        $this->generatedGeneratorVariables = $generatedGeneratorVariables;
        foreach ($generatedGeneratorVariables as $generatedGeneratorVariable){
            $generatedGeneratorVariable->setGeneratorVariable($this);
        }
        return $this;
    }

    /**
     * @param GeneratorVariable $generatedSimpleVariable
     * @return GeneratorVariable
     */
    public function addGeneratedGeneratorVariable($generatedGeneratorVariable)
    {
        if(!$this->generatedGeneratorVariables->contains($generatedGeneratorVariable)){
            $this->generatedGeneratorVariables->add($generatedGeneratorVariable);
            $generatedGeneratorVariable->setGeneratorVariable($this);
        }
        return $this;
    }

    /**
     * @param GeneratorVariable $generatedGeneratorVariable
     * @return GeneratorVariable
     */
    public function removeGeneratedGeneratorVariable($generatedGeneratorVariable)
    {
        if($this->generatedGeneratorVariables->contains($generatedGeneratorVariable)){
            $this->generatedGeneratorVariables->removeElement($generatedGeneratorVariable);
            $generatedGeneratorVariable->setGeneratorVariable(null);
        }
        return $this;
    }

    /**
     * @return Site|null
     */
    public function getSite(): ?Site
    {
        return $this->site;
    }

    /**
     * @param Site|null $site
     * @return GeneratorVariable
     */
    public function setSite(?Site $site): GeneratorVariable
    {
        $this->site = $site;
        $this->project = null;
        $this->generatorVariable = null;
        return $this;
    }

    /**
     * @return GeneratorVariable|null
     */
    public function getGeneratorVariable(): ?GeneratorVariable
    {
        return $this->generatorVariable;
    }

    /**
     * @param GeneratorVariable|null $generatorVariable
     * @return GeneratorVariable
     */
    public function setGeneratorVariable(?GeneratorVariable $generatorVariable): GeneratorVariable
    {
        $this->generatorVariable = $generatorVariable;
        $this->project = null;
        $this->site = null;
        return $this;
    }

    /**
     * @return Project|null
     */
    public function getProject(): ?Project
    {
        return $this->project;
    }

    /**
     * @param Project|null $project
     * @return GeneratorVariable
     */
    public function setProject(?Project $project): GeneratorVariable
    {
        $this->project = $project;
        $this->site = null;
        $this->generatorVariable = null;
        return $this;
    }

    /**
     * @return ProjectData|null
     */
    public function getProjectData(): ?ProjectData
    {
        return $this->projectData;
    }

    /**
     * @param ProjectData|null $projectData
     * @return GeneratorVariable
     */
    public function setProjectData(?ProjectData $projectData): GeneratorVariable
    {
        $this->projectData = $projectData;
        return $this;
    }
}
