using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
namespace Sarand.Net.Standard.Base.Core
{
//=======================================================================
// Definitions.
public enum ColumnAlignment { Default, Left, Center, Right }
public enum ColumnBoolFormat
{
/// Text: 'Y' (true) or 'N' (false).
YorN,
/// Text: 'Y' (true).
Y,
/// Text: 'N' (false).
N,
/// Text: '1' (true) or '0' (false).
OneOrZero,
/// Text: 'True' or 'False'.
TrueFalse,
/// Graphic icons: Tick (true) or Cross (false).
TickCross,
/// Graphic icon: Tick (true).
Tick,
/// Graphic icon: Cross (false).
Cross,
/// Graphic icons (inverted): Tick (false) or Cross (true).
TickCross_Inv,
/// Graphic icon (inverted): Tick (false).
Tick_Inv,
/// Graphic icon (inverted): Cross (true).
Cross_Inv
}
public enum ColumnTriStateFormat
{
/// Text: R, A, G etc.
RAG,
/// Text: 1, 2, 3 etc.
Numeric,
/// Graphic icons.
Lights
}
//=======================================================================
public class ColumnDfn
{
//-------------------------------------------------------------------
// Definitions.
public enum ColumnSortMode
{
Off, On, AscendOnly, DescendOnly
}
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public ColumnDfn
(int id, String caption, int width = 0, int dbColumn = 0,
String dataName = "", String sortDataName = "",
DataValue.DataType dataType = DataValue.DataType.String, ColumnAlignment alignment = ColumnAlignment.Default)
{
this.Id = id;
this.Caption = caption;
this.Width = width;
this.DbColumn = dbColumn;
this.DataName = dataName;
this.SortDataName = sortDataName;
this.DataType = dataType;
this.Alignment = alignment;
}
//-------------------------------------------------------------------
// Properties.
public int Id { get; set; } = 0;
/// Database column identity (DbDfn.ColumnIdx etc).
public int DbColumn { get; set; } = 0;
/// Column code - eg. for configuration options.
public String Code { get; set; } = String.Empty;
/// Column header text.
public String Caption { get; set; } = String.Empty;
/// Column width (device dependent).
public int Width { get; set; } = 0;
public ColumnAlignment Alignment { get; set; } = ColumnAlignment.Default;
/// Data value name (may be an alias).
public String DataName { get; set; } = String.Empty;
public byte NumDecimals { get; set; } = 2;
public char NumThousands { get; set; } = ',';
/// Default: Zero values hidden.
public bool ShowZeroValues { get; set; } = false;
public ColumnBoolFormat BoolFormat { get; set; } = ColumnBoolFormat.YorN;
public ColumnTriStateFormat TriStateFormat { get; set; } = ColumnTriStateFormat.RAG;
/// Null date - values on or before are considered invalid.
public DateTime NullDate { get; set; } = DateTime.MinValue;
public String DateFormat { get; set; } = "d-MMM-yy";
public String DateTimeSeparator { get; set; } = " ";
public String TimeFormat { get; set; } = "HH:mm";
public DataValue.DataType DataType { get; set; } = DataValue.DataType.String;
public bool IsNumeric { get { return DataType == DataValue.DataType.Long || DataType == DataValue.DataType.Double || DataType == DataValue.DataType.Decimal; } }
public bool Resizable { get; set; } = true;
public bool WrapText { get; set; } = false;
public bool Hidden { get; set; } = false;
public bool Frozen { get; set; } = false;
// Drop-down configuration.
public List Values { get; } = new List();
/// User must pick from the supplied list (default: true). Non-exclusive lists (editable) have same value and display members.
public bool ExclusiveValues { get; set; } = true;
/// User entered values (Exclusive=false) are converted if corresponding value found in list.
public bool MatchCase { get; set; } = true;
// Edit configuration.
public int MaxLength { get; set; } = 0;
public bool ReadOnly { get; set; } = false;
public bool Uppercase { get; set; } = false;
public bool Lowercase { get; set; } = false;
public bool Password { get; set; } = false;
// Sort attributes.
/// Sort mode. Default: 'On'.
public ColumnSortMode SortMode { get; set; } = ColumnSortMode.On;
/// Data value name for sort (fully qualified).
public String SortDataName { get; set; } = String.Empty;
public bool SortAscending { get; set; } = true;
//-------------------------------------------------------------------
// Population.
public void Set
(String caption, int width, int dbColumn = 0,
String dataName = "", String sortDataName = "",
DataValue.DataType dataType = DataValue.DataType.String, ColumnAlignment alignment = ColumnAlignment.Default)
{
this.Caption = caption;
this.Width = width;
this.DbColumn = dbColumn;
this.DataName = dataName;
this.SortDataName = sortDataName;
this.DataType = dataType;
this.Alignment = alignment;
}
//-------------------------------------------------------------------
// Formatting.
public String FormatValue (NamedValue.Map values)
{
String value = String.Empty;
if (DataName.IsEmpty()) return value;
DataValue dataValue = values.GetValue(DataName);
if (dataValue == null || !dataValue.IsValid()) return value;
return FormatValue(dataValue);
}
public String FormatValue (DataValue dataValue)
{
String value = String.Empty;
if (dataValue == null || !dataValue.IsValid()) return value;
switch (DataType)
{
case DataValue.DataType.Date:
if (dataValue.IsDate())
{
DateTime date = dataValue.AsDate();
if (DateUtil.IsValid(date, NullDate))
value = date.Format(DateFormat);
}
else value = dataValue.ToString();
break;
case DataValue.DataType.Time:
if (dataValue.IsTime())
{
DateTime time = dataValue.AsTime();
if (DateUtil.IsValid(time, NullDate))
value = time.Format(TimeFormat);
}
else value = dataValue.ToString();
break;
case DataValue.DataType.DateTime:
if (dataValue.IsDateTime())
{
DateTime dateTime = dataValue.AsDateTime();
if (DateUtil.IsValid(dateTime, NullDate))
value = dateTime.Format(DateFormat + DateTimeSeparator + TimeFormat);
}
else value = dataValue.ToString();
break;
case DataValue.DataType.Long:
if (dataValue.IsNumeric())
{
long longValue = 0;
if (dataValue.GetDataType() == DataValue.DataType.Long) longValue = dataValue.AsLong();
else longValue = (long)dataValue.ToNumeric();
if (longValue != 0 || ShowZeroValues)
value = longValue.ToString();
}
else value = dataValue.ToString();
break;
case DataValue.DataType.Double:
if (dataValue.IsNumeric())
{
double doubleValue = dataValue.ToNumeric();
if (doubleValue != 0.0 || ShowZeroValues)
value = StringUtil.FormatNumeric(doubleValue, NumDecimals, 0, NumThousands);
}
else value = dataValue.ToString();
break;
case DataValue.DataType.Decimal:
if (dataValue.IsNumeric())
{
decimal decimalValue = 0.0m;
if (dataValue.GetDataType() == DataValue.DataType.Decimal) decimalValue = dataValue.AsDecimal();
else decimalValue = (decimal)dataValue.ToNumeric();
if (decimalValue != 0.0m || ShowZeroValues)
value = StringUtil.FormatNumeric(decimalValue, NumDecimals, 0, NumThousands);
}
else value = dataValue.ToString();
break;
case DataValue.DataType.Bool:
switch (BoolFormat)
{
case ColumnBoolFormat.YorN:
value = (dataValue.ToBool() ? "Y" : "N");
break;
case ColumnBoolFormat.Y:
value = (dataValue.ToBool() ? "Y" : "");
break;
case ColumnBoolFormat.N:
value = (dataValue.ToBool() ? "" : "N");
break;
case ColumnBoolFormat.TrueFalse:
value = (dataValue.ToBool() ? "True" : "False");
break;
default:
value = (dataValue.ToBool() ? "1" : "0");
break;
}
break;
case DataValue.DataType.TriState:
switch (TriStateFormat)
{
case ColumnTriStateFormat.RAG:
if (dataValue.AsTriState() == DataValue.TriStateType.Red)
value = "R";
else if (dataValue.AsTriState() == DataValue.TriStateType.Amber)
value = "A";
else if (dataValue.AsTriState() == DataValue.TriStateType.Green)
value = "G";
else if (dataValue.AsTriState() == DataValue.TriStateType.Blue)
value = "B";
else if (dataValue.AsTriState() == DataValue.TriStateType.Purple)
value = "P";
else if (dataValue.AsTriState() == DataValue.TriStateType.Yellow)
value = "Y";
else if (dataValue.AsTriState() == DataValue.TriStateType.Unknown)
value = "";
break;
default:
if (dataValue.AsTriState() == DataValue.TriStateType.Red)
value = "1";
else if (dataValue.AsTriState() == DataValue.TriStateType.Amber)
value = "2";
else if (dataValue.AsTriState() == DataValue.TriStateType.Green)
value = "3";
else if (dataValue.AsTriState() == DataValue.TriStateType.Blue)
value = "4";
else if (dataValue.AsTriState() == DataValue.TriStateType.Purple)
value = "5";
else if (dataValue.AsTriState() == DataValue.TriStateType.Yellow)
value = "6";
else if (dataValue.AsTriState() == DataValue.TriStateType.Unknown)
value = "";
break;
}
break;
default:
value = dataValue.ToString();
break;
}
return value.TrimEnd(' ');
}
//-------------------------------------------------------------------
}
//=======================================================================
public static class ColumnDfnList
{
//-------------------------------------------------------------------
// C o n t a i n s
//-------------------------------------------------------------------
/// Determine whether list contains column with Id matching specified enum value (integer comparison).
public static bool HasId (this List values, T id) where T : struct, IConvertible
{
if (!(id is Enum))
throw new ArgumentException("HasId parameter must be an enumerated type. Type supplied: " + id.GetType().Name);
return values.HasId((int)(id as IConvertible));
}
/// Determine whether list contains column with Id matching specified integer value.
public static bool HasId (this List values, int id)
{
foreach (var column in values)
if (column.Id == id) return true;
return false;
}
/// Determine whether list contains column with Db Column matching specified enum value (integer comparison).
public static bool HasDbColumn (this List values, T id) where T : struct, IConvertible
{
if (!(id is Enum))
throw new ArgumentException("HasDbColumn parameter must be an enumerated type. Type supplied: " + id.GetType().Name);
return values.HasDbColumn((int)(id as IConvertible));
}
/// Determine whether list contains column with Db Column matching specified integer value.
public static bool HasDbColumn (this List values, int dbColumn)
{
foreach (var column in values)
if (column.DbColumn == dbColumn) return true;
return false;
}
//-------------------------------------------------------------------
// Columns in list.
public static int GetPosForId (this List values, T id) where T : struct, IConvertible
{
if (!(id is Enum))
throw new ArgumentException("HasId parameter must be an enumerated type. Type supplied: " + id.GetType().Name);
return values.GetPosForId((int)(id as IConvertible));
}
public static int GetPosForId (this List values, int id)
{
for (int pos = 0; pos < values.Count; pos++)
if (values[pos].Id == id) return pos + 1;
return 0;
}
public static List GetColumnsWithNonZeroWidth (this List values)
{
return values.FindAll(item => item.Width > 0);
}
//-------------------------------------------------------------------
// C o l u m n W i d t h s
//-------------------------------------------------------------------
// Combined width of all columns.
/// Get the width of all non-zero width columns separated by the specified spacing
public static int GetFullWidth (this List values, int columnSpacing)
{
List columnsNonZeroWidth = values.GetColumnsWithNonZeroWidth();
if (columnsNonZeroWidth.Count < 1) return 0;
int width = 0;
foreach (var column in values)
width += column.Width;
return width + (columnSpacing * (columnsNonZeroWidth.Count - 1));
}
// Column widths are adjusted to keep their relative width constant.
/// Expand/contract non-zero width columns to fill the specified width with the specified space in between each.
public static bool FillWidth (this List values, long width, int columnSpacing)
{
List columnsNonZeroWidth = values.GetColumnsWithNonZeroWidth();
if (columnsNonZeroWidth.Count < 1) return false;
long fullWidthNoSpacing = values.GetFullWidth(0);
if (fullWidthNoSpacing < 1) return false;
double columnWidthFactor = ((double)width - (columnSpacing * (columnsNonZeroWidth.Count - 1))) / fullWidthNoSpacing;
foreach (ColumnDfn column in columnsNonZeroWidth)
column.Width = Math.Max(1, (int)Math.Ceiling(column.Width * columnWidthFactor));
return true;
}
/// Calculate the left position for each non-zero width column with the specified spacing.
public static int[] GetColumnLeftPositions (this List values, int leftPosition, int columnSpacing)
{
List columnsNonZeroWidth = values.GetColumnsWithNonZeroWidth();
if (columnsNonZeroWidth.Count < 1) return new int[0];
int[] columnPositions = new int[columnsNonZeroWidth.Count];
int columnLeftPos = leftPosition;
for (int columnIdx = 0; columnIdx < columnsNonZeroWidth.Count; columnIdx++)
{
ColumnDfn column = columnsNonZeroWidth[columnIdx];
columnPositions[columnIdx] = columnLeftPos;
columnLeftPos += column.Width + columnSpacing;
}
return columnPositions;
}
///
/// Calculate the horizontal print position for each non-zero width column with the specified spacing.
/// NB Print position will take alignment (left/centre/right) into consideration.
///
public static int[] GetColumnPrintPositions (this List values, int leftPosition, int columnSpacing)
{
List columnsNonZeroWidth = values.GetColumnsWithNonZeroWidth();
if (columnsNonZeroWidth.Count < 1) return new int[0];
int[] columnPositions = new int[columnsNonZeroWidth.Count];
int columnLeftPos = leftPosition;
for (int columnIdx = 0; columnIdx < columnsNonZeroWidth.Count; columnIdx++)
{
ColumnDfn column = columnsNonZeroWidth[columnIdx];
int columnPos = columnLeftPos;
if (column.Alignment == ColumnAlignment.Center)
columnPos = columnLeftPos + (column.Width / 2);
else if (column.Alignment == ColumnAlignment.Right)
columnPos = columnLeftPos + column.Width;
columnPositions[columnIdx] = columnPos;
columnLeftPos += column.Width + columnSpacing;
}
return columnPositions;
}
//-------------------------------------------------------------------
// E x t r a c t C o n t e n t s
//-------------------------------------------------------------------
/// Compile list of captions from the columns.
public static List GetCaptions (this List values)
{
List captions = new List();
foreach (ColumnDfn column in values)
captions.Add(StringUtil.EmptyOnNull(column.Caption));
return captions;
}
///
/// Convert column list to strings representing sort columns.
/// NB Column name is populated as DataName and may not be the same as used in a database query in all cases.
///
public static List GetSortColumns (this List values)
{
List sortColumns = new List();
foreach (ColumnDfn column in values)
sortColumns.Add(column.DataName + (column.SortAscending ? " ASC" : " DESC"));
return sortColumns;
}
//-------------------------------------------------------------------
}
//=======================================================================
}