<?php

namespace o80\i18n;

use Locale;

class IniProvider implements Provider
{
    /** @var string */
    private $path = '.';

    /** @var string|null */
    private $loadedLang;

    /**
     * @param string $path The path of the directory containing the dictionaries files
     */
    public function setLangsPath(string $path): void
    {
        $this->path = $path;
    }

    /**
     * Load the best dictionary looking at the prefered languages given in parameter.
     *
     * @param array $langs Ordered list of accepted languages, prefered ones are first
     * @return array|null The dictionary or null if not found
     * @throws CantLoadDictionaryException Thrown when there is no files in the directories path
     */
    public function load(array $langs): ?array
    {
        // List file names
        $files = $this->listLangFiles();
        $this->loadedLang = null;

        if (empty($files)) {
            throw new CantLoadDictionaryException(CantLoadDictionaryException::NO_DICTIONARY_FILES);
        }

        foreach ($langs as $lang) {
            $loaded = $this->loadMatchingFile($files, $lang);
            if (!$loaded) {
                continue;
            }
            $dict = $loaded['dict'];
            $loadedLang = $loaded['lang'];
            if ($dict !== null) {
                $this->loadedLang = $loadedLang;
                return $dict;
            }
        }

        return null;
    }

    /**
     * List the files from the {@code path} directory and sort them by filename size desc.
     *
     * @return array Array of files found
     */
    public function listLangFiles(): array
    {
        $files = array_diff(scandir($this->path), array('..', '.'));
        uasort($files, static function ($a, $b) {
            return strlen($a) < strlen($b) ? 1 : -1;
        });
        return array_filter($files, static function ($file) {
            return substr($file, -4) === '.ini';
        });
    }

    /**
     * Parse a INI file from the {@code path} directry.
     *
     * @param string $filename The name of the file
     * @return array The dictionary
     */
    private function loadFile(string $filename): array
    {
        return parse_ini_file($this->path . '/' . $filename);
    }

    /**
     * Load the best dictionary looking at the language code given in parameter.
     *
     * @param array $files The array of dictionary file names
     * @param string $lang The language code
     * @return array|null The dictionary found for the given language code, or null if there is no match.
     */
    private function loadMatchingFile(array $files, string $lang): ?array
    {
        // Check all file names
        foreach ($files as $file) {
            // Extract locale from filename
            $fileLocale = substr($file, 0, -4);

            if (Locale::filterMatches($lang, $fileLocale)) { // Check if filename matches $lang
                return array('dict' => $this->loadFile($file), 'lang' => $fileLocale);
            }
        }

        return null;
    }

    /**
     * This method gives the code of loaded lang. It must be called AFTER the "load" method.
     *
     * @return string The code of the loaded lang.
     */
    public function getLoadedLang(): ?string
    {
        return $this->loadedLang;
    }
}
