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, 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 (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.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 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; } /// 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 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; } //------------------------------------------------------------------- } //======================================================================= }