1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "calDuration.h"
7 #include "calBaseCID.h"
8 
9 #include "nsComponentManagerUtils.h"
10 #include "nsServiceManagerUtils.h"
11 
12 #include "nsIClassInfoImpl.h"
13 
14 #include "calUtils.h"
15 
16 #define SECONDS_PER_WEEK 604800
17 #define SECONDS_PER_DAY 86400
18 #define SECONDS_PER_HOUR 3600
19 #define SECONDS_PER_MINUTE 60
20 
21 NS_IMPL_CLASSINFO(calDuration, nullptr, 0, CAL_DURATION_CID)
NS_IMPL_ISUPPORTS_CI(calDuration,calIDuration,calIDurationLibical)22 NS_IMPL_ISUPPORTS_CI(calDuration, calIDuration, calIDurationLibical)
23 
24 calDuration::calDuration() : mImmutable(false) { Reset(); }
25 
calDuration(const calDuration & cdt)26 calDuration::calDuration(const calDuration& cdt) {
27   mDuration.is_neg = cdt.mDuration.is_neg;
28   mDuration.weeks = cdt.mDuration.weeks;
29   mDuration.days = cdt.mDuration.days;
30   mDuration.hours = cdt.mDuration.hours;
31   mDuration.minutes = cdt.mDuration.minutes;
32   mDuration.seconds = cdt.mDuration.seconds;
33 
34   // copies are always mutable
35   mImmutable = false;
36 }
37 
calDuration(const struct icaldurationtype * const aDurationPtr)38 calDuration::calDuration(const struct icaldurationtype* const aDurationPtr)
39     : mImmutable(false) {
40   FromIcalDuration(aDurationPtr);
41 }
42 
43 NS_IMETHODIMP
GetIcalDuration(JS::MutableHandleValue)44 calDuration::GetIcalDuration(JS::MutableHandleValue) {
45   return NS_ERROR_NOT_IMPLEMENTED;
46 }
47 
48 NS_IMETHODIMP
SetIcalDuration(JS::HandleValue)49 calDuration::SetIcalDuration(JS::HandleValue) {
50   return NS_ERROR_NOT_IMPLEMENTED;
51 }
52 
53 NS_IMETHODIMP
GetIsMutable(bool * aResult)54 calDuration::GetIsMutable(bool* aResult) {
55   NS_ENSURE_ARG_POINTER(aResult);
56 
57   *aResult = !mImmutable;
58   return NS_OK;
59 }
60 
61 NS_IMETHODIMP
MakeImmutable()62 calDuration::MakeImmutable() {
63   mImmutable = true;
64   return NS_OK;
65 }
66 
67 NS_IMETHODIMP
Clone(calIDuration ** aResult)68 calDuration::Clone(calIDuration** aResult) {
69   calDuration* cdt = new calDuration(*this);
70   if (!cdt) return NS_ERROR_OUT_OF_MEMORY;
71 
72   NS_ADDREF(*aResult = cdt);
73   return NS_OK;
74 }
75 
76 NS_IMETHODIMP
Reset()77 calDuration::Reset() {
78   if (mImmutable) return NS_ERROR_FAILURE;
79 
80   mDuration.is_neg = 0;
81   mDuration.weeks = 0;
82   mDuration.days = 0;
83   mDuration.hours = 0;
84   mDuration.minutes = 0;
85   mDuration.seconds = 0;
86 
87   return NS_OK;
88 }
89 
GetIsNegative(bool * _retval)90 NS_IMETHODIMP calDuration::GetIsNegative(bool* _retval) {
91   *_retval = mDuration.is_neg;
92   return NS_OK;
93 }
SetIsNegative(bool aValue)94 NS_IMETHODIMP calDuration::SetIsNegative(bool aValue) {
95   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
96   mDuration.is_neg = aValue;
97   return NS_OK;
98 }
99 
GetWeeks(int16_t * _retval)100 NS_IMETHODIMP calDuration::GetWeeks(int16_t* _retval) {
101   *_retval = (int16_t)mDuration.weeks;
102   return NS_OK;
103 }
SetWeeks(int16_t aValue)104 NS_IMETHODIMP calDuration::SetWeeks(int16_t aValue) {
105   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
106   mDuration.weeks = aValue;
107   return NS_OK;
108 }
109 
GetDays(int16_t * _retval)110 NS_IMETHODIMP calDuration::GetDays(int16_t* _retval) {
111   *_retval = (int16_t)mDuration.days;
112   return NS_OK;
113 }
SetDays(int16_t aValue)114 NS_IMETHODIMP calDuration::SetDays(int16_t aValue) {
115   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
116   mDuration.days = aValue;
117   return NS_OK;
118 }
119 
GetHours(int16_t * _retval)120 NS_IMETHODIMP calDuration::GetHours(int16_t* _retval) {
121   *_retval = (int16_t)mDuration.hours;
122   return NS_OK;
123 }
SetHours(int16_t aValue)124 NS_IMETHODIMP calDuration::SetHours(int16_t aValue) {
125   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
126   mDuration.hours = aValue;
127   return NS_OK;
128 }
129 
GetMinutes(int16_t * _retval)130 NS_IMETHODIMP calDuration::GetMinutes(int16_t* _retval) {
131   *_retval = (int16_t)mDuration.minutes;
132   return NS_OK;
133 }
SetMinutes(int16_t aValue)134 NS_IMETHODIMP calDuration::SetMinutes(int16_t aValue) {
135   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
136   mDuration.minutes = aValue;
137   return NS_OK;
138 }
139 
GetSeconds(int16_t * _retval)140 NS_IMETHODIMP calDuration::GetSeconds(int16_t* _retval) {
141   *_retval = (int16_t)mDuration.seconds;
142   return NS_OK;
143 }
SetSeconds(int16_t aValue)144 NS_IMETHODIMP calDuration::SetSeconds(int16_t aValue) {
145   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
146   mDuration.seconds = aValue;
147   return NS_OK;
148 }
149 
GetInSeconds(int32_t * _retval)150 NS_IMETHODIMP calDuration::GetInSeconds(int32_t* _retval) {
151   int32_t retval =
152       (((int32_t)((int16_t)mDuration.weeks * SECONDS_PER_WEEK)) +
153        ((int32_t)((int16_t)mDuration.days * SECONDS_PER_DAY)) +
154        ((int32_t)((int16_t)mDuration.hours * SECONDS_PER_HOUR)) +
155        ((int32_t)((int16_t)mDuration.minutes * SECONDS_PER_MINUTE)) +
156        ((int32_t)((int16_t)mDuration.seconds)));
157   if (mDuration.is_neg) retval = -retval;
158   *_retval = retval;
159 
160   return NS_OK;
161 }
SetInSeconds(int32_t aValue)162 NS_IMETHODIMP calDuration::SetInSeconds(int32_t aValue) {
163   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
164 
165   mDuration.is_neg = (aValue < 0);
166   if (mDuration.is_neg) aValue = -aValue;
167 
168   // set weeks exOR days/hours/...
169   mDuration.weeks =
170       ((aValue % SECONDS_PER_WEEK) == 0 ? aValue / SECONDS_PER_WEEK : 0);
171   aValue -= (mDuration.weeks * SECONDS_PER_WEEK);
172 
173   mDuration.days = aValue / SECONDS_PER_DAY;
174   aValue -= (mDuration.days * SECONDS_PER_DAY);
175 
176   mDuration.hours = aValue / SECONDS_PER_HOUR;
177   aValue -= (mDuration.hours * SECONDS_PER_HOUR);
178 
179   mDuration.minutes = aValue / SECONDS_PER_MINUTE;
180   aValue -= (mDuration.minutes * SECONDS_PER_MINUTE);
181 
182   mDuration.seconds = aValue;
183 
184   return NS_OK;
185 }
186 
AddDuration(calIDuration * aDuration)187 NS_IMETHODIMP calDuration::AddDuration(calIDuration* aDuration) {
188   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
189 
190   nsresult rv;
191   nsCOMPtr<calIDurationLibical> icaldur = do_QueryInterface(aDuration, &rv);
192   NS_ENSURE_SUCCESS(rv, rv);
193 
194   struct icaldurationtype idt;
195   icaldur->ToIcalDuration(&idt);
196 
197   // Calculate the new absolute value of the duration
198   // For two negative durations, the abs. value will increase,
199   // so use + in that case.
200   // Of course, also use + when both durations are positive.
201   if (idt.is_neg == mDuration.is_neg) {
202     mDuration.weeks += idt.weeks;
203     mDuration.days += idt.days;
204     mDuration.hours += idt.hours;
205     mDuration.minutes += idt.minutes;
206     mDuration.seconds += idt.seconds;
207   } else {
208     mDuration.weeks -= idt.weeks;
209     mDuration.days -= idt.days;
210     mDuration.hours -= idt.hours;
211     mDuration.minutes -= idt.minutes;
212     mDuration.seconds -= idt.seconds;
213   }
214 
215   Normalize();
216 
217   return NS_OK;
218 }
219 
220 NS_IMETHODIMP
Normalize()221 calDuration::Normalize() {
222   if (mImmutable) return NS_ERROR_CALENDAR_IMMUTABLE;
223 
224   int32_t totalInSeconds;
225   GetInSeconds(&totalInSeconds);
226   SetInSeconds(totalInSeconds);
227 
228   return NS_OK;
229 }
230 
231 NS_IMETHODIMP
ToString(nsACString & aResult)232 calDuration::ToString(nsACString& aResult) { return GetIcalString(aResult); }
233 
NS_IMETHODIMP_(void)234 NS_IMETHODIMP_(void)
235 calDuration::ToIcalDuration(struct icaldurationtype* icald) {
236   icald->is_neg = mDuration.is_neg;
237   icald->weeks = mDuration.weeks;
238   icald->days = mDuration.days;
239   icald->hours = mDuration.hours;
240   icald->minutes = mDuration.minutes;
241   icald->seconds = mDuration.seconds;
242   return;
243 }
244 
FromIcalDuration(const struct icaldurationtype * const icald)245 void calDuration::FromIcalDuration(const struct icaldurationtype* const icald) {
246   mDuration.is_neg = icald->is_neg;
247   mDuration.weeks = icald->weeks;
248   mDuration.days = icald->days;
249   mDuration.hours = icald->hours;
250   mDuration.minutes = icald->minutes;
251   mDuration.seconds = icald->seconds;
252   return;
253 }
254 
255 NS_IMETHODIMP
GetIcalString(nsACString & aResult)256 calDuration::GetIcalString(nsACString& aResult) {
257   // note that ics is owned by libical, so we don't need to free
258   const char* ics = icaldurationtype_as_ical_string(mDuration);
259 
260   if (ics) {
261     aResult.Assign(ics);
262     return NS_OK;
263   }
264 
265   return NS_ERROR_OUT_OF_MEMORY;
266 }
267 
268 NS_IMETHODIMP
SetIcalString(const nsACString & aIcalString)269 calDuration::SetIcalString(const nsACString& aIcalString) {
270   mDuration =
271       icaldurationtype_from_string(PromiseFlatCString(aIcalString).get());
272   return NS_OK;
273 }
274 
275 NS_IMETHODIMP
Compare(calIDuration * aOther,int32_t * aResult)276 calDuration::Compare(calIDuration* aOther, int32_t* aResult) {
277   int32_t thisInSeconds, otherInSeconds;
278 
279   // cast to void because these calls can't fail
280   (void)GetInSeconds(&thisInSeconds);
281   (void)aOther->GetInSeconds(&otherInSeconds);
282 
283   if (thisInSeconds < otherInSeconds) {
284     *aResult = -1;
285   } else if (thisInSeconds > otherInSeconds) {
286     *aResult = 1;
287   } else {
288     *aResult = 0;
289   }
290 
291   return NS_OK;
292 }
293