1<?php
2/**
3 * Copyright 2015-2017 Horde LLC (http://www.horde.org/)
4 *
5 * See the enclosed file COPYING for license information (LGPL). If you
6 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
7 *
8 * @category  Horde
9 * @copyright 2015-2017 Horde LLC
10 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
11 * @package   Mime
12 */
13
14/**
15 * Recursive iterator for Horde_Mime_Part objects. This iterator is
16 * self-contained and independent of all other iterators.
17 *
18 * @author    Michael Slusarz <slusarz@horde.org>
19 * @category  Horde
20 * @copyright 2015-2017 Horde LLC
21 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
22 * @package   Mime
23 * @since     2.9.0
24 */
25class Horde_Mime_Part_Iterator
26implements Countable, Iterator
27{
28    /**
29     * Include the base when iterating?
30     *
31     * @var boolean
32     */
33    protected $_includeBase;
34
35    /**
36     * Base part.
37     *
38     * @var Horde_Mime_Part
39     */
40    protected $_part;
41
42    /**
43     * State data.
44     *
45     * @var object
46     */
47    protected $_state;
48
49    /**
50     * Constructor.
51     */
52    public function __construct(Horde_Mime_Part $part, $base = false)
53    {
54        $this->_includeBase = (bool)$base;
55        $this->_part = $part;
56    }
57
58    /* Countable methods. */
59
60    /**
61     * Returns the number of message parts.
62     *
63     * @return integer  Number of message parts.
64     */
65    public function count()
66    {
67        return count(iterator_to_array($this));
68    }
69
70    /* RecursiveIterator methods. */
71
72    /**
73     */
74    public function current()
75    {
76        return $this->valid()
77            ? $this->_state->current
78            : null;
79    }
80
81    /**
82     */
83    public function key()
84    {
85        return ($curr = $this->current())
86            ? $curr->getMimeId()
87            : null;
88    }
89
90    /**
91     */
92    public function next()
93    {
94        if (!isset($this->_state)) {
95            return;
96        }
97
98        $out = $this->_state->current->getPartByIndex($this->_state->index++);
99
100        if ($out) {
101            $this->_state->recurse[] = array(
102                $this->_state->current,
103                $this->_state->index
104            );
105            $this->_state->current = $out;
106            $this->_state->index = 0;
107        } elseif ($tmp = array_pop($this->_state->recurse)) {
108            $this->_state->current = $tmp[0];
109            $this->_state->index = $tmp[1];
110            $this->next();
111        } else {
112            unset($this->_state);
113        }
114    }
115
116    /**
117     */
118    public function rewind()
119    {
120        $this->_state = new stdClass;
121        $this->_state->current = $this->_part;
122        $this->_state->index = 0;
123        $this->_state->recurse = array();
124
125        if (!$this->_includeBase) {
126            $this->next();
127        }
128    }
129
130    /**
131     */
132    public function valid()
133    {
134        return !empty($this->_state);
135    }
136
137}
138