using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; namespace InABox.Database; public class VersionNumber : IComparable { public int MajorVersion { get; } public int MinorVersion { get; } public string Release { get; } public bool IsDevelopmentVersion { get; } public bool IsNewStyle { get; private set; } public VersionNumber() { IsDevelopmentVersion = true; MajorVersion = 0; MinorVersion = 0; Release = "0"; IsNewStyle = true; } public VersionNumber(int majorVersion, int minorVersion) { IsDevelopmentVersion = false; MajorVersion = majorVersion; MinorVersion = minorVersion; Release = "0"; IsNewStyle = true; } public VersionNumber(int majorVersion, int minorVersion, int release) { IsDevelopmentVersion = false; MajorVersion = majorVersion; MinorVersion = minorVersion; Release = release.ToString(); IsNewStyle = true; } public VersionNumber(int majorVersion, int minorVersion, string release) { IsDevelopmentVersion = false; MajorVersion = majorVersion; MinorVersion = minorVersion; Release = release; IsNewStyle = false; } private static readonly Regex _format = new Regex( @"^(?\d+)\.(?\d+)(?:(?[A-Za-z]+)|\.(?\d+))?$", RegexOptions.Compiled); public static VersionNumber Parse(string versionStr) { if (!TryParse(versionStr, out var _result)) throw new FormatException($"'{versionStr}' is not a valid version!"); return _result; } public static bool TryParse(string versionStr, [NotNullWhen(true)] out VersionNumber? version) { if (versionStr == "???") { version = new(); return true; } var match = _format.Match(versionStr); if (!match.Success) { version = null; return false; } if (match.Groups["oldstyle"].Success) { version = new(int.Parse(match.Groups["major"].Value), int.Parse(match.Groups["minor"].Value), match.Groups["release"].Value ); } else if (match.Groups["newstyle"].Success) { version = new(int.Parse(match.Groups["major"].Value), int.Parse(match.Groups["minor"].Value), int.Parse(match.Groups["newstyle"].Value) ); } else { version = new(int.Parse(match.Groups["major"].Value), int.Parse(match.Groups["minor"].Value), 0 ); } return true; } public int CompareTo(object? obj) { if (obj is not VersionNumber other) throw new ArgumentException($"Object must be of type {nameof(VersionNumber)}"); var _result = this < other ? -1 : this == other ? 0 : 1; return _result; } public static bool operator <(VersionNumber a, VersionNumber b) { if (a.IsDevelopmentVersion) return false; if (b.IsDevelopmentVersion) return true; if (a.MajorVersion != b.MajorVersion) return a.MajorVersion < b.MajorVersion; if (a.MinorVersion != b.MinorVersion) return a.MinorVersion < b.MinorVersion; if (a.IsNewStyle && b.IsNewStyle) return int.Parse(a.Release) < int.Parse(b.Release); return String.Compare(a.Release,b.Release, StringComparison.OrdinalIgnoreCase) < 0; } public static bool operator >(VersionNumber a, VersionNumber b) { return b < a; } public static bool operator <=(VersionNumber a, VersionNumber b) { return !(b < a); } public static bool operator >=(VersionNumber a, VersionNumber b) { return !(a < b); } public override bool Equals(object? obj) { if(obj is VersionNumber v) { return this == v; } return false; } public override int GetHashCode() { if (IsDevelopmentVersion) return 0; return MajorVersion ^ MinorVersion ^ Release.GetHashCode(); } public static bool operator ==(VersionNumber a, VersionNumber b) { if (a.IsDevelopmentVersion) return b.IsDevelopmentVersion; if (b.IsDevelopmentVersion) return false; return a.MajorVersion == b.MajorVersion && a.MinorVersion == b.MinorVersion && String.Compare(a.Release,b.Release, StringComparison.OrdinalIgnoreCase) == 0; } public static bool operator !=(VersionNumber a, VersionNumber b) { if (a.IsDevelopmentVersion) return !b.IsDevelopmentVersion; if (b.IsDevelopmentVersion) return true; return a.MajorVersion != b.MajorVersion || a.MinorVersion != b.MinorVersion || String.Compare(a.Release, b.Release, StringComparison.OrdinalIgnoreCase) != 0; } public override string ToString() { return IsDevelopmentVersion ? "???" : IsNewStyle ? !Release.Equals("0") ? $"{MajorVersion}.{MinorVersion:D2}.{Release}" : $"{MajorVersion}.{MinorVersion:D2}" : $"{MajorVersion}.{MinorVersion:D2}{Release}"; } }