Files
Common-VS2019/SacsStandardBase/Base/Bus/SacsHierarchyItem.cs
T
2024-08-27 19:49:17 +01:00

519 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Utils;
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 : SaErrorStateItem
{
//-------------------------------------------------------------------
// Definitions.
public class Data
{
//---------------------------------------------------------------
// Common properties.
private SysId id = new SysId();
private String notes = String.Empty;
/// <summary>Item identifier.</summary>
public SysId Id
{
get { return SysId.InvalidOnNull(id); }
set
{
CheckChanged(id, value);
id = SysId.InvalidOnNull(value);
}
}
/// <summary>Item notes.</summary>
public String Notes
{
get { return StringUtil.EmptyOnNull(notes); }
set
{
CheckChanged(notes, value);
notes = StringUtil.EmptyOnNull(value);
}
}
//---------------------------------------------------------------
// Flags.
private UInt16 flags = 0;
/// <summary>Item flags.<para>Up to 16 flags supported.</para></summary>
public UInt16 Flags
{
get { return flags; }
set
{
CheckChanged(flags, value);
flags = value;
}
}
/// <summary>Get flag value - position 1 - 16</summary>
public bool GetFlag(Byte flagPos)
{
return SacsHierarchyItem.GetFlag(Flags, flagPos);
}
/// <summary>Set flag value - position 1 - 16</summary>
public void SetFlag(Byte flagPos, bool value)
{
CheckChanged(GetFlag(flagPos), value);
Flags = SacsHierarchyItem.SetFlag(Flags, flagPos, value);
}
//---------------------------------------------------------------
// Status.
private SaStatus status = SaStatus.Unknown;
/// <summary>Item status.</summary>
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.
/// <summary>Copy common properties to this object.</summary>
protected void PopulateFrom(Data sourceData)
{
Id = sourceData.Id;
Notes = sourceData.Notes;
Status = sourceData.Status;
Flags = sourceData.Flags;
CreateStamp = sourceData.CreateStamp;
UpdateStamp = sourceData.UpdateStamp;
}
/// <summary>Copy comon properties to the target object.</summary>
internal void PopulateTo(Data targetData)
{
targetData.PopulateFrom(this);
}
//---------------------------------------------------------------
// Property change tracking.
private bool changed = false;
/// <summary>Flag to indicate whether any property has been modified.</summary>
public bool Changed
{
get { return changed; }
set
{
if (changed == value) return;
changed = value;
}
}
/// <summary>Clear 'Changed' flag.</summary>
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>(T oldValue, T newValue) where T : struct, IConvertible
{
CheckChangedEnumNullable<T>(oldValue, newValue);
}
protected void CheckChangedEnumNullable<T>(T? oldValue, T? newValue) where T : struct, IConvertible
{
if (!(oldValue != null && oldValue is Enum) || !(newValue != null && newValue is Enum))
throw new ArgumentException($"{SysUtil.Fn}<T> 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<String> oldValues, IEnumerable<String> newValues)
{
if (Changed) return;
Changed = !oldValues.ContentEquals(newValues);
}
protected void CheckChanged<T>(IEnumerable<T> oldValues, IEnumerable<T> 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(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
{
/// <summary>Property is valid (or has not been validate).</summary>
Valid,
/// <summary>Property is invalid.</summary>
Invalid,
/// <summary>Property is to be ignored during validation.</summary>
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;
}
//-------------------------------------------------------------------
// Disposal.
protected override void Dispose(bool disposing)
{
if (disposing)
{
}
}
//-------------------------------------------------------------------
// Properties.
public virtual bool ItemHasId { get; } = 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; }
}
/// <summary>Flags are positioned from 1, up to 16 allowed.</summary>
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;
}
/// <summary>Flags are positioned from 1, up to 16 allowed.</summary>
public bool GetFlag(Byte flagPos)
{
return GetFlag(data.Flags, flagPos);
}
/// <summary>Set flag value - position 1 - 16</summary>
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;
}
/// <summary>Set flag value - position 1 - 16</summary>
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;
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;
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.
/// <summary>Flag to indicate whether any property has been modified.</summary>
public bool Changed
{
get { return data.Changed; }
set
{
if (data.Changed == value) return;
data.Changed = value;
}
}
/// <summary>Clear the 'Changed' flag to indicate that no changes have been made.</summary>
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 }
/// <summary>Primary table alias to use if different from default.</summary>
public String TableAlias { get; set; }
/// <summary>Flag to indicate whether default filter ('1=1') is included if no other filter.</summary>
public bool IncludeDefaultFilter { get; set; } = true;
/// <summary>Results list paging.</summary>
public DbQuery.Paging ResultsPaging { get; } = new DbQuery.Paging();
/// <summary>Sort columns.</summary>
public List<ColumnDfn> SortColumns { get; } = new List<ColumnDfn>();
/// <summary>
/// Flag to return data in random order.
/// <para>- NB Depends on implementation for each manager and item.</para>
/// </summary>
public bool RandomOrder { get; set; } = false;
}
//-------------------------------------------------------------------
}
//=======================================================================
}