/
VFreeBusy.cs
518 lines (441 loc) · 18.3 KB
/
VFreeBusy.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
//===============================================================================================================
// System : Personal Data Interchange Classes
// File : VFreeBusy.cs
// Author : Eric Woodruff (Eric@EWoodruff.us)
// Updated : 11/24/2018
// Note : Copyright 2004-2018, Eric Woodruff, All rights reserved
// Compiler: Microsoft Visual C#
//
// This file contains the definition for the VFreeBusy object used by vCalendar and iCalendar objects
//
// This code is published under the Microsoft Public License (Ms-PL). A copy of the license should be
// distributed with the code and can be found at the project website: https://github.com/EWSoftware/PDI.
// This notice, the author's name, and all copyright notices must remain intact in all applications,
// documentation, and source files.
//
// Date Who Comments
// ==============================================================================================================
// 03/28/2004 EFW Created the code
//===============================================================================================================
using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using EWSoftware.PDI.Binding;
using EWSoftware.PDI.Properties;
namespace EWSoftware.PDI.Objects
{
/// <summary>
/// This class represents a VFREEBUSY component that can appear in a calendar
/// </summary>
[TypeDescriptionProvider(typeof(VFreeBusyTypeDescriptionProvider))]
public class VFreeBusy : CalendarObject
{
#region Private data members
//=====================================================================
// Single free/busy properties
private UrlProperty url;
private UniqueIdProperty uid;
private StartDateProperty startDate;
private EndDateProperty endDate;
private TimeStampProperty timeStamp;
private CommentProperty comment;
private OrganizerProperty organizer;
private DurationProperty duration;
private ContactProperty contact;
// Free/busy property collections. There can be one or more of each of these properties so they are
// stored in a collection.
private AttendeePropertyCollection attendees;
private RequestStatusPropertyCollection reqstats;
private FreeBusyPropertyCollection freebusy;
// This is a catch-all that holds all unknown or extension properties
private CustomPropertyCollection customProps;
#endregion
#region Properties
//=====================================================================
/// <summary>
/// This is used to establish the specification versions supported by the PDI object
/// </summary>
/// <value>Supports iCalendar 2.0 only</value>
public override SpecificationVersions VersionsSupported => SpecificationVersions.iCalendar20;
/// <summary>
/// This is used to get the Uniform Resource Locator (URL) property
/// </summary>
public UrlProperty Url
{
get
{
if(url == null)
url = new UrlProperty();
return url;
}
}
/// <summary>
/// This is used to get the Unique ID (UID) property
/// </summary>
/// <remarks>For the iCalendar 2.0 specification, this is a required property and will always by saved to
/// the data stream. A new ID will be created automatically if necessary.</remarks>
public UniqueIdProperty UniqueId
{
get
{
if(uid == null)
{
uid = new UniqueIdProperty();
uid.AssignNewId(true);
}
return uid;
}
}
/// <summary>
/// This is used to get the start date/time (DTSTART) property
/// </summary>
public StartDateProperty StartDateTime
{
get
{
if(startDate == null)
startDate = new StartDateProperty();
return startDate;
}
}
/// <summary>
/// This is used to get the end date/time (DTEND) property
/// </summary>
public EndDateProperty EndDateTime
{
get
{
if(endDate == null)
endDate = new EndDateProperty();
return endDate;
}
}
/// <summary>
/// This is used to get the time stamp (DTSTAMP) property
/// </summary>
/// <remarks>This will be updated whenever the object is written to a PDI data stream</remarks>
public TimeStampProperty TimeStamp
{
get
{
if(timeStamp == null)
timeStamp = new TimeStampProperty { DateTimeValue = DateTime.Now };
return timeStamp;
}
}
/// <summary>
/// This is used to get the comment (COMMENT) property
/// </summary>
/// <remarks>This property is only valid for the iCalendar 2.0 specification. It is ignored for
/// vCalendar 1.0 objects.</remarks>
public CommentProperty Comment
{
get
{
if(comment == null)
comment = new CommentProperty();
return comment;
}
}
/// <summary>
/// This is used to get the organizer (ORGANIZER) property
/// </summary>
/// <remarks>This property is only valid for the iCalendar 2.0 specification. It is ignored for
/// vCalendar 1.0 objects.</remarks>
public OrganizerProperty Organizer
{
get
{
if(organizer == null)
organizer = new OrganizerProperty();
return organizer;
}
}
/// <summary>
/// This is used to get the duration (DURATION) property
/// </summary>
public DurationProperty Duration
{
get
{
if(duration == null)
duration = new DurationProperty();
return duration;
}
}
/// <summary>
/// This is used to get the Contact (CONTACT) property
/// </summary>
public ContactProperty Contact
{
get
{
if(contact == null)
contact = new ContactProperty();
return contact;
}
}
/// <summary>
/// This is used to get the Attendee (ATTENDEE) properties. There may be more than one.
/// </summary>
/// <value>If the returned collection is empty, there are no attendee properties for the object</value>
public AttendeePropertyCollection Attendees
{
get
{
if(attendees == null)
attendees = new AttendeePropertyCollection();
return attendees;
}
}
/// <summary>
/// This is used to get the Request Status (REQUEST-STATUS) properties. There may be more than one.
/// </summary>
/// <value>If the returned collection is empty, there are no request status properties for the object</value>
public RequestStatusPropertyCollection RequestStatuses
{
get
{
if(reqstats == null)
reqstats = new RequestStatusPropertyCollection();
return reqstats;
}
}
/// <summary>
/// This is used to get the Free/Busy (FREEBUSY) properties. There may be more than one.
/// </summary>
/// <value>If the returned collection is empty, there are no free/busy properties for the object</value>
public FreeBusyPropertyCollection FreeBusy
{
get
{
if(freebusy == null)
freebusy = new FreeBusyPropertyCollection();
return freebusy;
}
}
/// <summary>
/// This is a catch-all that holds all unknown or extension properties
/// </summary>
/// <value>If the returned collection is empty, there are no custom properties for the calendar</value>
public CustomPropertyCollection CustomProperties
{
get
{
if(customProps == null)
customProps = new CustomPropertyCollection();
return customProps;
}
}
#endregion
#region Constructor
//=====================================================================
/// <summary>
/// Constructor
/// </summary>
public VFreeBusy()
{
this.Version = SpecificationVersions.iCalendar20;
}
#endregion
#region Methods
//=====================================================================
/// <summary>
/// This is overridden to allow cloning of a PDI object
/// </summary>
/// <returns>A clone of the object</returns>
public override object Clone()
{
VFreeBusy o = new VFreeBusy();
o.Clone(this);
return o;
}
/// <summary>
/// This is overridden to allow copying of the additional properties
/// </summary>
/// <param name="p">The PDI object from which the settings are to be copied</param>
protected override void Clone(PDIObject p)
{
VFreeBusy o = (VFreeBusy)p;
this.ClearProperties();
url = (UrlProperty)o.Url.Clone();
uid = (UniqueIdProperty)o.UniqueId.Clone();
startDate = (StartDateProperty)o.StartDateTime.Clone();
endDate = (EndDateProperty)o.EndDateTime.Clone();
timeStamp = (TimeStampProperty)o.TimeStamp.Clone();
comment = (CommentProperty)o.Comment.Clone();
organizer = (OrganizerProperty)o.Organizer.Clone();
duration = (DurationProperty)o.Duration.Clone();
contact = (ContactProperty)o.Contact.Clone();
this.Attendees.CloneRange(o.Attendees);
this.RequestStatuses.CloneRange(o.RequestStatuses);
this.FreeBusy.CloneRange(o.FreeBusy);
this.CustomProperties.CloneRange(o.CustomProperties);
}
/// <summary>
/// The method can be called to clear all current property values from the free/busy object. The version
/// is left unchanged.
/// </summary>
public override void ClearProperties()
{
url = null;
uid = null;
startDate = null;
endDate = null;
timeStamp = null;
comment = null;
organizer = null;
duration = null;
contact = null;
attendees = null;
reqstats = null;
freebusy = null;
customProps = null;
}
/// <summary>
/// This is used to propagate the version to all properties in the object that need it
/// </summary>
public override void PropagateVersion()
{
if(url != null)
url.Version = this.Version;
if(uid != null)
uid.Version = this.Version;
if(startDate != null)
startDate.Version = this.Version;
if(endDate != null)
endDate.Version = this.Version;
if(timeStamp != null)
timeStamp.Version = this.Version;
if(comment!= null)
comment.Version = this.Version;
if(organizer != null)
organizer.Version = this.Version;
if(duration != null)
duration.Version = this.Version;
if(contact != null)
contact.Version = this.Version;
if(attendees != null)
attendees.PropagateVersion(this.Version);
if(reqstats != null)
reqstats.PropagateVersion(this.Version);
if(freebusy != null)
freebusy.PropagateVersion(this.Version);
if(customProps != null)
customProps.PropagateVersion(this.Version);
}
/// <summary>
/// This is used to get a list of time zones used by all owned objects
/// </summary>
/// <param name="timeZoneIds">A <see cref="StringCollection"/> that will be used to store the list of
/// unique time zone IDs used by the calendar objects.</param>
public override void TimeZonesUsed(StringCollection timeZoneIds)
{
CalendarObject.AddTimeZoneIfUsed(startDate, timeZoneIds);
CalendarObject.AddTimeZoneIfUsed(endDate, timeZoneIds);
}
/// <summary>
/// This is used to replace an old time zone ID with a new time zone ID in all properties of a calendar
/// object.
/// </summary>
/// <param name="oldId">The old ID being replaced</param>
/// <param name="newId">The new ID to use</param>
public override void UpdateTimeZoneId(string oldId, string newId)
{
CalendarObject.UpdatePropertyTimeZoneId(startDate, oldId, newId);
CalendarObject.UpdatePropertyTimeZoneId(endDate, oldId, newId);
}
/// <summary>
/// This is used to apply the selected time zone to all date/time objects in the component and convert
/// them to the new time zone.
/// </summary>
/// <param name="vTimeZone">A <see cref="VTimeZone"/> object that will be used for all date/time objects
/// in the component.</param>
/// <remarks>When applied, all date/time values in the object will be converted to the new time zone</remarks>
public override void ApplyTimeZone(VTimeZone vTimeZone)
{
CalendarObject.ApplyPropertyTimeZone(startDate, vTimeZone);
CalendarObject.ApplyPropertyTimeZone(endDate, vTimeZone);
}
/// <summary>
/// This is used to set the selected time zone in all date/time objects in the component without
/// modifying the date/time values.
/// </summary>
/// <param name="vTimeZone">A <see cref="VTimeZone"/> object that will be used for all date/time objects
/// in the component.</param>
/// <remarks>This method does not affect the date/time values</remarks>
public override void SetTimeZone(VTimeZone vTimeZone)
{
CalendarObject.SetPropertyTimeZone(startDate, vTimeZone);
CalendarObject.SetPropertyTimeZone(endDate, vTimeZone);
}
/// <summary>
/// This can be used to write a free/busy object to a PDI data stream
/// </summary>
/// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the free/busy object is
/// written.</param>
/// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary
/// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param>
/// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they
/// convert themselves to a string or write themselves to a PDI data stream.</remarks>
public override void WriteToStream(TextWriter tw, StringBuilder sb)
{
// DTSTAMP is always updated and written to reflect when the object was saved to the stream
this.TimeStamp.DateTimeValue = DateTime.Now;
PropagateVersion();
tw.Write("BEGIN:VFREEBUSY\r\n");
// This is a required property for iCalendar 2.0.
BaseProperty.WriteToStream(this.UniqueId, sb, tw);
BaseProperty.WriteToStream(organizer, sb, tw);
if(attendees != null && attendees.Count != 0)
foreach(AttendeeProperty a in attendees)
BaseProperty.WriteToStream(a, sb, tw);
BaseProperty.WriteToStream(contact, sb, tw);
BaseProperty.WriteToStream(startDate, sb, tw);
BaseProperty.WriteToStream(endDate, sb, tw);
BaseProperty.WriteToStream(duration, sb, tw);
BaseProperty.WriteToStream(comment, sb, tw);
BaseProperty.WriteToStream(url, sb, tw);
BaseProperty.WriteToStream(timeStamp, sb, tw);
if(reqstats != null && reqstats.Count != 0)
foreach(RequestStatusProperty r in reqstats)
BaseProperty.WriteToStream(r, sb, tw);
if(freebusy != null && freebusy.Count != 0)
{
// If there are any, they are sorted in ascending order first
freebusy.Sort(true);
foreach(FreeBusyProperty fb in freebusy)
BaseProperty.WriteToStream(fb, sb, tw);
}
if(customProps != null && customProps.Count != 0)
foreach(CustomProperty c in customProps)
BaseProperty.WriteToStream(c, sb, tw);
tw.Write("END:VFREEBUSY\r\n");
}
/// <summary>
/// This is overridden to allow proper comparison of free/busy objects
/// </summary>
/// <param name="obj">The object to which this instance is compared</param>
/// <returns>Returns true if the object equals this instance, false if it does not</returns>
public override bool Equals(object obj)
{
if(!(obj is VFreeBusy fb))
return false;
// The ToString() method returns a text representation of the object based on all of its settings so
// it's a reliable way to tell if two instances are the same.
return (this == fb || this.ToString() == fb.ToString());
}
/// <summary>
/// Get a hash code for the calendar object
/// </summary>
/// <returns>Returns the hash code for the calendar object</returns>
/// <remarks>Since the ToString() method returns a text representation based on all of the settings, this
/// returns the hash code for the string returned by it.</remarks>
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
#endregion
}
}