1<?php
2/**
3 * Copyright 2008-2017 Horde LLC (http://www.horde.org/)
4 *
5 * See the enclosed file LICENSE 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 2008-2017 Horde LLC
10 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
11 * @package   Imap_Client
12 */
13
14/**
15 * Object representing the threaded sort results from
16 * Horde_Imap_Client_Base#thread().
17 *
18 * @author    Michael Slusarz <slusarz@horde.org>
19 * @category  Horde
20 * @copyright 2008-2017 Horde LLC
21 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
22 * @package   Imap_Client
23 */
24class Horde_Imap_Client_Data_Thread implements Countable, Serializable
25{
26    /**
27     * Internal thread data structure. Keys are base values, values are arrays
28     * with keys as the ID and values as the level.
29     *
30     * @var array
31     */
32    protected $_thread = array();
33
34    /**
35     * The index type.
36     *
37     * @var string
38     */
39    protected $_type;
40
41    /**
42     * Constructor.
43     *
44     * @param array $data   See $_thread.
45     * @param string $type  Either 'sequence' or 'uid'.
46     */
47    public function __construct($data, $type)
48    {
49        $this->_thread = $data;
50        $this->_type = $type;
51    }
52
53    /**
54     * Return the ID type.
55     *
56     * @return string  Either 'sequence' or 'uid'.
57     */
58    public function getType()
59    {
60        return $this->_type;
61    }
62
63    /**
64     * Return the sorted list of messages indices.
65     *
66     * @return Horde_Imap_Client_Ids  The sorted list of messages.
67     */
68    public function messageList()
69    {
70        return new Horde_Imap_Client_Ids($this->_getAllIndices(), $this->getType() == 'sequence');
71    }
72
73    /**
74     * Returns the list of messages in a thread.
75     *
76     * @param integer $index  An index contained in the thread.
77     *
78     * @return array  Keys are indices, values are objects with the following
79     *                properties:
80     *   - base: (integer) Base ID of the thread. If null, thread is a single
81     *           message.
82     *   - last: (boolean) If true, this is the last index in the sublevel.
83     *   - level: (integer) The sublevel of the index.
84     */
85    public function getThread($index)
86    {
87        foreach ($this->_thread as $v) {
88            if (isset($v[$index])) {
89                reset($v);
90
91                $ob = new stdClass;
92                $ob->base = (count($v) > 1) ? key($v) : null;
93                $ob->last = false;
94
95                $levels = $out = array();
96                $last = 0;
97
98                while (($v2 = current($v)) !== false) {
99                    $k2 = key($v);
100                    $ob2 = clone $ob;
101                    $ob2->level = $v2;
102                    $out[$k2] = $ob2;
103
104                    if (($last < $v2) && isset($levels[$v2])) {
105                        $out[$levels[$v2]]->last = true;
106                    }
107                    $levels[$v2] = $k2;
108                    $last = $v2;
109                    next($v);
110                }
111
112                foreach ($levels as $v) {
113                    $out[$v]->last = true;
114                }
115
116                return $out;
117            }
118        }
119
120        return array();
121    }
122
123    /* Countable methods. */
124
125    /**
126     */
127    public function count()
128    {
129        return count($this->_getAllIndices());
130    }
131
132    /* Serializable methods. */
133
134    /**
135     */
136    public function serialize()
137    {
138        return json_encode(array(
139            $this->_thread,
140            $this->_type
141        ));
142    }
143
144    /**
145     */
146    public function unserialize($data)
147    {
148        list($this->_thread, $this->_type) = json_decode($data, true);
149    }
150
151    /* Protected methods. */
152
153    /**
154     * Return all indices.
155     *
156     * @return array  An array of indices.
157     */
158    protected function _getAllIndices()
159    {
160        $out = array();
161
162        foreach ($this->_thread as $val) {
163            $out += $val;
164        }
165
166        return array_keys($out);
167    }
168
169}
170