using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics.Contracts; namespace NavScm.NavInterface { /// /// Adds a mapping between the NAV SQL Type field an enum to make its handling easier. /// public enum NavObjectType { TableData = 0, Table = 1, Report = 3, Codeunit = 5, XmlPort = 6, MenuSuite = 7, Page = 8, Query = 9 } /// /// /// This class wraps the actual NAV Object table data retrieved from the target database. /// It adds additional helper functions to manage the cache accociated with it. /// /// /// Note, that equality is defined by the DB primary key, which in turn includes /// Type and ID. See CacheKey /// for details. This sequence is also used for ordering of the object in case of /// a sorted output. /// /// /// Note, that object entries with a Company Name set are rejected at this point. They /// result (probably) from a multi-tenancy/extension setup, which we do not support at /// this time. As well, objects with unknown object types are rejected. /// /// /// /// partial class NavObject : IEquatable, IComparable, IComparable { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(NavObject)); /// /// Validate restrictions on supported objects as outlined in the class description. /// partial void OnLoaded() { Contract.Requires(Company_Name.Length == 0); Contract.Requires(Type >= 0 && Type <= 9 && Type != 2 && Type != 4 ); /* if (Company_Name.Length > 0) throw new InvalidOperationException($"The object {CacheKey} holds a variant with the company name {Company_Name}, which is unsupported"); if (Type < 0 || Type == 2 || Type == 4 || Type > 9) throw new InvalidOperationException($"The object type of {CacheKey} is unsupported"); */ } /// /// Casts the SQL type to the corresponding Enum. /// public NavObjectType NavType { get { return (NavObjectType)Type; } } /// /// /// Constructs an object cache key to uniquely identify the object out of its type and ID. /// Uses the string representation to make debugging easier. The equality operator maps to /// this key as well. /// /// /// Note, that the company Name is ignored here, as we do not support this scenario at this /// time and throw an error just in case. /// /// public string CacheKey { get { return $"{Type}.{ID}"; } } /// /// Converts the Date and Time fields to a combined Date/Time value. /// public DateTime ModifiedDate { get { return Date.Add(Time.TimeOfDay); } } /// /// Constructs a hash key based on Type and ID. /// /// Take 4 Bits of object Type and 28 bits of the actual object ID and shuffle them around /// to create the hash key. public override int GetHashCode() { return // lower 8 bits of ID first (ID << 24) // second byte of ID goes next & ((ID << 8) ^ 0x00ff0000) // third byte of ID goes next & ((ID >> 8) ^ 0x0000ff00) // lower 4 bits of fourth ID byte go next & ((ID >> 20) ^ 0x000000f0) // finally add the first four bits of the Type & (Type ^ 0x0000000f) ; } public override bool Equals(object obj) { if (!(obj is NavObject)) return false; return Equals((NavObject) obj); } public bool Equals(NavObject other) { return Type == other.Type && ID == other.ID; } public int CompareTo(NavObject other) { if (Type < other.Type) return -1; if (Type > other.Type) return +1; if (ID < other.ID) return -1; if (ID > other.ID) return +1; return 0; } public int CompareTo(object obj) { if (!(obj is NavObject)) throw new InvalidOperationException("obj is not an NavObject"); return this.CompareTo((NavObject)obj); } } }