1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 *
8 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js)
9 *  - (c) John MacFarlane
10 *
11 * Additional emphasis processing code based on commonmark-java (https://github.com/atlassian/commonmark-java)
12 *  - (c) Atlassian Pty Ltd
13 *
14 * For the full copyright and license information, please view the LICENSE
15 * file that was distributed with this source code.
16 */
17
18namespace League\CommonMark\Delimiter\Processor;
19
20final class DelimiterProcessorCollection implements DelimiterProcessorCollectionInterface
21{
22    /** @var array<string,DelimiterProcessorInterface>|DelimiterProcessorInterface[] */
23    private $processorsByChar = [];
24
25    public function add(DelimiterProcessorInterface $processor)
26    {
27        $opening = $processor->getOpeningCharacter();
28        $closing = $processor->getClosingCharacter();
29
30        if ($opening === $closing) {
31            $old = $this->processorsByChar[$opening] ?? null;
32            if ($old !== null && $old->getOpeningCharacter() === $old->getClosingCharacter()) {
33                $this->addStaggeredDelimiterProcessorForChar($opening, $old, $processor);
34            } else {
35                $this->addDelimiterProcessorForChar($opening, $processor);
36            }
37        } else {
38            $this->addDelimiterProcessorForChar($opening, $processor);
39            $this->addDelimiterProcessorForChar($closing, $processor);
40        }
41    }
42
43    public function getDelimiterProcessor(string $char): ?DelimiterProcessorInterface
44    {
45        return $this->processorsByChar[$char] ?? null;
46    }
47
48    public function getDelimiterCharacters(): array
49    {
50        return \array_keys($this->processorsByChar);
51    }
52
53    private function addDelimiterProcessorForChar(string $delimiterChar, DelimiterProcessorInterface $processor): void
54    {
55        if (isset($this->processorsByChar[$delimiterChar])) {
56            throw new \InvalidArgumentException(\sprintf('Delim processor for character "%s" already exists', $processor->getOpeningCharacter()));
57        }
58
59        $this->processorsByChar[$delimiterChar] = $processor;
60    }
61
62    private function addStaggeredDelimiterProcessorForChar(string $opening, DelimiterProcessorInterface $old, DelimiterProcessorInterface $new): void
63    {
64        if ($old instanceof StaggeredDelimiterProcessor) {
65            $s = $old;
66        } else {
67            $s = new StaggeredDelimiterProcessor($opening, $old);
68        }
69
70        $s->add($new);
71        $this->processorsByChar[$opening] = $s;
72    }
73}
74