HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers10/blije-gasten.komma.pro/app/Komma/Globalization/RegionInfo.php
<?php


namespace App\Komma\Globalization;

use App\Komma\Globalization\Datasets\Countries;
use Closure;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

/**
 * Class RegionInfo
 *
 * Contains information about the country/region after constructing it.
 * Inspired on the RegionInfo class from C#. But modified to our needs.
 *
 * @see https://docs.microsoft.com/en-us/dotnet/api/system.globalization.regioninfo?view=netframework-4.7.2
 * @package App\Komma\Globalization
 */
class RegionInfo extends AbstractCultureParser implements RegionInfoInterface
{
    /** @var RegionInfoInterface[] */
    private static $cache = [];

    /** @var string $displayName */
    private $displayName = '';

    /** @var string $nativeName */
    private $nativeName = '';

    /** @var string $currencyName */
    private $currencyName = '';

    /** @var string */
    private $currencyMinorName = '';

    /** @var string $currencySymbol */
    private $currencySymbol = '';

    /** @var string $ISOCurrencySymbol */
    private $ISOCurrencySymbol = '';

    /** @var bool $isMetric */
    private $isMetric = false;

    /** @var string $threeLetterISORegionName */
    private $threeLetterISORegionName = '';

    /** @var string $twoLetterISORegionName */
    private $twoLetterISORegionName = '';

    /** @var NumberFormatInfo $numberFormat */
    private $numberFormat;

    /** @var Collection */
    private $languages;

    /** @var bool True if it is bound to a Region only. false if it is bound to a Region AND a language */
    private $isNeutral = false;

    /**
     * AbstractCultureParser constructor.
     *
     * Is protected to prevent construction using the constructor. Use getInstance instead.
     */
    protected function __construct() {}

    /**
     * RegionInfo constructor.
     *
     * Use this function to get a new instance or cached instance of this class.
     *
     * The format for the culture name based on RFC 4646 is languagecode2>-country/regioncode2, where languagecode2 is the two-letter
     * language code and country/regioncode2 is the two-letter subculture code. Examples include ja-JP for Japanese (Japan)
     * and en-US for English (United States). In cases where a two-letter language code is not available,
     * a three-letter code derived from ISO 639-2 is used.
     *
     * Notice that some culture names also specify an ISO 15924 script. For example, Cyrl specifies the Cyrillic script
     * and Latin specifies the Latin script. A culture name that includes a script uses the pattern languagecode2-scripttag-country/regioncode2.
     * An example of this type of culture name is uz-Cyrl-UZ for Uzbek (Cyrillic, Uzbekistan).
     *
     * A neutral culture is specified by only the two-letter lowercase language code. For example, fr specifies the neutral culture for French, and de specifies the neutral culture for German.
     *
     * @param string $name
     * @return RegionInfoInterface|null
     */
    public static function getInstance($name)
    {
        //Create a new instance and parse its name.
        $instance = new static();
        $instance->parseName($name);
        $instance->name = implode('-', array_values(array_filter([strtolower($instance->languageIso2), ucfirst(strtolower($instance->scriptTagCountry)), strtoupper($instance->countryOrRegionCode2)])));

        if(in_array($instance->name, array_keys(self::$cache), true)) return self::$cache[$instance->name]; //Return a cached instance if available.

        //First find the country by its ISO2 name
        $found = false;
        foreach(Countries::DATA as $index => $data) {
            if(strtolower($data['Name']) === strtolower($instance->countryOrRegionCode2)) {
                //Then set data
                $instance->isMetric = $data['IsMetric'];
                $instance->twoLetterISORegionName = $data['TwoLetterISORegionName'];
                $instance->threeLetterISORegionName = $data['ThreeLetterISORegionName'];
                $instance->currencySymbol = $data['CurrencySymbol'];
                $instance->ISOCurrencySymbol = $data['ISOCurrencySymbol'];
                $instance->currencyName = $data['CurrencyName'];
                $instance->currencyMinorName = $data['CurrencyMinorName'];
                $instance->currencySymbol = $data['CurrencySymbol'];
                $instance->isNeutral = !($instance->countryOrRegionCode2 && $instance->languageIso2);

                $instance->setupNumberFormat($data);
                $instance->setupLanguages($data);
                $instance->setDisplayName($data);
                $instance->setNativeName($data);
                $found = true;
                break;
            }
        }

        if(!$found) {
            throw new \InvalidArgumentException('RegionInfo: No information available for: '.$name);
        }


        self::$cache[$instance->name] = $instance; //Cache this instance if not cached.
        return $instance;
    }

