<?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\Reflection\VariableDefinition;

use Magento\Mray\CodeStructuralElement\Php\Reflection\PropertyDeclaration;
use Magento\Mray\CodeStructuralElement\Php\Reflection\TypeFactory;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ValueAccessor;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ValuePointer;
use Magento\Mray\CodeStructuralElement\Php\Reflection\VariableDefinition;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types;

class DeclaredProperty implements VariableDefinition
{
    /** @var PropertyDeclaration  */
    private $d;
    /** @var Type */
    private $class;

    /** @var ValueAccessor */
    private $accessor;

    /**
     * @param PropertyDeclaration $d
     * @param Type|null $class
     */
    public function __construct(
        PropertyDeclaration $d,
        Type $class = null
    ) {
        $this->d = $d;
        $this->class = $class ?? TypeFactory::get(Types\Object_::class);
    }

    /**
     * @return bool
     */
    public function isDefinition(): bool
    {
        return true;
    }

    /**
     * @return ValueAccessor
     */
    public function getAccessor(): ValueAccessor
    {
        if (!isset($this->accessor)) {
            $propertyName = $this->d->getName();

            if ($propertyName) {
                $this->accessor = new ValueAccessor\KnownPath([
                    new ValuePointer('this', $this->class),
                    new ValuePointer($propertyName, $this->getType()),
                ]);
            } else {
                $this->accessor = new ValueAccessor\Unresolvable();
            }
        }
        return $this->accessor;
    }

    /**
     * @return Type|null
     */
    public function getType(): ?Type
    {
        return $this->d->getType();
    }
}
