<?php
// src/model/entities/Node.php

declare(strict_types=1);

namespace App\Entity;

use Config;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: TABLE_PREFIX . "node")]
class Node
{
    use \Position;

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: "integer")]
    private ?int $id_node = null;

    #[ORM\Column(type: "string", length: 255)]
    private string $name_node;

    #[ORM\Column(type: "integer")]
    private int $position;

    #[ORM\ManyToOne(targetEntity: self::class)]
    //#[ORM\ManyToOne(targetEntity: self::class, fetch: 'EAGER')] // fetch: 'eager' désactive le mode fainéant de doctrine
    #[ORM\JoinColumn(name: "parent_id", referencedColumnName: "id_node", onDelete: "SET NULL", nullable: true)]
    private ?self $parent = null;

    // un onDelete: "CASCADE" serait logique ici mais dangereux, on pourrait aussi faire en sorte que les noeuds soient récupérables si la page est brutalement supprimée
    #[ORM\ManyToOne(targetEntity: Page::class)]
    #[ORM\JoinColumn(name: "page_id", referencedColumnName: "id_page", nullable: true)]
    private ?Page $page;

    #[ORM\ManyToOne(targetEntity: Article::class, cascade: ['persist'])]
    #[ORM\JoinColumn(name: "article_id", referencedColumnName: "id_article", onDelete: "CASCADE", nullable: true)] // supprimer le contenu d'un article supprime les noeuds associés, faux dans l'autre sens
    private ?Article $article = null;

    // propriété non mappée dans la table "node", la jointure est décrite dans NodeData
    // elle sert à persister ou supprimer des données par cascade
    // "mappedBy" permet de cibler $node dans l'autre classe, qui elle possède un "inversedBy"
    #[ORM\OneToOne(targetEntity: NodeData::class, mappedBy: "node", cascade: ['persist', 'remove'])]
    private ?NodeData $node_data = null;


    // attributs non destinés à doctrine
    private array $children = []; // tableau de Node
    private ?self $adopted = null; // = "new" est un enfant de "main" lorsque la page est "article"

    public function __construct(string $name = '', int $position = 0, ?self $parent = null, ?Page $page = null, ?Article $article = null)
    {
        $this->name_node = $name;
        $this->position = $position;
        $this->parent = $parent;
        $this->page = $page;
        $this->article = $article;
    }

    // pfff...
    public function getId(): ?int
    {
        return $this->id_node;
    }
    public function getName(): string
    {
        return $this->name_node;
    }
    /*public function setName(string $name): void
    {
        $this->name_node = $name;
    }*/
    
    public function getParent(): ?self
    {
        return $this->parent;
    }
    /*public function setParent(?self $parent): void
    {
        $this->parent = $parent;
    }*/
    public function getPosition(): int
    {
        return $this->position;
    }
    public function setPosition(int $position): void
    {
        $this->position = $position;
    }
    public function getPage(): Page
    {
        return $this->page;
    }
    /*public function setPage(Page $page): void
    {
        $this->page = $page;
    }*/
    public function getArticle(): Article
    {
        return $this->article;
    }
    /*public function setArticle(Article $article): void
    {
        $this->article = $article;
    }*/
    public function getNodeData(): ?NodeData
    {
        return $this->node_data;
    }
    public function getChildren(): array
    {
        return $this->children;
    }
    public function getNodeByName(string $name): ?Node
    {
        foreach($this->children as $child){
            if($child->getName() === $name){
                return $child;
            }
        }
        return null;
    }
    public function addChild(self $child): void
    {
        $this->children[] = $child;

        if(!\Blocks::hasPresentation($this->getName())){ // post_block et news_block ont leurs enfants ordonnés avec ORDER BY
            $this->sortChildren(false);
        }
    }
    public function removeChild(self $child): void
    {
        foreach($this->children as $key => $object){
            if($object->getId() === $child->getId()){
                unset($this->children[$key]);
            }
            break;
        }
        $this->children = array_values($this->children); // réindexer pour supprimer la case vide
    }

    public function getAdoptedChild(): ?self // peut renvoyer null
    {
        return $this->adopted;
    }
    public function setAdoptedChild(self $child): void
    {
        $this->adopted = $child;
    }
}