    /**
     * Sets up the number format info instance.
     */
    private function setupNumberFormat($data)
    {
        $this->numberFormat = new NumberFormatInfo();
        $this->numberFormat->setCurrencyDecimalDigits($data['numberFormatting']['currencyDecimalDigits']);
        $this->numberFormat->setCurrencyDecimalSeparator($data['numberFormatting']['currencyDecimalSeparator']);
        $this->numberFormat->setCurrencyGroupSeparator($data['numberFormatting']['currencyGroupSeparator']);
        $this->numberFormat->setCurrencyGroupSizes($data['numberFormatting']['currencyGroupSizes']);
    }

    /**
     * Parses the region name. It must either be a two-letter region name, such as "US" for the United States,
     * or the name of a specific culture, such as "en-US" for English (United States)
     *
     * @param string $name
     */
    function parseName(string $name)
    {
        if ($name !== "") {
            $explodedName = explode('-', $name);
            $count = count($explodedName);
            if ($count == 2) {
                $this->languageIso2 = strtolower($explodedName[0]);
                $this->countryOrRegionCode2 = strtolower($explodedName[1]);
                return;
            } elseif ($count == 1) {
                $this->countryOrRegionCode2 = strtolower($explodedName[0]);
                return;
            }
        } else {
            return;
        }
        
        throw new \RuntimeException('The name was invalid it must either be a two-letter region name, such as "US" for the United States, or the name of a specific culture, such as "en-US" for English (United States). Was: '.$name);
    }

    /**
     * @param array $data
     */
    private function setupLanguages(array $data)
    {
        $this->languages = new Collection();
        if($this->languageIso2 == '') {
            //Push all of its languages
            foreach ($data['ISOLanguages'] as $languageIso2) {
                if($languageIso2 != '') {
                    $language = Language::getInstance($languageIso2);
                    if($language->isComplete()) $this->languages->push($language);
                }
            }
        } else {
            //Push a specific language
            $language = Language::getInstance($this->languageIso2);
            if($language->isComplete()) $this->languages->push($language);
        }
    }

    /**
     * @param $data
     */
    private function setDisplayName($data)
    {
        if($this->isNeutral) {
            $this->displayName = $data['DisplayName'];
        } else {
            /** @var Language $language */
            $language = $this->languages->first();
            $languageDisplayName = $language->getDisplayName() !== '' ? $language->getDisplayName() : $language->getName();
            $this->displayName = $languageDisplayName.' ('.$data['DisplayName'].')';
        }
    }

    /**
     * @param $data
     */
    private function setNativeName($data)
    {
        if($this->isNeutral) {
            $this->nativeName = $data['NativeName'];
        } else {
            /** @var Language $language */
            $language = $this->languages->first();
            $languageNativeName = $language->getNativeName() !== '' ? $language->getNativeName() : $language->getName();
            $nativeNamePart = ($data['NativeName'] !== '') ? '('.$data['NativeName'].')' : '('.$data['DisplayName'].')';
            $this->nativeName = $languageNativeName.' '.$nativeNamePart;
        }
    }


    /**
     * @return Collection
     */
    public static function getAllCultures()
    {
        $allCultures = static::cultureBuilderLoop(function(RegionInfo $neutralCultureRegionInfo) {
            $specificCultures = $neutralCultureRegionInfo->getLanguages()->map(function(Language $language) use($neutralCultureRegionInfo) {
                $name = strtolower($language->getName()).'-'.strtoupper($neutralCultureRegionInfo->getName());
                $specificCulture = self::getInstance($name);
                return $specificCulture;
            });

            return collect([$neutralCultureRegionInfo])->merge($specificCultures);
        });

        return $allCultures;
    }

    /**
     * Return all cultures that are both bound to a language and a region
     * @return Collection
     */
    public static function getSpecificCultures()
    {
        $specificCultures = static::cultureBuilderLoop(function(RegionInfo $neutralCultureRegionInfo) {
            $specificCultures = $neutralCultureRegionInfo->getLanguages()->map(function(Language $language) use($neutralCultureRegionInfo) {
                $name = strtolower($language->getName()).'-'.strtoupper($neutralCultureRegionInfo->getName());
                $specificCulture = self::getInstance($name);
                return $specificCulture;
            });

            return $specificCultures;
        });

        return $specificCultures;
    }

