1<?php
2/**
3 * Copyright 2009-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 * @author   Chuck Hagenbuch <chuck@horde.org>
9 * @category Horde
10 * @license  http://www.horde.org/licenses/lgpl21 LGPL
11 * @package  Date
12 */
13
14/**
15 * Date repeater.
16 *
17 * @author    Chuck Hagenbuch <chuck@horde.org>
18 * @category  Horde
19 * @copyright 2009-2017 Horde LLC
20 * @license   http://www.horde.org/licenses/lgpl21 LGPL
21 * @package   Date
22 */
23class Horde_Date_Repeater_Time extends Horde_Date_Repeater
24{
25    public $currentTime;
26    public $type;
27    public $ambiguous;
28
29    public function __construct($time)
30    {
31        $t = str_replace(':', '', $time);
32
33        switch (strlen($t)) {
34        case 1:
35        case 2:
36            $hours = (int)$t;
37            $this->ambiguous = true;
38            $this->type = ($hours == 12) ? 0 : $hours * 3600;
39            break;
40
41        case 3:
42            $this->ambiguous = true;
43            $this->type = $t[0] * 3600 + (int)substr($t, 1, 2) * 60;
44            break;
45
46        case 4:
47            $this->ambiguous = (strpos($time, ':') !== false) && ($t[0] != 0) && ((int)substr($t, 0, 2) <= 12);
48            $hours = (int)substr($t, 0, 2);
49            $this->type = ($hours == 12) ?
50                ((int)substr($t, 2, 2) * 60) :
51                ($hours * 60 * 60 + (int)substr($t, 2, 2) * 60);
52            break;
53
54        case 5:
55            $this->ambiguous = true;
56            $this->type = $t[0] * 3600 + (int)substr($t, 1, 2) * 60 + (int)substr($t, 3, 2);
57            break;
58
59        case 6:
60            $this->ambiguous = (strpos($time, ':') !== false) && ($t[0] != 0) && ((int)substr($t, 0, 2) <= 12);
61            $hours = (int)substr($t, 0, 2);
62            $this->type = ($hours == 12) ?
63                ((int)substr($t, 2, 2) * 60 + (int)substr($t, 4, 2)) :
64                ($hours * 60 * 60 + (int)substr($t, 2, 2) * 60 + (int)substr($t, 4, 2));
65            break;
66
67        default:
68            throw new Horde_Date_Repeater_Exception('Time cannot exceed six digits');
69        }
70    }
71
72    /**
73     * Return the next past or future Span for the time that this Repeater represents
74     *   pointer - Symbol representing which temporal direction to fetch the next day
75     *             must be either :past or :future
76     */
77    public function next($pointer = 'future')
78    {
79        parent::next($pointer);
80
81        $halfDay = 3600 * 12;
82        $fullDay = 3600 * 24;
83
84        $first = false;
85
86        if (!$this->currentTime) {
87            $first = true;
88            $midnight = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day));
89            $yesterdayMidnight = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day - 1));
90            $tomorrowMidnight = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day + 1));
91
92            if ($pointer == 'future') {
93                if ($this->ambiguous) {
94                    foreach (array($midnight->add($this->type), $midnight->add($halfDay + $this->type), $tomorrowMidnight->add($this->type)) as $t) {
95                        if ($t->compareDateTime($this->now) >= 0) {
96                            $this->currentTime = $t;
97                            break;
98                        }
99                    }
100                } else {
101                    foreach (array($midnight->add($this->type), $tomorrowMidnight->add($this->type)) as $t) {
102                        if ($t->compareDateTime($this->now) >= 0) {
103                            $this->currentTime = $t;
104                            break;
105                        }
106                    }
107                }
108            } elseif ($pointer == 'past') {
109                if ($this->ambiguous) {
110                    foreach (array($midnight->add($halfDay + $this->type), $midnight->add($this->type), $yesterdayMidnight->add($this->type * 2)) as $t) {
111                        if ($t->compareDateTime($this->now) <= 0) {
112                            $this->currentTime = $t;
113                            break;
114                        }
115                    }
116                } else {
117                    foreach (array($midnight->add($this->type), $yesterdayMidnight->add($this->type)) as $t) {
118                        if ($t->compareDateTime($this->now) <= 0) {
119                            $this->currentTime = $t;
120                            break;
121                        }
122                    }
123                }
124            }
125
126            if (!$this->currentTime) {
127                throw new Horde_Date_Repeater_Exception('Current time cannot be null at this point');
128            }
129        }
130
131        if (!$first) {
132            $increment = $this->ambiguous ? $halfDay : $fullDay;
133            $this->currentTime->sec += ($pointer == 'future') ? $increment : -$increment;
134        }
135
136        return new Horde_Date_Span($this->currentTime, $this->currentTime->add(1));
137    }
138
139    public function this($context = 'future')
140    {
141        parent::this($context);
142
143        if ($context == 'none') {
144            $context = 'future';
145        }
146        return $this->next($context);
147    }
148
149    public function width()
150    {
151        return 1;
152    }
153
154    public function __toString()
155    {
156        return parent::__toString() . '-time-' . $this->type;
157    }
158
159}
160