Skip to content

Commit

Permalink
add - doc - Added support for IANA and X- componen...
Browse files Browse the repository at this point in the history
...ts

---

We've added support for IANA and X- components for the calendar.

---

Type: add
Breaking: False
Doc Required: True
Backport Required: False
Part: 1/1
  • Loading branch information
AptiviCEO committed Oct 2, 2024
1 parent a339536 commit 8da8f68
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 5 deletions.
8 changes: 7 additions & 1 deletion VisualCard.Calendar/Parsers/VCalendarParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,10 @@ private Parts.Calendar GetCalendarInheritedInstance(string type)
VCalendarConstants._objectVStandardSpecifier => new CalendarStandard(CalendarVersion),
VCalendarConstants._objectVDaylightSpecifier => new CalendarDaylight(CalendarVersion),
VCalendarConstants._objectVAlarmSpecifier => new CalendarAlarm(CalendarVersion),
_ => throw new ArgumentException($"Invalid type {type}"),
_ =>
CalendarVersion.Major == 2 ?
new CalendarOtherComponent(CalendarVersion, type) :
throw new ArgumentException($"Invalid type {type}"),
};
}

Expand Down Expand Up @@ -453,6 +456,9 @@ private void SaveLastSubPart(Parts.Calendar? subpart, ref Parts.Calendar part)
case nameof(CalendarTimeZone):
part.timeZones.Add((CalendarTimeZone)subpart);
break;
case nameof(CalendarOtherComponent):
part.others.Add((CalendarOtherComponent)subpart);
break;
default:
nestable = false;
break;
Expand Down
5 changes: 3 additions & 2 deletions VisualCard.Calendar/Parsers/VCalendarParserTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,9 @@ internal static (PartType type, object enumeration, Type? enumType, Func<string,

internal static string GetObjectTypeFromComponent<TComponent>(TComponent component)
where TComponent : Parts.Calendar =>
GetObjectTypeFromType(component.GetType());
GetObjectTypeFromType(component.GetType(), component is CalendarOtherComponent other ? other.ComponentName : "");

internal static string GetObjectTypeFromType(Type type) =>
internal static string GetObjectTypeFromType(Type type, string specifier = "") =>
type.Name switch
{
nameof(Parts.Calendar) => VCalendarConstants._objectVCalendarSpecifier,
Expand All @@ -340,6 +340,7 @@ internal static string GetObjectTypeFromType(Type type) =>
nameof(CalendarStandard) => VCalendarConstants._objectVStandardSpecifier,
nameof(CalendarDaylight) => VCalendarConstants._objectVDaylightSpecifier,
nameof(CalendarAlarm) => VCalendarConstants._objectVAlarmSpecifier,
nameof(CalendarOtherComponent) => specifier,
_ => throw new InvalidDataException("Type is not a valid component"),
};

Expand Down
15 changes: 13 additions & 2 deletions VisualCard.Calendar/Parts/Calendar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class Calendar : IEquatable<Calendar>
internal readonly List<CalendarJournal> journals = [];
internal readonly List<CalendarFreeBusy> freeBusyList = [];
internal readonly List<CalendarTimeZone> timeZones = [];
internal readonly List<CalendarOtherComponent> others = [];
private readonly Version version;
private readonly Dictionary<CalendarPartsArrayEnum, List<BaseCalendarPartInfo>> partsArray = [];
private readonly Dictionary<CalendarStringsEnum, string> strings = [];
Expand Down Expand Up @@ -90,6 +91,12 @@ public class Calendar : IEquatable<Calendar>
public CalendarTimeZone[] TimeZones =>
[.. timeZones];

/// <summary>
/// Other component list
/// </summary>
public CalendarOtherComponent[] Others =>
[.. others];

/// <summary>
/// Gets a part array from a specified key
/// </summary>
Expand Down Expand Up @@ -336,6 +343,8 @@ internal string SaveToString(Version version, Dictionary<CalendarPartsArrayEnum,
cardBuilder.Append(calendarFreeBusy.SaveToString(version, calendarFreeBusy.partsArray, calendarFreeBusy.strings, calendarFreeBusy.integers, VCalendarConstants._objectVFreeBusySpecifier));
foreach (var calendarTimeZone in timeZones)
cardBuilder.Append(calendarTimeZone.SaveToString(version, calendarTimeZone.partsArray, calendarTimeZone.strings, calendarTimeZone.integers, VCalendarConstants._objectVTimeZoneSpecifier));
foreach (var calendarOther in others)
cardBuilder.Append(calendarOther.SaveToString(version, calendarOther.partsArray, calendarOther.strings, calendarOther.integers, calendarOther.ComponentName));
}
else if (objectType == VCalendarConstants._objectVEventSpecifier)
{
Expand Down Expand Up @@ -410,19 +419,21 @@ public bool Equals(Calendar source, Calendar target)
PartComparison.CompareCalendarComponents(source.todos, target.todos) &&
PartComparison.CompareCalendarComponents(source.journals, target.journals) &&
PartComparison.CompareCalendarComponents(source.freeBusyList, target.freeBusyList) &&
PartComparison.CompareCalendarComponents(source.timeZones, target.timeZones)
PartComparison.CompareCalendarComponents(source.timeZones, target.timeZones) &&
PartComparison.CompareCalendarComponents(source.others, target.others)
;
}

/// <inheritdoc/>
public override int GetHashCode()
{
int hashCode = -1266621595;
int hashCode = 797403623;
hashCode = hashCode * -1521134295 + EqualityComparer<List<CalendarEvent>>.Default.GetHashCode(events);
hashCode = hashCode * -1521134295 + EqualityComparer<List<CalendarTodo>>.Default.GetHashCode(todos);
hashCode = hashCode * -1521134295 + EqualityComparer<List<CalendarJournal>>.Default.GetHashCode(journals);
hashCode = hashCode * -1521134295 + EqualityComparer<List<CalendarFreeBusy>>.Default.GetHashCode(freeBusyList);
hashCode = hashCode * -1521134295 + EqualityComparer<List<CalendarTimeZone>>.Default.GetHashCode(timeZones);
hashCode = hashCode * -1521134295 + EqualityComparer<List<CalendarOtherComponent>>.Default.GetHashCode(others);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<CalendarPartsArrayEnum, List<BaseCalendarPartInfo>>>.Default.GetHashCode(partsArray);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<CalendarStringsEnum, string>>.Default.GetHashCode(strings);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<CalendarIntegersEnum, double>>.Default.GetHashCode(integers);
Expand Down
154 changes: 154 additions & 0 deletions VisualCard.Calendar/Parts/CalendarOtherComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//
// VisualCard Copyright (C) 2021-2024 Aptivi
//
// This file is part of VisualCard
//
// VisualCard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// VisualCard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY, without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

using System;
using System.Collections.Generic;
using System.Diagnostics;
using VisualCard.Calendar.Parsers;
using VisualCard.Calendar.Parts.Comparers;
using VisualCard.Calendar.Parts.Enums;

namespace VisualCard.Calendar.Parts
{
/// <summary>
/// A vCalendar card instance
/// </summary>
[DebuggerDisplay("vCalendar other component version {CalendarVersion.ToString()}, parts: (A [{partsArray.Count}] | S [{strings.Count}] | I [{integers.Count}])")]
public class CalendarOtherComponent : Calendar, IEquatable<CalendarOtherComponent>
{
internal readonly string componentName = "";
private readonly Dictionary<CalendarPartsArrayEnum, List<BaseCalendarPartInfo>> partsArray = [];
private readonly Dictionary<CalendarStringsEnum, string> strings = [];
private readonly Dictionary<CalendarIntegersEnum, double> integers = [];

/// <summary>
/// Component name
/// </summary>
public string ComponentName =>
componentName;

/// <summary>
/// Gets a part array from a specified key
/// </summary>
/// <returns>An array of values or an empty part array []</returns>
public new TPart[] GetPartsArray<TPart>() where TPart : BaseCalendarPartInfo
{
// Get the parts enumeration according to the type
var key = VCalendarParserTools.GetPartsArrayEnumFromType(typeof(TPart), CalendarVersion);

// Now, return the value
return GetPartsArray<TPart>(key.Item1, CalendarVersion, partsArray);
}

/// <summary>
/// Gets a part array from a specified key
/// </summary>
/// <param name="key">A key to use</param>
/// <returns>An array of values or an empty part array []</returns>
public new TPart[] GetPartsArray<TPart>(CalendarPartsArrayEnum key) where TPart : BaseCalendarPartInfo =>
GetPartsArray<TPart>(key, CalendarVersion, partsArray);

/// <summary>
/// Gets a string from a specified key
/// </summary>
/// <param name="key">A key to use</param>
/// <returns>A value, or "individual" if the kind doesn't exist, or an empty string ("") if any other type either doesn't exist or the type is not supported by the card version</returns>
public new string GetString(CalendarStringsEnum key) =>
GetString(key, CalendarVersion, strings);

/// <summary>
/// Saves this parsed card to the string
/// </summary>
public new string SaveToString() =>
SaveToString(CalendarVersion, partsArray, strings, integers, componentName);

/// <summary>
/// Saves the contact to the returned string
/// </summary>
public override string ToString() =>
SaveToString();

/// <inheritdoc/>
public override bool Equals(object obj) =>
Equals((CalendarOtherComponent)obj);

/// <summary>
/// Checks to see if both the cards are equal
/// </summary>
/// <param name="other">The target <see cref="Calendar"/> instance to check to see if they equal</param>
/// <returns>True if all the card elements are equal. Otherwise, false.</returns>
public bool Equals(CalendarOtherComponent other) =>
Equals(this, other);

/// <summary>
/// Checks to see if both the cards are equal
/// </summary>
/// <param name="source">The source <see cref="Calendar"/> instance to check to see if they equal</param>
/// <param name="target">The target <see cref="Calendar"/> instance to check to see if they equal</param>
/// <returns>True if all the card elements are equal. Otherwise, false.</returns>
public bool Equals(CalendarOtherComponent source, CalendarOtherComponent target)
{
// We can't perform this operation on null.
if (source is null || target is null)
return false;

// Check all the properties
return
PartComparison.PartsArrayEnumEqual(source.partsArray, target.partsArray) &&
PartComparison.StringsEqual(source.strings, target.strings) &&
PartComparison.IntegersEqual(source.integers, target.integers)
;
}

/// <inheritdoc/>
public override int GetHashCode()
{
int hashCode = 2054266066;
hashCode = hashCode * -1521134295 + base.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(componentName);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<CalendarPartsArrayEnum, List<BaseCalendarPartInfo>>>.Default.GetHashCode(partsArray);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<CalendarStringsEnum, string>>.Default.GetHashCode(strings);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<CalendarIntegersEnum, double>>.Default.GetHashCode(integers);
return hashCode;
}

/// <inheritdoc/>
public static bool operator ==(CalendarOtherComponent a, CalendarOtherComponent b)
=> a.Equals(b);

/// <inheritdoc/>
public static bool operator !=(CalendarOtherComponent a, CalendarOtherComponent b)
=> !a.Equals(b);

internal new void AddPartToArray(CalendarPartsArrayEnum key, BaseCalendarPartInfo value) =>
AddPartToArray(key, value, CalendarVersion, partsArray, componentName);

internal new void SetString(CalendarStringsEnum key, string value) =>
SetString(key, value, strings);

internal new void SetInteger(CalendarIntegersEnum key, double value) =>
SetInteger(key, value, integers);

internal CalendarOtherComponent(Version version, string componentName) :
base(version)
{
this.componentName = componentName.ToUpper();
}
}
}
4 changes: 4 additions & 0 deletions VisualCard.ShowCalendars/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
"commandName": "Project",
"commandLineArgs": "TestFiles/vcalendarEventTz.ics"
},
"vCalendar 2.0 test - event with other component": {
"commandName": "Project",
"commandLineArgs": "TestFiles/veventothercomp.vcs"
},
"vCalendar 1.0 test": {
"commandName": "Project",
"commandLineArgs": "TestFiles/vevent1.vcs"
Expand Down
27 changes: 27 additions & 0 deletions VisualCard.ShowCalendars/TestFiles/veventothercomp.vcs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
BEGIN:VCALENDAR
PRODID:-//xyz Corp//NONSGML PDA Calendar Version 1.0//EN
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
DTSTAMP:1996-07-04T12:00:00
UID:[email protected]
ORGANIZER:mailto:[email protected]
DTSTART:1996-09-18T14:30:00
DTEND:1996-09-20T22:00:00
STATUS:CONFIRMED
CATEGORIES:CONFERENCE
SUMMARY:Networld+Interop Conference
DESCRIPTION:Networld+Interop Conference
and Exhibit\nAtlanta World Congress Center\n
Atlanta\, Georgia
POPULAR:True
X-TRENDING:True
GEO:37.24;-17.87
REQUEST-STATUS:4.1;Event conflict. Date-time is busy.
REQUEST-STATUS:3.7;Invalid calendar user;ORGANIZER:
mailto:[email protected]
END:VEVENT
BEGIN:X-COMPONENT
X-NAME:Event
END:X-COMPONENT
END:VCALENDAR

0 comments on commit 8da8f68

Please sign in to comment.