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_DayPortion extends Horde_Date_Repeater
24{
25    /**
26     * 6am-12am (6 * 60 * 60, 12 * 60 * 60)
27     */
28    public static $morning = array(21600, 43200);
29
30    /**
31     * 1pm-5pm (13 * 60 * 60, 17 * 60 * 60)
32     */
33    public static $afternoon = array(46800, 61200);
34
35    /**
36     * 5pm-8pm (17 * 60 * 60, 20 * 60 * 60)
37     */
38    public static $evening = array(61200, 72000);
39
40    /**
41     * 8pm-12pm (20 * 60 * 60, 24 * 60 * 60)
42     */
43    public static $night = array(72000, 86400);
44
45    public $range;
46    public $currentSpan;
47    public $type;
48
49    public function __construct($type)
50    {
51        $this->type = $type;
52
53        if (is_int($type)) {
54            $this->range = array(($type * 3600), (($type + 12) * 3600));
55        } else {
56            $lookup = array(
57                'am' => array(0, (12 * 3600 - 1)),
58                'pm' => array((12 * 3600), (24 * 3600 - 1)),
59                'morning' => self::$morning,
60                'afternoon' => self::$afternoon,
61                'evening' => self::$evening,
62                'night' => self::$night,
63            );
64            if (!isset($lookup[$type])) {
65                throw new InvalidArgumentException("Invalid type '$type' for Repeater_DayPortion");
66            }
67            $this->range = $lookup[$type];
68        }
69    }
70
71    public function next($pointer = 'future')
72    {
73        parent::next($pointer);
74
75        if (!$this->currentSpan) {
76            $nowSeconds = $this->now->hour * 3600 + $this->now->min * 60 + $this->now->sec;
77            if ($nowSeconds < $this->range[0]) {
78                switch ($pointer) {
79                case 'future':
80                    $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day, 'sec' => $this->range[0]));
81                    break;
82
83                case 'past':
84                    $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day - 1, 'sec' => $this->range[0]));
85                    break;
86                }
87            } elseif ($nowSeconds > $this->range[1]) {
88                switch ($pointer) {
89                case 'future':
90                    $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day + 1, 'sec' => $this->range[0]));
91                    break;
92
93                case 'past':
94                    $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day, 'sec' => $this->range[0]));
95                    break;
96                }
97            } else {
98                switch ($pointer) {
99                case 'future':
100                    $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day + 1, 'sec' => $this->range[0]));
101                    break;
102
103                case 'past':
104                    $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day - 1, 'sec' => $this->range[0]));
105                    break;
106                }
107            }
108
109            $rangeEnd = $rangeStart->add($this->range[1] - $this->range[0]);
110            $this->currentSpan = new Horde_Date_Span($rangeStart, $rangeEnd);
111        } else {
112            switch ($pointer) {
113            case 'future':
114                $this->currentSpan = $this->currentSpan->add(array('day' => 1));
115                break;
116
117            case 'past':
118                $this->currentSpan = $this->currentSpan->add(array('day' => -1));
119                break;
120            }
121        }
122
123        return $this->currentSpan;
124    }
125
126    public function this($context = 'future')
127    {
128        parent::this($context);
129
130        $rangeStart = new Horde_Date(array('year' => $this->now->year, 'month' => $this->now->month, 'day' => $this->now->day, 'sec' => $this->range[0]));
131        $this->currentSpan = new Horde_Date_Span($rangeStart, $rangeStart->add($this->range[1] - $this->range[0]));
132        return $this->currentSpan;
133    }
134
135    public function offset($span, $amount, $pointer)
136    {
137        $this->now = $span->begin;
138        $portionSpan = $this->next($pointer);
139        $direction = ($pointer == 'future') ? 1 : -1;
140        return $portionSpan->add(array('day' => $direction * ($amount - 1)));
141    }
142
143    public function width()
144    {
145        if (!$this->range) {
146            throw new Horde_Date_Repeater_Exception('Range has not been set');
147        }
148
149        if ($this->currentSpan) {
150            return $this->currentSpan->width();
151        }
152
153        if (is_int($this->type)) {
154            return (12 * 3600);
155        } else {
156            return $this->range[1] - $this->range[0];
157        }
158    }
159
160    public function __toString()
161    {
162        return parent::__toString() . '-dayportion-' . $this->type;
163    }
164
165}
166