<?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\IdentifiedEntity;
use Shared\Authentication\Entity\Site;
use Shared\Enumeration\Annotation\EnumType;
use Shared\Utils\ArrayCollectionUtils;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Webapp\Core\Validator\UniqueAttributeInParent;

/**
 * @ApiResource(
 *     denormalizationContext={"groups"={"semi_automatic_variable"}},
 *     normalizationContext={"groups"={"semi_automatic_variable"}},
 *     collectionOperations={
 *         "get"={},
 *         "post"={
 *              "security_post_denormalize"="is_granted('ROLE_PLATFORM_MANAGER', object.getSite())"
 *          },
 *     },
 *     itemOperations={
 *          "get"={},
 *          "patch"={
 *              "security_post_denormalize"="is_granted('ROLE_PLATFORM_MANAGER', object.getSite())"
 *          },
 *          "delete"={
 *              "security"="is_granted('ROLE_PLATFORM_MANAGER', object.getSite())"
 *          }
 *     }
 * )
 *
 * @ApiFilter(SearchFilter::class, properties={"site": "exact", "alias": "exact",  "managedVariables": "exact", "project": "exact"})
 * @ApiFilter(GroupFilter::class, arguments={"whitelist"={"project_explorer_view", "connected_variables"}})
 *
 * @ORM\Entity
 *
 * @ORM\Table(name="device", schema="webapp")
 */
class Device extends IdentifiedEntity
{
    use OpenSilexEntity;

    /**
     * @ORM\Column(type="string")
     *
     * @Assert\NotBlank
     *
     * @UniqueAttributeInParent(parentsAttributes={"site.devices", "project.devices"})
     *
     * @Groups({"semi_automatic_variable", "project_explorer_view", "data_explorer_view"})
     */
    private string $alias = '';

    /**
     * @ORM\Column(type="string")
     *
     * @Groups({"semi_automatic_variable"})
     */
    private string $name = '';

    /**
     * @ORM\Column(type="string")
     *
     * @Groups({"semi_automatic_variable"})
     */
    private string $manufacturer = '';

    /**
     * @ORM\Column(type="string")
     *
     * @Groups({"semi_automatic_variable"})
     */
    private string $type = '';

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

    /**
     * @var Collection<int, SemiAutomaticVariable>
     *
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\SemiAutomaticVariable", mappedBy="device", cascade={"persist", "remove"}, orphanRemoval=true)
     *
     * @Groups({"semi_automatic_variable", "project_explorer_view", "connected_variables"})
     */
    private Collection $managedVariables;

    /**
     * @ORM\Column(type="string")
     *
     * @Groups({"semi_automatic_variable"})
     *
     * @EnumType(class="Webapp\Core\Enumeration\CommunicationProtocolEnum")
     */
    private string $communicationProtocol = '';

    /**
     * @ORM\Column(type="integer")
     *
     * @Groups({"semi_automatic_variable"})
     */
    private int $frameLength = 0;

    /**
     * @ORM\Column(type="string", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     */
    private ?string $frameStart = null;

    /**
     * @ORM\Column(type="string", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     */
    private ?string $frameEnd = null;

    /**
     * @ORM\Column(type="string", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     */
    private ?string $frameCsv = null;

    /**
     * @ORM\Column(type="integer", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     */
    private ?int $baudrate = null;

    /**
     * @ORM\Column(type="integer", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     *
     * @EnumType(class="Webapp\Core\Enumeration\BitFormatEnum", nullable=true)
     */
    private ?int $bitFormat = null;

    /**
     * @ORM\Column(type="string", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     *
     * @EnumType(class="Webapp\Core\Enumeration\FlowControlEnum", nullable=true)
     */
    private ?string $flowControl = null;

    /**
     * @ORM\Column(type="string", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     *
     * @EnumType(class="Webapp\Core\Enumeration\ParityEnum", nullable=true)
     */
    private ?string $parity = null;

    /**
     * @ORM\Column(type="string", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     *
     * @EnumType(class="Webapp\Core\Enumeration\StopBitEnum", nullable=true)
     */
    private ?string $stopBit = null;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     *
     * @Groups({"semi_automatic_variable"})
     */
    private ?bool $remoteControl = null;

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

    public function __construct()
    {
        $this->managedVariables = new ArrayCollection();
    }

    /**
     * @psalm-mutation-free
     */
    public function getAlias(): string
    {
        return $this->alias;
    }

