<?PHP
/**
 * Contains class NodaValidationHelper.
 *
 * @author Joshua Ramon Enslin <joshua@museum-digital.de>
 */
declare(strict_types = 1);

/**
 * A class of static functions for validating single fields of noda entities.
 */
final class NodaValidationHelper {

    const ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS = 3;

    /**
     * Validates an actor description for completeness. Of course, only an informed
     * guess based on the length and character composition of the description can be
     * made.
     *
     * @param string $description Input descrition.
     * @param string $name        Names of the actor. Optional. Setting this enables
     *                            checks e.g. to prevent duplicating the actor name
     *                            as a description.
     *
     * @return void
     */
    public static function validateTagDescription(string $description, string $name = ""):void {

        // For nodac, empty tag descriptions are to be allowed. Thus, a
        // dedicated check for fully empty ones with a dedicated exception
        // is needed.
        if (empty($description)) {
            throw new MDInvalidEmptyInputException("No tag name is provided");
        }

        // Throw error on descriptions that are too short
        if (\mb_strlen($description) < 10) {
            throw new MDgenericInvalidInputsException("Tag description is too short");
        }

        // Validate tag description based on character composition.

        // Ensure more than 3 distinct characters are used.
        $chars = \str_split($description);

        $uniqueChars = array_unique($chars);
        if (count($uniqueChars) <= self::ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS) {
            throw new MDgenericInvalidInputsException("There need to be more than " . self::ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS . " distinct characters.");
        }

        // Ensure more than the actor name is used.
        $clearedChars = ['  ' => ' ', ',' => ' ', ';' => ' ', '.' => ' '];

        $uniqueNames = array_unique(array_diff(explode(' ', strtr($name, $clearedChars)), ['']));
        sort($uniqueNames);

        $descCleared = strtr($description, $clearedChars);
        $descWords = array_unique(array_diff(explode(' ', $descCleared), ['']));
        sort($descWords);

        if ($uniqueNames === $descWords) {
            throw new MDgenericInvalidInputsException("The tag name was simply repeated in the description. This is not enough.");
        }

    }

    /**
     * Validates an actor description for completeness. Of course, only an informed
     * guess based on the length and character composition of the description can be
     * made.
     *
     * @param string   $description Input descrition.
     * @param string[] $names       Names of the actor. Optional. Setting this enables
     *                              checks e.g. to prevent duplicating the actor name
     *                              as a description.
     *
     * @return void
     */
    public static function validateActorDescription(string $description, array $names = []):void {

        // For nodac, empty actor descriptions are to be allowed. Thus, a
        // dedicated check for fully empty ones with a dedicated exception
        // is needed.
        if (empty($description)) {
            throw new MDInvalidEmptyInputException("No author name is provided");
        }

        // Throw error on descriptions that are too short
        if (\mb_strlen($description) < 10) {
            throw new MDgenericInvalidInputsException("Author description is too short");
        }

        // Validate actor description based on character composition.

        $chars = \str_split($description);

        $uniqueChars = array_unique($chars);
        if (count($uniqueChars) <= self::ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS) {
            throw new MDgenericInvalidInputsException("There need to be more than " . self::ACTOR_DESCRIPTION_REQUIRED_DISTINCT_CHARS . " distinct characters.");
        }

        if (!empty($names)) {

            $clearedChars = ['  ' => ' ', ',' => ' ', ';' => ' ', '.' => ' '];

            $namesMerged = implode(' ', $names);
            $namesMerged = strtr($namesMerged, $clearedChars);
            $uniqueNames = array_unique(array_diff(explode(' ', $namesMerged), ['']));
            sort($uniqueNames);

            $descCleared = strtr($description, $clearedChars);
            $descWords = array_unique(array_diff(explode(' ', $descCleared), ['']));
            sort($descWords);

            if ($uniqueNames === $descWords) {
                throw new MDgenericInvalidInputsException("The actor name was simply repeated in the description. This is not enough.");
            }

        }

    }
}
