1<?php
2/**
3 * SCSSPHP
4 *
5 * @copyright 2012-2015 Leaf Corcoran
6 *
7 * @license http://opensource.org/licenses/MIT MIT
8 *
9 * @link http://leafo.github.io/scssphp
10 */
11namespace Leafo\ScssPhp;
12
13use Leafo\ScssPhp\Formatter\OutputBlock;
14/**
15 * Base formatter
16 *
17 * @author Leaf Corcoran <leafot@gmail.com>
18 */
19abstract class Formatter
20{
21    /**
22     * @var integer
23     */
24    public $indentLevel;
25    /**
26     * @var string
27     */
28    public $indentChar;
29    /**
30     * @var string
31     */
32    public $break;
33    /**
34     * @var string
35     */
36    public $open;
37    /**
38     * @var string
39     */
40    public $close;
41    /**
42     * @var string
43     */
44    public $tagSeparator;
45    /**
46     * @var string
47     */
48    public $assignSeparator;
49    /**
50     * @var boolea
51     */
52    public $keepSemicolons;
53    /**
54     * Initialize formatter
55     *
56     * @api
57     */
58    public abstract function __construct();
59    /**
60     * Return indentation (whitespace)
61     *
62     * @return string
63     */
64    protected function indentStr()
65    {
66        return '';
67    }
68    /**
69     * Return property assignment
70     *
71     * @api
72     *
73     * @param string $name
74     * @param mixed  $value
75     *
76     * @return string
77     */
78    public function property($name, $value)
79    {
80        return rtrim($name) . $this->assignSeparator . $value . ';';
81    }
82    /**
83     * Strip semi-colon appended by property(); it's a separator, not a terminator
84     *
85     * @api
86     *
87     * @param array $lines
88     */
89    public function stripSemicolon(&$lines)
90    {
91        if ($this->keepSemicolons) {
92            return;
93        }
94        if (($count = count($lines)) && substr($lines[$count - 1], -1) === ';') {
95            $lines[$count - 1] = substr($lines[$count - 1], 0, -1);
96        }
97    }
98    /**
99     * Output lines inside a block
100     *
101     * @param \Leafo\ScssPhp\Formatter\OutputBlock $block
102     */
103    protected function blockLines(OutputBlock $block)
104    {
105        $inner = $this->indentStr();
106        $glue = $this->break . $inner;
107        echo $inner . implode($glue, $block->lines);
108        if (!empty($block->children)) {
109            echo $this->break;
110        }
111    }
112    /**
113     * Output block selectors
114     *
115     * @param \Leafo\ScssPhp\Formatter\OutputBlock $block
116     */
117    protected function blockSelectors(OutputBlock $block)
118    {
119        $inner = $this->indentStr();
120        echo $inner . implode($this->tagSeparator, $block->selectors) . $this->open . $this->break;
121    }
122    /**
123     * Output block children
124     *
125     * @param \Leafo\ScssPhp\Formatter\OutputBlock $block
126     */
127    protected function blockChildren(OutputBlock $block)
128    {
129        foreach ($block->children as $child) {
130            $this->block($child);
131        }
132    }
133    /**
134     * Output non-empty block
135     *
136     * @param \Leafo\ScssPhp\Formatter\OutputBlock $block
137     */
138    protected function block(OutputBlock $block)
139    {
140        if (empty($block->lines) && empty($block->children)) {
141            return;
142        }
143        $pre = $this->indentStr();
144        if (!empty($block->selectors)) {
145            $this->blockSelectors($block);
146            $this->indentLevel++;
147        }
148        if (!empty($block->lines)) {
149            $this->blockLines($block);
150        }
151        if (!empty($block->children)) {
152            $this->blockChildren($block);
153        }
154        if (!empty($block->selectors)) {
155            $this->indentLevel--;
156            if (empty($block->children)) {
157                echo $this->break;
158            }
159            echo $pre . $this->close . $this->break;
160        }
161    }
162    /**
163     * Entry point to formatting a block
164     *
165     * @api
166     *
167     * @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree
168     *
169     * @return string
170     */
171    public function format(OutputBlock $block)
172    {
173        ob_start();
174        $this->block($block);
175        $out = ob_get_clean();
176        return $out;
177    }
178}
179