519 lines
16 KiB
C#
519 lines
16 KiB
C#
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 "<Unknown>";
|
|
}
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
/// <summary>Return value interpretted as boolean.</summary>
|
|
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;
|
|
}
|
|
/// <summary>Return explicit boolean value or false for other types.</summary>
|
|
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.
|
|
|
|
/// <summary>Add a String value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, String value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
/// <summary>Add a boolean value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, bool value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
/// <summary>Add an integer value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, int value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
/// <summary>Add a long value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, long value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
/// <summary>Add a double value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, double value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
/// <summary>Add a decimal value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, decimal value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
/// <summary>Add a date time value to the list.</summary>
|
|
public static void Add(this List<DataValue> values, DateTime value)
|
|
{
|
|
values.Add(new DataValue(value));
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Conversion.
|
|
|
|
/// <summary>Convert all data values to strings.</summary>
|
|
public static List<String> ToStringList(this List<DataValue> values)
|
|
{
|
|
List<String> stringValues = new List<String>();
|
|
foreach (var dataValue in values)
|
|
stringValues.Add(values.ToString());
|
|
return stringValues;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert the data values to raw objects.
|
|
/// <para>eg. For population to Excel spreadsheet cells.</para>
|
|
/// </summary>
|
|
public static List<Object> ToObjectList(this List<DataValue> values)
|
|
{
|
|
List<Object> cellValues = new List<Object>();
|
|
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.
|
|
|
|
/// <summary>Minimum numeric value in the list.</summary>
|
|
public static DataValue GetMinValue(this List<DataValue> 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;
|
|
}
|
|
|
|
/// <summary>Maximum numeric value in the list.</summary>
|
|
public static DataValue GetMaxValue(this List<DataValue> 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;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
|
|
//=======================================================================
|
|
}
|