<?php

namespace MightyPork\Utils;

use MightyPork\Exceptions\NotExistException;
use ReflectionClass;

/** Trait for checking if const is defined in class */
trait Enum
{
    private static $cache_enum_constants = null;

    /**
     * Get all constants
     *
     * @param string $prefix required name prefix (filter)
     * @return array name -> value array
     */
    public static function getConstants($prefix = '')
    {
        if (static::$cache_enum_constants != null) return static::$cache_enum_constants;

        $map = (new ReflectionClass(static::class))->getConstants();
        $selected = [];
        foreach ($map as $k => $v) {
            if ($prefix === '' || strpos($k, $prefix) === 0) {
                $selected[$k] = $v;
            }
        }

        static::$cache_enum_constants = $selected;
        return $selected;
    }

    /**
     * Check if a constant with a given value is defined in this class.
     *
     * @param mixed $value checked value
     * @param string $prefix required name prefix
     * @return bool
     */
    public static function isDefined($value, $prefix = '')
    {
        return in_array($value, static::getConstants($prefix));
    }

    /**
     * Check if a constant with a given name is defined in this class.
     *
     * @param string $name checked name
     * @param string $prefix required name prefix
     * @return bool
     */
    public static function hasConstant($name, $prefix = '')
    {
        return array_key_exists($name, static::getConstants($prefix));
    }

    /**
     * Get constant value dynamically by name
     *
     * @param string $name
     * @return mixed
     */
    public static function forName($name)
    {
        return constant(static::class . '::' . $name);
    }

    /**
     * Get constant name by it's value
     *
     * @param mixed $value
     * @return string
     */
    public static function nameOf($value)
    {
        $k = array_search($value, static::getConstants());

        if ($k == false)
            throw new NotExistException("Invalid value '$value' for enum " . static::class);

        return $k;
    }
}