<?php

namespace Fifa\ConnectId\Sdk\ApiModelValidation;

use DOMDocument;
use DOMXPath;
use Exception;
use Fifa\ConnectId\Sdk\Util\Data\ISO3166CountryCode;
use Fifa\ConnectId\Sdk\Util\Data\ISO6392LanguageCode;
use Fifa\ConnectId\Sdk\Util\XsdSchemaValidator\XsdSchemasDirectoryResolver;
use LogicException;

class XsdSchemaValuesResolver
{
    const includesSubDirectory = "includes";

    /**
     * @var string
     */
    private static $directoryContainingXsdFiles;

    /**
     * @var array
     */
    private static $schemaEnumValues;

    /**
     * XsdSchemaValuesResolver static constructor.
     * @throws Exception
     */
    public static function __constructStatic()
    {
        self::$directoryContainingXsdFiles = XsdSchemasDirectoryResolver::getDirectory();
        self::$schemaEnumValues = array(
            ISO3166CountryCode::class => self::loadSchemaValues("iso3166-country-code.xsd"),
            ISO6392LanguageCode::class => self::loadSchemaValues("iso639-2-language-code.xsd")
        );
    }

    /**
     * Returns enum values based on xsd file and throws exception if the specified enum type is not supported
     *
     * @param $enumType
     * @return array
     */
    public static function getValues($enumType): array
    {
        if (array_key_exists($enumType, self::$schemaEnumValues))
        {
            return self::$schemaEnumValues[$enumType];
        }

        throw new LogicException("There are no values from xsd file for type $enumType");
    }

    /**
     * @throws Exception
     */
    private static function loadSchemaValues($xsdFileName): array
    {
        $xsdFilePath = self::getPathFromIncludesSubDirectory($xsdFileName);

        $values = array();
        $xsdDocument = new DOMDocument();
        $xsdDocument->preserveWhiteSpace = false;
        if ($xsdDocument->load($xsdFilePath))
        {
            $xsdPath = new DOMXPath($xsdDocument);
            $restrictionNode = $xsdPath
                ->query('//xsd:restriction')
                ->item(0);

            $index = 0;
            foreach ($restrictionNode->childNodes as $enumeration)
            {
                if($enumeration->localName == "enumeration") {
                    $value = $enumeration->getAttribute('value');
                    $values[$index] = $value;
                    $index++;
                }
            }
        }
        return $values;
    }

    /**
     * @throws Exception
     */
    private static function getPathFromIncludesSubDirectory($fileName): string
    {
        $pathToAnExistingFile = self::$directoryContainingXsdFiles . DIRECTORY_SEPARATOR
            . self::includesSubDirectory . DIRECTORY_SEPARATOR . $fileName;
        self::validateThatFileExists($pathToAnExistingFile);
        return $pathToAnExistingFile;
    }

    /**
     * @throws Exception
     */
    private static function validateThatFileExists($pathToFile)
    {
        if (!file_exists($pathToFile))
        {
            throw new Exception("File could not be found: $pathToFile");
        }
    }
}

XsdSchemaValuesResolver::__constructStatic();