blob: a8104d1ad135fa8667fb067b44c98ae6db55e53c [file] [log] [blame]
Zhiyi Zhangcea58d52015-08-26 10:19:56 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California
4 *
5 * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
6 * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
7 *
8 * ndn-group-encrypt is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-group-encrypt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-group-encrypt, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
20 */
21
22#include "repetitive-interval.hpp"
23#include "tlv.hpp"
24
25#include <ndn-cxx/encoding/block-helpers.hpp>
26#include <ndn-cxx/util/concepts.hpp>
27#include <boost/date_time/posix_time/posix_time.hpp>
28
29namespace ndn {
30namespace gep {
31
32static const TimeStamp DEFAULT_TIME = boost::posix_time::from_iso_string("14000101T000000");
33
34BOOST_CONCEPT_ASSERT((WireEncodable<RepetitiveInterval>));
35BOOST_CONCEPT_ASSERT((WireDecodable<RepetitiveInterval>));
36
37RepetitiveInterval::RepetitiveInterval()
38 : m_startDate(DEFAULT_TIME)
39 , m_endDate(DEFAULT_TIME)
40 , m_intervalStartHour(0)
41 , m_intervalEndHour(24)
42 , m_nRepeats(0)
43 , m_unit(RepeatUnit::NONE)
44{
45}
46
47RepetitiveInterval::RepetitiveInterval(const Block& block)
48{
49 wireDecode(block);
50}
51
52RepetitiveInterval::RepetitiveInterval(const TimeStamp& startDate,
53 const TimeStamp& endDate,
54 size_t intervalStartHour,
55 size_t intervalEndHour,
56 size_t nRepeats,
57 RepeatUnit unit)
58 : m_startDate(startDate)
59 , m_endDate(endDate)
60 , m_intervalStartHour(intervalStartHour)
61 , m_intervalEndHour(intervalEndHour)
62 , m_nRepeats(nRepeats)
63 , m_unit(unit)
64{
65 BOOST_ASSERT(m_intervalStartHour < m_intervalEndHour);
66 BOOST_ASSERT(m_startDate.date() <= m_endDate.date());
67 BOOST_ASSERT(m_intervalEndHour <= 24);
68 if (unit == RepeatUnit::NONE)
69 BOOST_ASSERT(m_startDate.date() == m_endDate.date());
70}
71
72template<encoding::Tag TAG>
73size_t
74RepetitiveInterval::wireEncode(EncodingImpl<TAG>& encoder) const
75{
76 using namespace boost::posix_time;
77
78 size_t totalLength = 0;
79
80 // RepeatUnit
81 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::RepeatUnit,
82 static_cast<size_t>(m_unit));
83 // NRepeat
84 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::NRepeats, m_nRepeats);
85 // IntervalEndHour
86 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::IntervalEndHour, m_intervalEndHour);
87 // IntervalStartHour
88 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::IntervalStartHour,
89 m_intervalStartHour);
90 // EndDate
91 totalLength += prependStringBlock(encoder, tlv::EndDate, to_iso_string(m_endDate));
92 // StartDate
93 totalLength += prependStringBlock(encoder, tlv::StartDate, to_iso_string(m_startDate));
94
95 totalLength += encoder.prependVarNumber(totalLength);
96 totalLength += encoder.prependVarNumber(tlv::RepetitiveInterval);
97
98 return totalLength;
99}
100
101const Block&
102RepetitiveInterval::wireEncode() const
103{
104 if (m_wire.hasWire())
105 return m_wire;
106
107 EncodingEstimator estimator;
108 size_t estimatedSize = wireEncode(estimator);
109
110 EncodingBuffer buffer(estimatedSize, 0);
111 wireEncode(buffer);
112
113 this->m_wire = buffer.block();
114 return m_wire;
115}
116
117void
118RepetitiveInterval::wireDecode(const Block& wire)
119{
120 using namespace boost::posix_time;
121
122 if (wire.type() != tlv::RepetitiveInterval)
123 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding RepetitiveInterval"));
124
125 m_wire = wire;
126 m_wire.parse();
127
128 if (m_wire.elements_size() != 6)
129 BOOST_THROW_EXCEPTION(tlv::Error("RepetitiveInterval tlv does not have six sub-TLVs"));
130
131 Block::element_const_iterator it = m_wire.elements_begin();
132 // StartDate
133 if (it->type() == tlv::StartDate) {
134 m_startDate = ptime(from_iso_string(readString(*it)));
135 it++;
136 }
137 else
138 BOOST_THROW_EXCEPTION(tlv::Error("First element must be StartDate"));
139
140 // EndDate
141 if (it->type() == tlv::EndDate) {
142 m_endDate = ptime(from_iso_string(readString(*it)));
143 it++;
144 }
145 else
146 BOOST_THROW_EXCEPTION(tlv::Error("Second element must be EndDate"));
147
148 // IntervalStartHour
149 if (it->type() == tlv::IntervalStartHour) {
150 m_intervalStartHour = readNonNegativeInteger(*it);
151 it++;
152 }
153 else
154 BOOST_THROW_EXCEPTION(tlv::Error("Third element must be IntervalStartHour"));
155
156 // IntervalEndHour
157 if (it->type() == tlv::IntervalEndHour) {
158 m_intervalEndHour = readNonNegativeInteger(*it);
159 it++;
160 }
161 else
162 BOOST_THROW_EXCEPTION(tlv::Error("Fourth element must be IntervalEndHour"));
163
164 // NRepeats
165 if (it->type() == tlv::NRepeats) {
166 m_nRepeats = readNonNegativeInteger(*it);
167 it++;
168 }
169 else
170 BOOST_THROW_EXCEPTION(tlv::Error("Fifth element must be NRepeats"));
171
172 // RepeatUnit
173 if (it->type() == tlv::RepeatUnit) {
174 m_unit = static_cast<RepeatUnit>(readNonNegativeInteger(*it));
175 it++;
176 }
177 else
178 BOOST_THROW_EXCEPTION(tlv::Error("The last element must be RepeatUnit"));
179}
180
181std::tuple<bool, Interval>
182RepetitiveInterval::getInterval(const TimeStamp& tp) const
183{
184 TimeStamp startTime;
185 TimeStamp endTime;
186 bool isPositive;
187
188 if (!this->hasIntervalOnDate(tp)) {
189 // there is no interval on the date of tp
190 startTime = TimeStamp(tp.date(), boost::posix_time::hours(0));
191 endTime = TimeStamp(tp.date(), boost::posix_time::hours(24));
192 isPositive = false;
193 }
194 else {
195 // there is an interval on the date of tp
196 startTime = TimeStamp(tp.date(), boost::posix_time::hours(m_intervalStartHour));
197 endTime = TimeStamp(tp.date(), boost::posix_time::hours(m_intervalEndHour));
198
199 // check if in the time duration
200 if (tp < startTime) {
201 endTime = startTime;
202 startTime = TimeStamp(tp.date(), boost::posix_time::hours(0));
203 isPositive = false;
204 }
205 else if (tp > endTime) {
206 startTime = endTime;
207 endTime = TimeStamp(tp.date(), boost::posix_time::hours(24));
208 isPositive = false;
209 }
210 else {
211 isPositive = true;
212 }
213 }
214 return std::make_tuple(isPositive, Interval(startTime, endTime));
215}
216
217bool
218RepetitiveInterval::hasIntervalOnDate(const TimeStamp& tp) const
219{
220 namespace bg = boost::gregorian;
221
222 // check if in the bound of the interval
223 if (tp.date() < m_startDate.date() || tp.date() > m_endDate.date()) {
224 return false;
225 }
226
227 if (m_unit == RepeatUnit::NONE) {
228 return true;
229 }
230
231 // check if in the matching date
232 bg::date dateA = tp.date();
233 bg::date dateB = m_startDate.date();
234 if (m_unit == RepeatUnit::DAY) {
235 bg::date_duration duration = dateA - dateB;
236 if (static_cast<size_t>(duration.days()) % m_nRepeats == 0)
237 return true;
238 }
239 else if (m_unit == RepeatUnit::MONTH && dateA.day() == dateB.day()) {
240 size_t yearDiff = static_cast<size_t>(dateA.year() - dateB.year());
241 size_t monthDiff = 12 * yearDiff + dateA.month().as_number() - dateB.month().as_number();
242 if (monthDiff % m_nRepeats == 0)
243 return true;
244 }
245 else if (m_unit == RepeatUnit::YEAR &&
246 dateA.day().as_number() == dateB.day().as_number() &&
247 dateA.month().as_number() == dateB.month().as_number()) {
248 size_t diff = static_cast<size_t>(dateA.year() - dateB.year());
249 if (diff % m_nRepeats == 0)
250 return true;
251 }
252
253 return false;
254}
255
256bool
257RepetitiveInterval::operator<(const RepetitiveInterval& interval) const
258{
259 if (m_startDate < interval.getStartDate())
260 return true;
Yingdi Yua717b882016-03-09 17:56:42 -0800261 else if (m_startDate > interval.getStartDate())
262 return false;
263
Zhiyi Zhangcea58d52015-08-26 10:19:56 -0700264 if (m_endDate < interval.getEndDate())
265 return true;
Yingdi Yua717b882016-03-09 17:56:42 -0800266 else if (m_endDate > interval.getEndDate())
267 return false;
268
Zhiyi Zhangcea58d52015-08-26 10:19:56 -0700269 if (m_intervalStartHour < interval.getIntervalStartHour())
270 return true;
Yingdi Yua717b882016-03-09 17:56:42 -0800271 else if (m_intervalStartHour > interval.getIntervalStartHour())
272 return false;
273
Zhiyi Zhangcea58d52015-08-26 10:19:56 -0700274 if (m_intervalEndHour < interval.getIntervalEndHour())
275 return true;
Yingdi Yua717b882016-03-09 17:56:42 -0800276 else if (m_intervalEndHour > interval.getIntervalEndHour())
277 return false;
278
Zhiyi Zhangcea58d52015-08-26 10:19:56 -0700279 if (m_nRepeats < interval.getNRepeats())
280 return true;
Yingdi Yua717b882016-03-09 17:56:42 -0800281 else if (m_nRepeats > interval.getNRepeats())
282 return false;
283
284 return (static_cast<size_t>(m_unit) < static_cast<size_t>(interval.getRepeatUnit()));
Zhiyi Zhangcea58d52015-08-26 10:19:56 -0700285}
286
287} // namespace gep
288} // namespace ndn