    /**
     * Return all cultures that are bound to a language but not to a region.
     *
     * @return Collection
     */
    public static function getNeutralCultures()
    {
        return static::cultureBuilderLoop();
    }

    /**
     * Loops over all countries and creates regionInfo instances for them (or retrieves cached versions).
     * And for each of them executes an optional closure that can edit the regionInfo instance, or return multiple of them
     *
     * @param Closure|null $cultureEditor
     * @return Collection
     */
    private static function cultureBuilderLoop(Closure $cultureEditor = null)
    {
        $instances = collect();
        foreach(Countries::DATA as $index => $data) {
            $neutralInstance = self::getInstance($data['Name']);
            if($cultureEditor) {
                $neutralInstances = $cultureEditor($neutralInstance); //Must returns an instance of RegionInfo or a collection of RegionInfo instances.
                $neutralInstances = Collection::wrap($neutralInstances);
                $neutralInstances->each(function($regionInfo) use(&$instances, $neutralInstances) {
                    $instances->push($regionInfo);
                });
            } else {
                $instances->push($neutralInstance);
            }
        }

        return $instances;
    }

    /**
     *  Returns the neutral region (the one not associated to a language
     */
    public function getNeutralRegionInfo(): RegionInfoInterface
    {
        return self::getInstance($this->countryOrRegionCode2);
    }

    /**
     * Find one or more regionInfo's by a certain where statement
     *
     * @param $name
     * @param $operator
     * @param $value
     * @return Collection|null
     */
    public static function getWhere($name, $operator, $value)
    {
        $foundRegionInfos = self::getAllCultures()->filter(function(RegionInfo $regionInfo) use ($name, $operator, $value) {
            $methodName = 'get'.ucfirst(Str::camel($name));
            if(!method_exists(self::class, $methodName)) throw new \InvalidArgumentException('Could not execute where statement since there is no method called "'.$methodName.'". This getter is used for the where statement.');

            $regionInfoValue = $regionInfo->{$methodName}();
            switch ($operator) {
                case '==';
                case '=';
                    return $regionInfoValue == $value;
                case '!=';
                case '<>';
                    return $regionInfoValue != $value;
                case '===';
                    return $regionInfoValue === $value;
                case '!==';
                    return $regionInfoValue !== $value;
                case '<';
                    return $regionInfoValue < $value;
                case '>';
                    return $regionInfoValue > $value;
                case '<=';
                    return $regionInfoValue <= $value;
                case '>=';
                    return $regionInfoValue >= $value;
                default:
                    return false;
            }
        });

        return $foundRegionInfos;
    }


    /**
     * @return string
     */
    public function getDisplayName(): string
    {
        return $this->displayName;
    }

    /**
     * @return string
     */
    public function getNativeName(): string
    {
        return $this->nativeName;
    }

    /**
     * @return string
     */
    public function getCurrencyName(): string
    {
        return $this->currencyName;
    }

    /**
     * @return string
     */
    public function getCurrencyMinorName(): string
    {
        return $this->currencyMinorName;
    }

    /**
     * @return string
     */
    public function getCurrencySymbol(): string
    {
        return $this->currencySymbol;
    }

    /**
     * @return string
     */
    public function getISOCurrencySymbol(): string
    {
        return $this->ISOCurrencySymbol;
    }

    /**
     * @return bool
     */
    public function isMetric(): bool
    {
        return $this->isMetric;
    }

    /**
     * @return string
     */
    public function getThreeLetterISORegionName(): string
    {
        return $this->threeLetterISORegionName;
    }

    /**
     * @return string
     */
    public function getTwoLetterISORegionName(): string
    {
        return $this->twoLetterISORegionName;
    }


    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /** @return NumberFormatInfo */
    public function getNumberFormat(): NumberFormatInfo
    {
        return $this->numberFormat;
    }

    /**
     * @return Collection
     */
    public function getLanguages(): Collection
    {
        return $this->languages;
    }

    /**
     * @return bool
     */
    public function isNeutral(): bool
    {
        return $this->isNeutral;
    }

    /** @return bool Alias for isNeutral */
    public function getNeutral(): bool { return $this->isNeutral(); }
}