<?php

/**
 * @package Dotclear
 * @subpackage Core
 *
 * @copyright Olivier Meunier & Association Dotclear
 * @copyright AGPL-3.0
 */
declare(strict_types=1);

namespace Dotclear\Core;

use Dotclear\Interface\Core\FormaterInterface;

/**
 * @brief   Text formater handler.
 *
 * @since   2.28, Text formater features have been grouped in this class
 */
class Formater implements FormaterInterface
{
    /**
     * Stack of registered content formaters.
     *
     * @var     array<string, array<string, callable(string):string> >    $stack
     */
    private array $stack = [];

    /**
     * Stack of registered content formaters' name.
     *
     * @var     array<string, string>    $names
     */
    private array $names = [];

    /**
     * Constructs a new instance.
     *
     * @param   Core    $core   The core container
     */
    public function __construct(
        protected Core $core
    ) {
    }

    public function addEditorFormater(string $editor_id, string $name, ?callable $func): void
    {
        if (is_callable($func)) {
            $this->stack[$editor_id][$name] = $func;
        }
    }

    public function addFormaterName(string $format, string $name): void
    {
        $this->names[$format] = $name;
    }

    public function getFormaterName(string $format): string
    {
        return $this->names[$format] ?? $format;
    }

    public function getEditors(): array
    {
        $res = [];

        foreach (array_keys($this->stack) as $editor_id) {
            $name = is_string($name = $this->core->plugins()->getDefine($editor_id)->get('name')) ? $name : '';
            if ($name !== '') {
                $res[$editor_id] = $name;
            }
        }

        return $res;
    }

    public function getFormater(string $editor_id): array
    {
        if (isset($this->stack[$editor_id])) {
            return array_keys($this->stack[$editor_id]);
        }

        return [];
    }

    public function getFormaters(): array
    {
        $res = [];

        foreach ($this->stack as $editor => $formaters) {
            $res[$editor] = array_keys($formaters);
        }

        return $res;
    }

    public function callEditorFormater(string $editor_id, string $name, string $str): string
    {
        $res = null;
        if (isset($this->stack[$editor_id]) && isset($this->stack[$editor_id][$name])) {
            $res = call_user_func($this->stack[$editor_id][$name], $str);
        } else {
            // Fallback with another editor if possible
            foreach ($this->stack as $editor => $formaters) {
                if (array_key_exists($name, $formaters)) {
                    $res = call_user_func($this->stack[$editor][$name], $str);

                    break;
                }
            }
        }

        return is_string($res) ? $res : $str;
    }
}
