1<?php
2
3/**
4 * Plugin RefNotes: Note
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Mykola Ostrovskyy <dwpforge@gmail.com>
8 */
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11class refnotes_note_block_iterator extends FilterIterator {
12
13    private $note;
14    private $limit;
15    private $count;
16
17    /**
18     * Constructor
19     */
20    public function __construct($note, $limit) {
21        $this->note = new ArrayObject($note);
22        $this->limit = $this->getBlockLimit($limit);
23        $this->count = 0;
24
25        parent::__construct($this->note->getIterator());
26    }
27
28    /**
29     *
30     */
31    function accept() {
32        $result = $this->current()->isValid();
33
34        if ($result) {
35            ++$this->count;
36        }
37
38        return $result;
39    }
40
41    /**
42     *
43     */
44    function valid() {
45        return parent::valid() && (($this->limit == 0) || ($this->count <= $this->limit));
46    }
47
48    /**
49     *
50     */
51    private function getBlockLimit($limit) {
52        if (preg_match('/(\/?)(\d+)/', $limit, $match) == 1) {
53            if ($match[1] != '') {
54                $devider = intval($match[2]);
55                $result = ceil($this->getValidCount() / $devider);
56            }
57            else {
58                $result = intval($match[2]);
59            }
60        }
61        else {
62            $result = 0;
63        }
64
65        return $result;
66    }
67
68    /**
69     *
70     */
71    private function getValidCount() {
72        $result = 0;
73
74        foreach ($this->note as $note) {
75            if ($note->isValid()) {
76                ++$result;
77            }
78        }
79
80        return $result;
81    }
82}
83
84////////////////////////////////////////////////////////////////////////////////////////////////////
85class refnotes_note_mock {
86
87    /**
88     *
89     */
90    public function getScope() {
91        return new refnotes_scope_mock();
92    }
93
94    /**
95     *
96     */
97    public function setText($text) {
98    }
99
100    /**
101     *
102     */
103    public function addReference($reference) {
104    }
105}
106
107////////////////////////////////////////////////////////////////////////////////////////////////////
108class refnotes_note extends refnotes_refnote {
109
110    protected $scope;
111    protected $namespaceName;
112    protected $id;
113    protected $name;
114    protected $inline;
115    protected $reference;
116    protected $text;
117    protected $processed;
118
119    /**
120     *
121     */
122    public static function getNamePattern($type) {
123        if (($type == 'full-extended') || ($type == 'extended')) {
124            $result = ($type == 'full-extended') ? refnotes_namespace::getNamePattern('optional') : '';
125            $result .= '[[:alpha:]\d][\w.&\(\)\[\]{}+-]*';
126        }
127        else {
128            $result = '[[:alpha:]]\w*';
129        }
130
131        return $result;
132    }
133
134    /**
135     * Constructor
136     */
137    public function __construct($scope, $namespaceName, $name) {
138        parent::__construct();
139
140        $this->scope = $scope;
141        $this->namespaceName = $namespaceName;
142        $this->id = -1;
143        $this->name = $name;
144        $this->inline = false;
145        $this->reference = array();
146        $this->text = '';
147        $this->processed = false;
148    }
149
150    /**
151     *
152     */
153    private function initId() {
154        $this->id = $this->scope->getNoteId();
155
156        if ($this->name == '') {
157            $this->name = '#' . $this->id;
158        }
159    }
160
161    /**
162     *
163     */
164    public function getId() {
165        return $this->id;
166    }
167
168    /**
169     *
170     */
171    public function getName() {
172        return $this->name;
173    }
174
175    /**
176     *
177     */
178    public function getNamespaceName() {
179        return $this->namespaceName;
180    }
181
182    /**
183     *
184     */
185    public function getScope() {
186        return $this->scope;
187    }
188
189    /**
190     *
191     */
192    public function setText($text) {
193        if ($this->text == '' || !$this->inline) {
194            $this->text = $text;
195        }
196    }
197
198    /**
199     *
200     */
201    public function getText() {
202        return $this->text;
203    }
204
205    /**
206     *
207     */
208    public function addReference($reference) {
209        if ($this->id == -1 && !$this->inline) {
210            $this->inline = $reference->isInline();
211
212            if (!$this->inline) {
213                $this->initId();
214            }
215        }
216
217        if ($reference->isBackReferenced()) {
218            $this->reference[] = $reference;
219            $this->processed = false;
220        }
221    }
222
223    /**
224     * Checks if the note should be processed
225     */
226    public function isValid() {
227        return !$this->processed && !empty($this->reference) && $this->text != '';
228    }
229}
230
231////////////////////////////////////////////////////////////////////////////////////////////////////
232class refnotes_renderer_note extends refnotes_note {
233
234    /**
235     *
236     */
237    public function getMinReferenceId() {
238        $result = -1;
239
240        /* References are added in ascending order, so the first valid id should be minimal. */
241        foreach ($this->reference as $reference) {
242            if ($reference->getId() != -1) {
243                $result = $reference->getId();
244                break;
245            }
246        }
247
248        return $result;
249    }
250
251    /**
252     *
253     */
254    public function getAnchorName() {
255        $result = 'refnotes';
256        $result .= $this->scope->getName();
257        $result .= ':note' . $this->id;
258
259        return $result;
260    }
261
262    /**
263     *
264     */
265    public function render($mode) {
266        $doc = $this->scope->getRenderer()->renderNote($mode, $this, $this->reference);
267
268        $this->reference = array();
269        $this->processed = true;
270
271        return $doc;
272    }
273}
274
275////////////////////////////////////////////////////////////////////////////////////////////////////
276class refnotes_action_note extends refnotes_note {
277
278    /**
279     * Constructor
280     */
281    public function __construct($scope, $namespaceName, $name) {
282        parent::__construct($scope, $namespaceName, $name);
283
284        $this->loadDatabaseDefinition();
285
286        $this->inline = $this->getAttribute('inline', false);
287    }
288
289    /**
290     *
291     */
292    private function loadDatabaseDefinition() {
293        $name = $this->namespaceName . $this->name;
294        $note = refnotes_reference_database::getInstance()->findNote($name);
295
296        if ($note != NULL) {
297            $this->attributes = $note->getAttributes();
298            $this->data = $note->getData();
299        }
300    }
301
302    /**
303     *
304     */
305    public function addReference($reference) {
306        parent::addReference($reference);
307
308        $exclude = $this->scope->getRenderer()->getReferencePrivateDataSet();
309        $data = array_diff_key($reference->getData(), array_flip($exclude));
310        $this->data = array_merge($this->data, $data);
311    }
312
313    /**
314     * Checks if the note should be processed. Simple notes are also reported as valid so that
315     * scope limits will produce note blocks identical to ones during rendering.
316     */
317    public function isValid() {
318        return !$this->processed && !empty($this->reference) && ($this->text != '' || $this->hasData());
319    }
320
321    /**
322     * Inject reference database data into references so that they can be properly rendered.
323     * Inject note text into the first reference.
324     */
325    public function rewriteReferences() {
326        if ($this->text == '' && $this->hasData()) {
327            foreach ($this->reference as $reference) {
328                $reference->rewrite($this->attributes, $this->data);
329            }
330
331            $this->reference[0]->setNoteText($this->scope->getRenderer()->renderNoteText($this));
332        }
333
334        $this->processed = true;
335    }
336}
337