<?php
namespace Engine\Theme\JSLoader;

/**
 * Abstract class from which all JS loader handlers are extended
 * @author Lucian Sirbu
 */
abstract class LoaderAbstract
{
    /**
	 * For classes that do queue items, this is the queue
	 */
    protected array $filesList = [];

    /**
	 * The list of file params(defer, priority, group)
	 */
    protected array $filesParams = [];

    /**
	 * A list of files already sent to the brwoser
	*/
    protected array $sentFilesList = [];

    /**
	 * A list of groups loaded. This determines what exporter classes to call on the postload() event
	 */
    protected array $loadedGroups = [];

    /**
	 * Options for the loader
	 */
    protected array $options = [];

    public function __construct()
    {
    }

    /**
	 * Initialize the object
	 */
    abstract public function initialize(): void;

    /**
	 * Set an internal option
	 * @param string $key
	 * @param mixed $value
	 */
    public function setOption(string $key, mixed $value): void
    {
        $this->options[$key] = $value;
    }

    /**
	 * Get an internal option
	 * @param string $key
	 * @return mixed
	 */
    public function getOption(string $key): mixed
    {
        return $this->options[$key] ?? null;
    }

    /**
	 * Preload the files, called in the <header> of the tpl file
	 * @return string|null
	 */
    abstract public function preload(): ?string;

    /**
	 * Postload the files, called in the <footer> of the tpl file
	 * @return string|null
	 */
    abstract public function postload(): ?string;

    /**
	 * Load a file
	 * @param string $file
	 * @param array $params
	 * @return string|null
	 */
    abstract public function load(string $file, array $params = []): ?string;


    /**
	 * Called in certain places int he tpl file to trigger a rendering of the currently queued files(if any)
	 * @param string|null $renderId
	 * @param array $params
	 * @return string|null
	 */
    abstract public function render(?string $renderId = null, array $params = []): ?string;

    /**
	 * Load an already defined group of files with a specified set of params
	 * @param string $groupName
	 * @param array $params
	 * @throws Exception
	 */
    public function loadGroup(string $groupName, array $params = []): void
    {
        $resourceLoaderCfg = \Theme::getInstance()->getResourceLoaderCfg();
        if (!$resourceLoaderCfg) {
            throw new \Exception("ResourceLoader configs not loaded. Please check this out");
        }

        if (!isset($resourceLoaderCfg['groups'][$groupName])) {
            throw new \Exception("Cannot load group '{$groupName}'");
        }

        $params['group'] = $groupName;
        if (!empty($resourceLoaderCfg['groups'][$groupName]['js'])) {
            if (isset($params['priority'])) {
                $groupPriority = (int)$params['priority'];
            } else {
                $groupPriority = (int)(PHP_INT_MAX / 2) + count($this->loadedGroups) * 2500;
            }

            foreach ($resourceLoaderCfg['groups'][$groupName]['js'] as $file) {
                $params['priority'] = $groupPriority + count($this->filesList);
                $this->load($file, $params);
            }
        }

        $this->loadedGroups[$groupName] = $groupName;
    }

}
