1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Console\Formatter;
13
14/**
15 * @author Jean-François Simon <contact@jfsimon.fr>
16 */
17class OutputFormatterStyleStack
18{
19    /**
20     * @var OutputFormatterStyleInterface[]
21     */
22    private $styles;
23
24    /**
25     * @var OutputFormatterStyleInterface
26     */
27    private $emptyStyle;
28
29    /**
30     * Constructor.
31     *
32     * @param OutputFormatterStyleInterface|null $emptyStyle
33     */
34    public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
35    {
36        $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
37        $this->reset();
38    }
39
40    /**
41     * Resets stack (ie. empty internal arrays).
42     */
43    public function reset()
44    {
45        $this->styles = array();
46    }
47
48    /**
49     * Pushes a style in the stack.
50     *
51     * @param OutputFormatterStyleInterface $style
52     */
53    public function push(OutputFormatterStyleInterface $style)
54    {
55        $this->styles[] = $style;
56    }
57
58    /**
59     * Pops a style from the stack.
60     *
61     * @param OutputFormatterStyleInterface|null $style
62     *
63     * @return OutputFormatterStyleInterface
64     *
65     * @throws \InvalidArgumentException When style tags incorrectly nested
66     */
67    public function pop(OutputFormatterStyleInterface $style = null)
68    {
69        if (empty($this->styles)) {
70            return $this->emptyStyle;
71        }
72
73        if (null === $style) {
74            return array_pop($this->styles);
75        }
76
77        foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
78            if ($style->apply('') === $stackedStyle->apply('')) {
79                $this->styles = array_slice($this->styles, 0, $index);
80
81                return $stackedStyle;
82            }
83        }
84
85        throw new \InvalidArgumentException('Incorrectly nested style tag found.');
86    }
87
88    /**
89     * Computes current style with stacks top codes.
90     *
91     * @return OutputFormatterStyle
92     */
93    public function getCurrent()
94    {
95        if (empty($this->styles)) {
96            return $this->emptyStyle;
97        }
98
99        return $this->styles[count($this->styles) - 1];
100    }
101
102    /**
103     * @param OutputFormatterStyleInterface $emptyStyle
104     *
105     * @return OutputFormatterStyleStack
106     */
107    public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
108    {
109        $this->emptyStyle = $emptyStyle;
110
111        return $this;
112    }
113
114    /**
115     * @return OutputFormatterStyleInterface
116     */
117    public function getEmptyStyle()
118    {
119        return $this->emptyStyle;
120    }
121}
122