<?php
/**
 * Copyright 2020 Adobe
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute this file in
 * accordance with the terms of the Adobe license agreement accompanying
 * it.
 */
declare(strict_types=1);

namespace Magento\Mray\CodeStructuralElement\Php\NodeVisitor;

use Magento\Mray\CodeStructuralElement\Php\Reflection\CallableDeclaration\Function_;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ClassLikeDeclaration\Class_;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ClassLikeDeclaration\Interface_;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ConstantDeclaration\Const_;
use Magento\Mray\CodeStructuralElement\Php\Reflection\Context;
use PhpParser\Node;
use PhpParser\NodeVisitor;

class StructuralElementsReflector implements NodeVisitor
{
    /** @var Context  */
    private $context;

    /**
     * @param Context $context
     */
    public function __construct(Context $context)
    {
        $this->context = $context;
    }

    /**
     * @inheritDoc
     */
    public function beforeTraverse(array $nodes)
    {
        return null;
    }

    /**
     * @inheritDoc
     */
    public function enterNode(Node $node)
    {
        if ($node instanceof Node\Stmt\Class_) {
            $r = $this->context->getGlobal()->getStructuralElementDeclarations();
            $d = new Class_($node, $r);
            $r->registerClassLike($d);
            $node->setAttribute('declaration', $d);
        } elseif ($node instanceof Node\Stmt\Interface_) {
            $r = $this->context->getGlobal()->getStructuralElementDeclarations();
            $d = new Interface_($node, $r);
            $r->registerClassLike($d);
            $node->setAttribute('declaration', $d);
        } elseif ($node instanceof Node\Stmt\Const_) {
            $r = $this->context->getGlobal()->getStructuralElementDeclarations();
            foreach ($node->consts as $const) {
                $d = new Const_($node, $const);
                $r->registerGlobalConstant($d);
                $const->setAttribute('declaration', $d);
            }
        } elseif ($node instanceof Node\Stmt\Function_) {
            $r = $this->context->getGlobal()->getStructuralElementDeclarations();
            $d = new Function_($node);
            $r->registerFunction($d);
            $node->setAttribute('declaration', $d);
        }

        // todo: add traits support

        return null;
    }

    /**
     * @inheritDoc
     */
    public function leaveNode(Node $node)
    {
        return $node;
    }

    /**
     * @inheritDoc
     */
    public function afterTraverse(array $nodes)
    {
        return null;
    }
}
