<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Statistiky\Services\Analyzators\Validators;

/**
 * Class ValidatorContext
 *
 * @package Seka\Portal\Modul\Statistiky\Services\Analyzators\Validators
 */
final class ValidatorContext
{
    /**
     * @var \Seka\Portal\Modul\Statistiky\Services\Analyzators\Validators\Validator|mixed|\Seka\Portal\Modul\Statistiky\Services\Analyzators\Validators\Generic
     */
    private Validator $strategy;

    /**
     * @var array
     */
    private array $warnings = [];

    /**
     * Create the instance of the validator by building the class name with the UpperCamelCase format
     * Generate a warning if the validator wasn't found, and create a generic validator instance
     *
     * @param string     $type     type of analysis
     * @param string     $strategy validator strategy class name
     * @param array|null $optData  optional data passed to the semantic validators
     */
    public function __construct(string $type, string $strategy, array $optData = null)
    {
        $validatorClassName = $this->getValidatorClassName($type, $strategy);

        if (class_exists($validatorClassName)) {
            $this->strategy = new $validatorClassName($optData);
        } else {
            $this->strategy = new Generic();
            $this->warnings[] = sprintf(
                'Strategy %s (%s) is not implemented for the %s analyzer',
                $strategy,
                $validatorClassName,
                $type
            );
        }
    }

    /**
     * Remove elements from memory
     *
     * @return void
     */
    function __destruct()
    {
        unset($this->strategy);
    }

    /**
     * Return the tokens retrieved from the validator
     *
     * @return array
     */
    public function getTokens(): array
    {
        return $this->strategy->getTokens();
    }

    /**
     * Return the errors found during the validation
     *
     * @return array
     */
    public function getErrors(): array
    {
        return $this->strategy->getErrors();
    }

    /**
     * Return the warnings found during the validation
     *
     * @return array
     */
    public function getWarnings(): array
    {
        return $this->warnings;
    }

    /**
     * Return the error description to help the user to solve the problem
     *
     * @param $input string|array
     *
     * @return string
     */
    public function getErrorMsg($input): string
    {
        return $this->strategy->getErrorMsg($input);
    }

    /**
     * @param mixed $input input data of the csv
     *
     * @return bool whether this data is valid or not for current validator
     */
    public function validate($input): bool
    {
        return $this->strategy->validate($input);
    }

    /**
     * @param string $type
     * @param string $strategy
     *
     * @return string
     */
    private function getValidatorClassName(string $type, string $strategy): string
    {
        $validatorClassName = sprintf(
            '%s%s',
            ucfirst($type),
            str_replace(' ', '', ucwords(str_replace('_', ' ', $strategy)))
        );

        return sprintf(
            '%s\Analyzators\Validators\%s',
            __NAMESPACE__,
            $validatorClassName
        );
    }
}
