using System; using System.Collections.Generic; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Utils; namespace Sarand.Net.Standard.Base.Core { //======================================================================= public class DataValue { //------------------------------------------------------------------- // Definitions. public enum DataType { Unknown = 0, Bool, TriState, Long, Double, Decimal, String, Date, Time, DateTime, Guid, Blob }; public enum TriStateType { Unknown = 0, Red, Amber, Green, Blue, Purple, Yellow }; //------------------------------------------------------------------- // Data members. private DataType dataType; private Object value; //------------------------------------------------------------------- // Construction. public DataValue() { } public DataValue(DataValue dataValue) { if (dataValue != null) { dataType = dataValue.GetDataType(); value = dataValue.value; } } public DataValue(bool value) { this.value = value; this.dataType = DataType.Bool; } public DataValue(TriStateType value) { this.value = value; this.dataType = DataType.TriState; } public DataValue(long value) { this.value = value; this.dataType = DataType.Long; } public DataValue(double value) { this.value = value; this.dataType = DataType.Double; } public DataValue(decimal value) { this.value = value; this.dataType = DataType.Decimal; } public DataValue(String value) { this.value = value; this.dataType = DataType.String; } public DataValue(DateTime value, DataType type = DataType.DateTime) { this.value = value; switch (type) { case DataType.Date: case DataType.Time: case DataType.DateTime: this.dataType = type; break; default: this.dataType = DataType.DateTime; break; } } public DataValue(Guid value) { this.value = value; this.dataType = DataType.Guid; } public DataValue(Byte[] value) { this.value = value; this.dataType = DataType.Blob; } //------------------------------------------------------------------- // Properties. public static readonly DataValue NullValue = new DataValue(); public DataType GetDataType() { return dataType; } public static String GetTypeDesc(DataType type) { // Converts type to string. switch (type) { case DataType.Bool: return "Bool"; case DataType.TriState: return "TriState"; case DataType.Long: return "Long"; case DataType.Double: return "Double"; case DataType.Decimal: return "Decimal"; case DataType.String: return "String"; case DataType.Date: return "Date"; case DataType.Time: return "Time"; case DataType.DateTime: return "DateTime"; case DataType.Guid: return "Guid"; case DataType.Blob: return "Blob"; } return ""; } public String GetTypeDesc() { return GetTypeDesc(dataType); } public bool IsValid() { return (dataType != DataType.Unknown); } public bool IsNumeric() { return (dataType == DataType.Long || dataType == DataType.Double || dataType == DataType.Decimal); } public bool IsDate() { return (dataType == DataType.Date || dataType == DataType.DateTime); } public bool IsTime() { return (dataType == DataType.Time || dataType == DataType.DateTime); } public bool IsDateTime() { return (dataType == DataType.Date || dataType == DataType.Time || dataType == DataType.DateTime); } public bool IsGuid() { return (dataType == DataType.Guid); } public bool IsBlob() { return (dataType == DataType.Blob); } //------------------------------------------------------------------- // Conversion. public override String ToString() { if (value == null) return String.Empty; // Forces any data type to string. switch (dataType) { case DataType.Bool: return ((bool)value ? "Y" : "N"); case DataType.TriState: return ((TriStateType)value).ToString(); case DataType.Long: return ((long)value).ToString(); case DataType.Double: return ((double)value).ToString(); case DataType.Decimal: return ((decimal)value).ToString(); case DataType.String: return (String)value; case DataType.Date: return ((DateTime)value).ToString("yyyyMMdd"); case DataType.Time: return ((DateTime)value).ToString("HH:mm:ss"); case DataType.DateTime: return ((DateTime)value).ToString("yyyyMMddHHmmss"); } return String.Empty; } public double ToNumeric() { if (value == null) return 0.0; // Convert any type to double numeric. switch (dataType) { case DataType.Bool: return ((bool)value ? 1 : 0); case DataType.TriState: return (int)(TriStateType)value; case DataType.Long: return (long)value; case DataType.Double: return (double)value; case DataType.Decimal: return (double)(decimal)value; case DataType.String: return StringUtil.ToDouble((String)value); case DataType.Date: return ((DateTime)value).Ticks; case DataType.Time: return ((DateTime)value).Ticks; case DataType.DateTime: return ((DateTime)value).Ticks; } return 0.0; } public decimal ToDecimal() { if (value == null) return 0.0m; // Convert any type to double numeric. switch (dataType) { case DataType.Bool: return ((bool)value ? 1 : 0); case DataType.TriState: return (int)(TriStateType)value; case DataType.Long: return (long)value; case DataType.Double: return (decimal)(double)value; case DataType.Decimal: return (decimal)value; case DataType.String: return StringUtil.ToDecimal((String)value); case DataType.Date: return ((DateTime)value).Ticks; case DataType.Time: return ((DateTime)value).Ticks; case DataType.DateTime: return ((DateTime)value).Ticks; } return 0.0m; } /// Return value interpretted as boolean. public bool ToBool() { if (value == null) return false; // Numeric <> 0, String: 'Yes', 'True', numeric value. switch (dataType) { case DataType.Bool: return (bool)value; case DataType.TriState: return (TriStateType)value != TriStateType.Unknown; case DataType.Long: return (long)value != 0; case DataType.Double: return (double)value != 0.0; case DataType.Decimal: return (decimal)value != 0.0m; case DataType.String: return ((String)value).ToBool(); case DataType.Date: return ((DateTime)value).Ticks != 0; case DataType.Time: return ((DateTime)value).Ticks != 0; case DataType.DateTime: return ((DateTime)value).Ticks != 0; } return false; } /// Return explicit boolean value or false for other types. public bool AsBool() { // Convert to specific type of data - fails if type is not correct: if (dataType == DataType.Bool) return (bool)value; if (dataType == DataType.Unknown) return false; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return false; } public TriStateType AsTriState() { if (dataType == DataType.TriState) return (TriStateType)value; if (dataType == DataType.Unknown) return TriStateType.Unknown; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return TriStateType.Unknown; } public long AsLong() { if (dataType == DataType.Long) return (long)value; if (dataType == DataType.Unknown) return 0; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return 0; } public double AsDouble() { if (dataType == DataType.Double) return (double)value; if (dataType == DataType.Unknown) return 0.0; // Aug-2018 Temporarily allow decimal values to be returned as double. if (dataType == DataType.Decimal) { SaLogger.Warn($"{SysUtil.Fn} Data type: {dataType.ToString()}."); return (double)(decimal)value; } if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return 0.0; } public decimal AsDecimal() { if (dataType == DataType.Decimal) return (decimal)value; if (dataType == DataType.Unknown) return 0.00m; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return 0.00m; } public String AsString() { if (dataType == DataType.String) return (String)value; if (dataType == DataType.Unknown) return ""; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return ""; } public DateTime AsDateTime() { // NB DateTime.Ticks is NotFiniteNumberException of 100-nanosecond intervals since beginning of 1st January 0001. if (dataType == DataType.Date || dataType == DataType.Time || dataType == DataType.DateTime) return (DateTime)value; if (dataType == DataType.Unknown) return DateTime.MinValue; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return DateTime.MinValue; } public DateTime AsDate() { if (dataType == DataType.Date || dataType == DataType.DateTime) return ((DateTime)value).Date; if (dataType == DataType.Unknown) return DateTime.MinValue; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return DateTime.MinValue; } public DateTime AsTime() { if (dataType == DataType.Time || dataType == DataType.DateTime) return (DateTime)value; if (dataType == DataType.Unknown) return DateTime.MinValue; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return DateTime.MinValue; } public Guid AsGuid() { if (dataType == DataType.Guid) return (Guid)value; if (dataType == DataType.Unknown) return default(Guid); if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return default(Guid); } public Byte[] AsBlob() { if (dataType == DataType.Blob) return (Byte[])value; if (dataType == DataType.Unknown) return null; if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Incorrect data type: {dataType.ToString()}."); return null; } //------------------------------------------------------------------- // Comparison. public bool Equals(DataValue value) { return false; } public int CompareTo(DataValue value) { return -1; } //------------------------------------------------------------------- // Utilities. public void Clear() { dataType = DataType.Unknown; value = null; } //------------------------------------------------------------------- // Arithmeic. public void Increment(DataValue value) { if (dataType == value.GetDataType()) { switch (dataType) { case DataType.Long: this.value = (long)(this.value) + value.AsLong(); break; case DataType.Double: this.value = (double)(this.value) + value.AsDouble(); break; case DataType.Decimal: this.value = (decimal)(this.value) + value.AsDecimal(); break; } } } public void Decrement(DataValue value) { if (dataType == value.GetDataType()) { switch (dataType) { case DataType.Long: this.value = (long)(this.value) - value.AsLong(); break; case DataType.Double: this.value = (double)(this.value) - value.AsDouble(); break; case DataType.Decimal: this.value = (decimal)(this.value) - value.AsDecimal(); break; } } } public void MultiplyBy(DataValue value) { if (dataType == value.GetDataType()) { switch (dataType) { case DataType.Long: this.value = (long)(this.value) * value.AsLong(); break; case DataType.Double: this.value = (double)(this.value) * value.AsDouble(); break; case DataType.Decimal: this.value = (decimal)(this.value) * value.AsDecimal(); break; } } } public void DivideBy(DataValue value) { if (dataType == value.GetDataType()) { switch (dataType) { case DataType.Long: this.value = (long)(this.value) / value.AsLong(); break; case DataType.Double: this.value = (double)(this.value) / value.AsDouble(); break; case DataType.Decimal: this.value = (decimal)(this.value) / value.AsDecimal(); break; } } } //------------------------------------------------------------------- } //======================================================================= // Data Value list extension functions. public static class DataValueList { //------------------------------------------------------------------- // Population. /// Add a String value to the list. public static void Add(this List values, String value) { values.Add(new DataValue(value)); } /// Add a boolean value to the list. public static void Add(this List values, bool value) { values.Add(new DataValue(value)); } /// Add an integer value to the list. public static void Add(this List values, int value) { values.Add(new DataValue(value)); } /// Add a long value to the list. public static void Add(this List values, long value) { values.Add(new DataValue(value)); } /// Add a double value to the list. public static void Add(this List values, double value) { values.Add(new DataValue(value)); } /// Add a decimal value to the list. public static void Add(this List values, decimal value) { values.Add(new DataValue(value)); } /// Add a date time value to the list. public static void Add(this List values, DateTime value) { values.Add(new DataValue(value)); } //------------------------------------------------------------------- // Conversion. /// Convert all data values to strings. public static List ToStringList(this List values) { List stringValues = new List(); foreach (var dataValue in values) stringValues.Add(values.ToString()); return stringValues; } /// /// Convert the data values to raw objects. /// eg. For population to Excel spreadsheet cells. /// public static List ToObjectList(this List values) { List cellValues = new List(); foreach (DataValue value in values) { if (value.GetDataType() == DataValue.DataType.Bool) cellValues.Add(value.AsBool()); else if (value.GetDataType() == DataValue.DataType.Long) cellValues.Add(value.AsLong()); else if (value.GetDataType() == DataValue.DataType.Double) cellValues.Add(value.AsDouble()); else if (value.GetDataType() == DataValue.DataType.Decimal) cellValues.Add(value.AsDecimal()); else if (value.IsDateTime()) cellValues.Add(value.AsDateTime()); else // Default - String value. cellValues.Add(value.ToString()); } return cellValues; } //------------------------------------------------------------------- // Numeric - only with compatible numeric values. /// Minimum numeric value in the list. public static DataValue GetMinValue(this List values) { DataValue minValue = null; foreach (var dataValue in values) { if (dataValue.IsNumeric()) { if (minValue == null) minValue = new DataValue(dataValue.ToNumeric()); else if (dataValue.ToNumeric() < minValue.ToNumeric()) minValue = new DataValue(dataValue.ToNumeric()); } } return minValue; } /// Maximum numeric value in the list. public static DataValue GetMaxValue(this List values) { DataValue maxValue = null; foreach (var dataValue in values) { if (dataValue.IsNumeric()) { if (maxValue == null) maxValue = new DataValue(dataValue.ToNumeric()); else if (dataValue.ToNumeric() > maxValue.ToNumeric()) maxValue = new DataValue(dataValue.ToNumeric()); } } return maxValue; } //------------------------------------------------------------------- } //======================================================================= }