    /**
     * @return $this
     */
    public function setAlias(string $alias): self
    {
        $this->alias = $alias;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @return $this
     */
    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getManufacturer(): string
    {
        return $this->manufacturer;
    }

    /**
     * @return $this
     */
    public function setManufacturer(string $manufacturer): self
    {
        $this->manufacturer = $manufacturer;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getType(): string
    {
        return $this->type;
    }

    /**
     * @return $this
     */
    public function setType(string $type): self
    {
        $this->type = $type;

        return $this;
    }

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

    /**
     * @return $this
     */
    public function setSite(?Site $site): self
    {
        $this->site = $site;
        $this->project = null;

        return $this;
    }

    /**
     * @return Collection<int,  SemiAutomaticVariable>
     *
     * @psalm-mutation-free
     */
    public function getManagedVariables(): Collection
    {
        return $this->managedVariables;
    }

    /**
     * @param iterable<int, SemiAutomaticVariable> $managedVariables
     *
     * @return $this
     */
    public function setManagedVariables(iterable $managedVariables): self
    {
        ArrayCollectionUtils::update($this->managedVariables, $managedVariables, function (SemiAutomaticVariable $semiAutomaticVariable) {
            $semiAutomaticVariable->setDevice($this);
        });

        return $this;
    }

    /**
     * @return $this
     */
    public function addManagedVariable(SemiAutomaticVariable $managedVariable): self
    {
        if (!$this->managedVariables->contains($managedVariable)) {
            $this->managedVariables->add($managedVariable);
            $managedVariable->setDevice($this);
        }

        return $this;
    }

    /**
     * @return $this
     */
    public function removeManagedVariable(SemiAutomaticVariable $managedVariable): self
    {
        if ($this->managedVariables->contains($managedVariable)) {
            $this->managedVariables->removeElement($managedVariable);
            $managedVariable->setDevice(null);
        }

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getCommunicationProtocol(): string
    {
        return $this->communicationProtocol;
    }

    /**
     * @return $this
     */
    public function setCommunicationProtocol(string $communicationProtocol): self
    {
        $this->communicationProtocol = $communicationProtocol;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getFrameLength(): int
    {
        return $this->frameLength;
    }

    /**
     * @return $this
     */
    public function setFrameLength(int $frameLength): self
    {
        $this->frameLength = $frameLength;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getFrameStart(): ?string
    {
        return $this->frameStart;
    }

    /**
     * @return $this
     */
    public function setFrameStart(?string $frameStart): self
    {
        $this->frameStart = $frameStart;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getFrameEnd(): ?string
    {
        return $this->frameEnd;
    }

    /**
     * @return $this
     */
    public function setFrameEnd(?string $frameEnd): self
    {
        $this->frameEnd = $frameEnd;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getFrameCsv(): ?string
    {
        return $this->frameCsv;
    }

    /**
     * @return $this
     */
    public function setFrameCsv(?string $frameCsv): self
    {
        $this->frameCsv = $frameCsv;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getBaudrate(): ?int
    {
        return $this->baudrate;
    }

    /**
     * @return $this
     */
    public function setBaudrate(?int $baudrate): self
    {
        $this->baudrate = $baudrate;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getBitFormat(): ?int
    {
        return $this->bitFormat;
    }

    /**
     * @return $this
     */
    public function setBitFormat(?int $bitFormat): self
    {
        $this->bitFormat = $bitFormat;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getFlowControl(): ?string
    {
        return $this->flowControl;
    }

    /**
     * @return $this
     */
    public function setFlowControl(?string $flowControl): self
    {
        $this->flowControl = $flowControl;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getParity(): ?string
    {
        return $this->parity;
    }

    /**
     * @return $this
     */
    public function setParity(?string $parity): self
    {
        $this->parity = $parity;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getStopBit(): ?string
    {
        return $this->stopBit;
    }

    /**
     * @return $this
     */
    public function setStopBit(?string $stopBit): self
    {
        $this->stopBit = $stopBit;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getRemoteControl(): ?bool
    {
        return $this->remoteControl;
    }

    /**
     * @return $this
     */
    public function setRemoteControl(?bool $remoteControl): self
    {
        $this->remoteControl = $remoteControl;

        return $this;
    }

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

    /**
     * @return $this
     */
    public function setProject(?Project $project): self
    {
        $this->project = $project;
        $this->site = null;

        return $this;
    }
}
