using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Utils; using System; using System.Collections.Generic; using System.Linq; namespace Sarand.Net.Standard.Base.Bus { //======================================================================= public class UpdateStamp { private DateTime on = DateTime.Now; private SysId by = new SysId(); private String host = String.Empty; public DateTime On { get { return on; } set { on = value; } } public SysId By { get { return by; } set { by = SysId.InvalidOnNull(value); } } public String Host { get { return host; } set { host = StringUtil.EmptyOnNull(value); } } } //======================================================================= public class SacsHierarchyItem : SacsStateItem { //------------------------------------------------------------------- // Definitions. public class Data { //--------------------------------------------------------------- // Common properties. private SysId id = new SysId(); private String notes = String.Empty; /// Item identifier. public SysId Id { get { return SysId.InvalidOnNull(id); } set { CheckChanged(id, value); id = SysId.InvalidOnNull(value); } } /// Item notes. public String Notes { get { return StringUtil.EmptyOnNull(notes); } set { CheckChanged(notes, value); notes = StringUtil.EmptyOnNull(value); } } //--------------------------------------------------------------- // Flags. private UInt16 flags = 0; /// Item flags.Up to 16 flags supported. public UInt16 Flags { get { return flags; } set { CheckChanged(flags, value); flags = value; } } /// Get flag value - position 1 - 16 public bool GetFlag(Byte flagPos) { return SacsHierarchyItem.GetFlag(Flags, flagPos); } /// Set flag value - position 1 - 16 public void SetFlag(Byte flagPos, bool value) { CheckChanged(GetFlag(flagPos), value); Flags = SacsHierarchyItem.SetFlag(Flags, flagPos, value); } //--------------------------------------------------------------- // Status. private SaStatus status = SaStatus.Unknown; /// Item status. public SaStatus Status { get { return status; } set { CheckChangedEnum(status, value); status = value; } } public String StatusCode { get { return SacsSystem.GetStatusCode(Status); } set { Status = SacsSystem.GetStatusForCode(value); } } public String StatusDesc { get { return SacsSystem.GetStatusDesc(Status); } } public bool IsStatusAwaiting { get { return Status == SaStatus.Awaiting; } } public bool IsStatusCurrent { get { return Status == SaStatus.Current; } } public bool IsStatusActive { get { return Status == SaStatus.Active; } } public bool IsStatusEnabled { get { return Status == SaStatus.Enabled; } } public bool IsStatusCompleted { get { return Status == SaStatus.Completed; } } public bool IsStatusCancelled { get { return Status == SaStatus.Cancelled; } } public bool IsStatusDeleted { get { return Status == SaStatus.Deleted; } } //--------------------------------------------------------------- // Update stamps. public UpdateStamp CreateStamp { get; protected set; } = new UpdateStamp(); public UpdateStamp UpdateStamp { get; protected set; } = new UpdateStamp(); //--------------------------------------------------------------- // Population. /// Copy common properties to this object. protected void PopulateFrom(Data sourceData) { Id = sourceData.Id; Notes = sourceData.Notes; Status = sourceData.Status; Flags = sourceData.Flags; CreateStamp = sourceData.CreateStamp; UpdateStamp = sourceData.UpdateStamp; } /// Copy comon properties to the target object. internal void PopulateTo(Data targetData) { targetData.PopulateFrom(this); } //--------------------------------------------------------------- // Property change tracking. private bool changed = false; /// Flag to indicate whether any property has been modified. public bool Changed { get { return changed; } set { if (changed == value) return; changed = value; } } /// Clear 'Changed' flag. public void AcceptChanges() { Changed = false; } //--------------------------------------------------------------- // Compare old and new property values and set 'Changed' if different. protected void CheckChanged(SysId oldValue, SysId newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) // Compare by numeric value so that invalid values are equal. Changed = SysId.ToInt(oldValue) != SysId.ToInt(newValue); } protected void CheckChanged(ItemId oldValue, ItemId newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = (oldValue.Type != newValue.Type) || (!oldValue.Id.Equals(newValue.Id)); } protected void CheckChanged(String oldValue, String newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = !StringUtil.EmptyOnNull(oldValue).Equals(StringUtil.EmptyOnNull(newValue)); } protected void CheckChanged(bool oldValue, bool newValue) { CheckChangedNullable(oldValue, newValue); } protected void CheckChangedNullable(bool? oldValue, bool? newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = (oldValue != newValue); } protected void CheckChangedEnum(T oldValue, T newValue) where T : struct, IConvertible { CheckChangedEnumNullable(oldValue, newValue); } protected void CheckChangedEnumNullable(T? oldValue, T? newValue) where T : struct, IConvertible { if (!(oldValue != null && oldValue is Enum) || !(newValue != null && newValue is Enum)) throw new ArgumentException($"{SysUtil.Fn} Parameters must be enumerated types. Type supplied: {oldValue.GetType().Name}, {newValue.GetType().Name}."); if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = ((int)(oldValue as IConvertible) != (int)(newValue as IConvertible)); } protected void CheckChanged(long oldValue, long newValue) { CheckChangedNullable(oldValue, newValue); } protected void CheckChangedNullable(long? oldValue, long? newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = (oldValue != newValue); } protected void CheckChanged(double oldValue, double newValue) { CheckChangedNullable(oldValue, newValue); } protected void CheckChangedNullable(double? oldValue, double? newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = (oldValue != newValue); } protected void CheckChanged(decimal oldValue, decimal newValue) { CheckChangedNullable(oldValue, newValue); } protected void CheckChangedNullable(decimal? oldValue, decimal? newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = (oldValue != newValue); } protected void CheckChanged(DateTime oldValue, DateTime newValue) { CheckChangedNullable(oldValue, newValue); } protected void CheckChangedNullable(DateTime? oldValue, DateTime? newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = !oldValue.Equals(newValue); } protected void CheckChanged(IEnumerable oldValues, IEnumerable newValues) { if (Changed) return; Changed = !oldValues.ContentEquals(newValues); } protected void CheckChanged(IEnumerable oldValues, IEnumerable newValues) { if (Changed) return; if (oldValues.Count() != newValues.Count()) Changed = true; else { var combinedValues = oldValues.Zip(newValues, Tuple.Create); foreach (var combinedValue in combinedValues) { if (!combinedValue.Item1.Equals(combinedValue.Item2)) { Changed = true; return; } } } } protected void CheckChanged(Guid oldValue, Guid newValue) { CheckChangedNullable(oldValue, newValue); } protected void CheckChangedNullable(Guid? oldValue, Guid? newValue) { if (Changed) return; if ((oldValue == null) != (newValue == null)) Changed = true; else if (oldValue != null && newValue != null) Changed = !oldValue.Equals(newValue); } protected void CheckChanged(byte[] oldValue, byte[] newValue) { if (Changed) return; if ((oldValue == null) != (newValue != null)) Changed = true; else if (oldValue.Length != newValue.Length) Changed = true; if (oldValue != null && newValue != null) Changed = !oldValue.SequenceEqual(newValue); } //--------------------------------------------------------------- } //------------------------------------------------------------------- // Property validation. public enum ValidValue { /// Property is valid (or has not been validate). Valid, /// Property is invalid. Invalid, /// Property is to be ignored during validation. Ignore, } public class ErrField { // Identifies the field that has invalid data. public ValidValue Id { get; set; } = ValidValue.Valid; public ValidValue Notes { get; set; } = ValidValue.Valid; public ValidValue Status { get; set; } = ValidValue.Valid; public ValidValue Flags { get; set; } = ValidValue.Valid; } //------------------------------------------------------------------- // Data members. // Data object holds object business properties. // Starts as internal class, replaced on construction by object specific class. private Data data = new Data(); //------------------------------------------------------------------- // Construction. protected SacsHierarchyItem() { } protected SacsHierarchyItem(SysId id) { data.Id = id; } //------------------------------------------------------------------- // Properties. /// By default, all hierarchy itrems have an Id.
Override and return false where this is not the case.
public virtual bool ItemHasId() { return true; } public SysId Id { get { if (!ItemHasId()) throw new NotSupportedException($"{SysUtil.Fn}.get - Item has no Id property."); return data.Id; } set { if (!ItemHasId() && SysId.IsValid(data.Id)) throw new NotSupportedException($"{SysUtil.Fn}.set - Item has no Id property."); if (SysId.IsValid(data.Id) && (!SysId.IsValid(value) || !data.Id.Equals(value))) throw new NotSupportedException($"{SysUtil.Fn}.set - Id already has a valid value."); data.Id = value; } } public String Notes { get { return StringUtil.EmptyOnNull(data.Notes); } set { data.Notes = value; } } //------------------------------------------------------------------- // Status. public SaStatus Status { get { return data.Status; } set { data.Status = value; } } public String StatusCode { get { return data.StatusCode; } set { data.StatusCode = value; } } public String StatusDesc { get { return data.StatusDesc; } } public bool IsStatusAwaiting { get { return data.IsStatusAwaiting; } } public bool IsStatusCurrent { get { return data.IsStatusCurrent; } } public bool IsStatusActive { get { return data.IsStatusActive; } } public bool IsStatusEnabled { get { return data.IsStatusEnabled; } } public bool IsStatusCompleted { get { return data.IsStatusCompleted; } } public bool IsStatusCancelled { get { return data.IsStatusCancelled; } } public bool IsStatusDeleted { get { return data.IsStatusDeleted; } } //------------------------------------------------------------------- // Flags. public UInt16 Flags { get { return data.Flags; } protected set { data.Flags = value; } } /// Flags are positioned from 1, up to 16 allowed. public static bool GetFlag(UInt16 flags, Byte flagPos) { bool flag = false; if (flagPos > 0 && flagPos <= 16) flag = (((flags >> (flagPos - 1)) & 0x0001) == 1 ? true : false); return flag; } /// Flags are positioned from 1, up to 16 allowed. public bool GetFlag(Byte flagPos) { return GetFlag(data.Flags, flagPos); } /// Set flag value - position 1 - 16 public static UInt16 SetFlag(UInt16 flags, Byte flagPos, bool value) { if (flagPos > 0 && flagPos <= 16) { UInt16 mask = (UInt16)(1 << (flagPos - 1)); if (value) flags |= mask; else flags &= (UInt16)(~mask); } return flags; } /// Set flag value - position 1 - 16 public void SetFlag(Byte flagPos, bool value) { data.Flags = SetFlag(data.Flags, flagPos, value); } //------------------------------------------------------------------- // Update stamps. public UpdateStamp CreateStamp { get { return data.CreateStamp; } } public void SetCreateStamp(DateTime? on, SysId by, String host) { CreateStamp.On = on ?? default(DateTime); CreateStamp.By = by; CreateStamp.Host = host; } public UpdateStamp UpdateStamp { get { return data.UpdateStamp; } } public void SetUpdateStamp(DateTime? on, SysId by, String host) { UpdateStamp.On = on ?? default(DateTime); UpdateStamp.By = by; UpdateStamp.Host = host; } //------------------------------------------------------------------- // Populate data item - only once on construction. protected void SetData(Data data) { // Can only be replaced if currently internal class. if (this.data.GetType() != typeof(Data)) throw new NotSupportedException($"{SysUtil.Fn} Data object has already been specified"); // If Id has already been specified (on construction) and supplied Id is not valid, set it to the existing value. if (ItemHasId() && SysId.IsValid(Id) && !SysId.IsValid(data.Id)) data.Id = Id; // Properties that cannot be changed if previously specified. if (ItemHasId() && SysId.IsValid(Id) && SysId.ToInt(Id) != SysId.ToInt(data.Id)) throw new NotSupportedException($"{SysUtil.Fn} Id cannot be changed"); this.data.PopulateTo(data); this.data = data; } //------------------------------------------------------------------- // Property change tracking. /// Flag to indicate whether any property has been modified. public bool Changed { get { return data.Changed; } set { if (data.Changed == value) return; data.Changed = value; } } /// Clear the 'Changed' flag to indicate that no changes have been made. public void AcceptChanges() { Changed = false; } //------------------------------------------------------------------- // Format value for display. public static String FormatForDisplay(String value, int maxLength = 0) { if (StringUtil.IsEmpty(value)) return String.Empty; // Replace non-display characters. value = value.Replace("\t", " ").Replace("\r", " ").Replace("\n", " "); // Remove leading, trailing and multiple internal spaces. value = value.Trim().Replace(" +", " "); // Restrict to maximum length. if (maxLength > 0 && value.Length > maxLength) { value = value.Left(maxLength); if (maxLength > 20) value += "..."; } return value; } //------------------------------------------------------------------- // Parameters. public class Params { // Construction. protected Params() { } public enum FlagState { Either = 0, True, False } public enum BoolState { Either = 0, True, False } /// Primary table alias to use if different from default. public String TableAlias { get; set; } /// Flag to indicate whether default filter ('1=1') is included if no other filter. public bool IncludeDefaultFilter { get; set; } = true; /// Results list paging. public DbQuery.Paging ResultsPaging { get; } = new DbQuery.Paging(); /// Sort columns. public List SortColumns { get; } = new List(); /// /// Flag to return data in random order. /// - NB Depends on implementation for each manager and item. /// public bool RandomOrder { get; set; } = false; } //------------------------------------------------------------------- } //======================================================================= }