<?php declare(strict_types=1);
/*
 * irstea/ng-model-generator-bundle generates Typescript interfaces for Angular using api-platform metadata.
 * Copyright (C) 2018 IRSTEA
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License and the GNU
 * Lesser General Public License along with this program. If not, see
 * <https://www.gnu.org/licenses/>.
 */

namespace Irstea\NgModelGeneratorBundle\Models;

use Irstea\NgModelGeneratorBundle\Exceptions\InvalidArgumentException;

/**
 * Class PHPClass.
 */
final class PHPClass implements ClassName
{
    /** @var string */
    private $namespace;

    /** @var string */
    private $baseName;

    /**
     * ClassName constructor.
     *
     * @param string $namespace
     * @param string $baseName
     */
    private function __construct(string $namespace, string $baseName)
    {
        $this->namespace = $namespace;
        $this->baseName = $baseName;
    }

    /**
     * Get namespace.
     *
     * @return string
     */
    public function getNamespace(): string
    {
        return $this->namespace;
    }

    /**
     * Get baseName.
     *
     * @return string
     */
    public function getBaseName(): string
    {
        return $this->baseName;
    }

    /**
     * @return string
     */
    public function getFullName(): string
    {
        return $this->namespace . $this->baseName;
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return $this->getFullName();
    }

    /**
     * {@inheritdoc}
     */
    public function jsonSerialize()
    {
        return $this->getFullName();
    }

    /**
     * @param PHPClass $a
     * @param PHPClass $b
     *
     * @return bool
     */
    public static function baseNameOrdering(PHPClass $a, PHPClass $b): bool
    {
        return $a->getBaseName() > $b->getBaseName();
    }

    /**
     * @param ClassName|\ReflectionClass|string $name
     *
     * @return ClassName
     */
    public static function get($name): ClassName
    {
        if ($name instanceof ClassName) {
            $name = $name->getFullName();
        } elseif ($name instanceof \ReflectionClass) {
            $name = $name->getName();
        } elseif (!\is_string($name)) {
            throw new InvalidArgumentException(__METHOD__ . " argument should be a string, ClassName or ReflectionClass, not $name");
        }

        static $instances = [];

        if (!isset($instances[$name])) {
            $groups = [];
            if (!preg_match('/^\\\\?((?:\w+\\\\)*)(\w+)$/i', $name, $groups)) {
                throw new InvalidArgumentException("Invalid PHP class name: $name");
            }
            [, $namespace, $baseName] = $groups;

            $instances[$name] = new self($namespace, $baseName);
        }

        return $instances[$name];
    }
}