using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Diagnostics;
namespace Dialogik.Utils.Defines
{
public interface IEnumBase
{
bool InitValue (Int32 decValue);
}
public class EnumBase<TC, TT> : ISerializable, IEnumBase
{
internal enum EnumOperator
{
DecValue = 1,
EnumValue = 2,
EnumName = 3,
Bytes = 4,
BitFlags = 5,
BitFlagsAdd = 6,
BitFlagsSub = 7,
}
private static int s_flagEnumSize = 0;
private static int s_SegmentCount = 0;
private static List<object> s_constantEnums = new List<object>();
private static int[] s_constantArray = null;
private static Type s_classType = typeof(TC);
private static Type s_enumType = typeof(TT);
private static Type s_decType = null;
#region Members
private EnumContext<TT> _innerValue = null;
internal EnumContext<TT> Value
{
get
{
return this._innerValue;
}
set
{
this._innerValue = value;
}
}
public List<TC> ListConst
{
get
{
return (GetInnerList(false));
}
}
public List<TC> ListFlagged
{
get
{
return (GetInnerList(true));
}
}
private List<TC> GetInnerList(bool flaggedOnly)
{
Instancer _instancer = Factory.GetInstancer(s_classType);
List<TC> _innerList = new List<TC>();
if (s_flagEnumSize > 0)
{
bool[] bitFlags = this.Value.BitFlags;
int count = bitFlags.Length;
for (int i = 0; i < count; i++)
{
if (!flaggedOnly || bitFlags[i])
{
TC _innerItem = (TC)_instancer.CreateNew();
IEnumBase _innerBase = _innerItem as IEnumBase;
if (_innerBase.InitValue(i + 1))
{
_innerList.Add(_innerItem);
}
}
}
}
return _innerList;
}
public List<Int32> ListConstDecValues
{
get
{
List<Int32> _result = new List<Int32>();
List<EnumContext<TT>> _inner = GetContextValues(false);
foreach(EnumContext<TT> _item in _inner)
{
_result.Add(_item.DecValue);
}
return (_result);
}
}
public List<Int32> ListFlaggedDecValues
{
get
{
List<Int32> _result = new List<Int32>();
List<EnumContext<TT>> _inner = GetContextValues(true);
foreach(EnumContext<TT> _item in _inner)
{
_result.Add(_item.DecValue);
}
return (_result);
}
}
public List<TT> ListConstEnumValues
{
get
{
List<TT> _result = new List<TT>();
List<EnumContext<TT>> _inner = GetContextValues(false);
foreach(EnumContext<TT> _item in _inner)
{
_result.Add(_item.EnumValue);
}
return (_result);
}
}
public List<TT> ListFlaggedEnumValues
{
get
{
List<TT> _result = new List<TT>();
List<EnumContext<TT>> _inner = GetContextValues(true);
foreach(EnumContext<TT> _item in _inner)
{
_result.Add(_item.EnumValue);
}
return (_result);
}
}
private List<EnumContext<TT>> GetContextValues(bool flaggedOnly)
{
List<EnumContext<TT>> _innerList = new List<EnumContext<TT>>();
if (s_flagEnumSize > 0)
{
bool[] bitFlags = this.Value.BitFlags;
int count = bitFlags.Length;
for (int i = 0; i < count; i++)
{
if (!flaggedOnly || bitFlags[i])
{
EnumContext<TT> itemValue = null;
itemValue = InitEnumType(EnumOperator.DecValue, i + 1);
if (itemValue.DecValue > 0)
{
_innerList.Add(itemValue);
}
}
}
}
return _innerList;
}
#endregion
#region Contructors
internal EnumBase()
{
InitFlags();
this.Value = new EnumContext<TT>(s_flagEnumSize, 0, null);
}
// for constants
internal EnumBase(Int32 decValue, TT enumValue, Type enumType, string description)
{
s_decType = enumType;
string _enumName = Enum.GetName(enumType, decValue);
InitFlags();
this.Value = new EnumContext<TT>(s_flagEnumSize, decValue, null) { EnumValue = enumValue, EnumName = _enumName, Description = description };
s_constantEnums.Add((object)this);
if (decValue > 0)
{
decValue--;
s_constantArray[decValue] = s_constantEnums.Count - 1;
}
}
// because constants are required by design and static, it is sufficient to call InitFlags
// in above constructors only
private void InitFlags()
{
if (s_constantEnums.Count == 0)
{
// Reflection is done only once per class
EFlagsAttribute[] flagsAttributes = (EFlagsAttribute[])this.GetType().GetCustomAttributes(typeof(EFlagsAttribute), true);
if (flagsAttributes.Length > 0)
{
s_flagEnumSize = (int)flagsAttributes[0].FlagSize;
s_SegmentCount = s_flagEnumSize / 8 /*Byte*/;
}
if (s_flagEnumSize > 0)
{
s_constantArray = new int[s_flagEnumSize];
}
}
}
internal EnumBase(TT enumValue) { this.Value = InitEnumType(EnumOperator.EnumValue, enumValue); }
internal EnumBase(Int32 decValue) { this.Value = InitEnumType(EnumOperator.DecValue, decValue); }
internal EnumBase(string enumName) { this.Value = InitEnumType(EnumOperator.EnumName, enumName); }
internal EnumBase(byte[] serBytes) { this.RawData = serBytes; }
internal EnumBase(bool[] bitFlags) { this.Value = InitEnumType(EnumOperator.BitFlags, bitFlags); }
internal EnumBase(bool addFlags, object value1, object value2)
{
if (s_flagEnumSize == 0)
{
Debug.Assert(false);
}
else
{
this.Value = InitEnumType(addFlags ? EnumOperator.BitFlagsAdd : EnumOperator.BitFlagsSub, (bool[])value1, (bool[])value2);
}
}
#endregion
#region ISerializable
public EnumBase(SerializationInfo info, StreamingContext context)
{
this.RawData = (byte[])info.GetValue("b", typeof(byte[]));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("b", this.RawData);
}
#endregion
#region Property - RawData
public byte[] RawData
{
#region Getter
get
{
List<byte> resultBytes = new List<byte>();
if (s_flagEnumSize == 0)
{
// first byte is 1 = decimal
resultBytes.Add((byte)0x01);
Int32 decValue = Value.DecValue;
resultBytes.Add((byte)decValue);
decValue = decValue >> 8;
resultBytes.Add((byte)decValue);
decValue = decValue >> 8;
resultBytes.Add((byte)decValue);
decValue = decValue >> 8;
resultBytes.Add((byte)decValue);
}
else
{
// first byte is 2 = bitflags
resultBytes.Add((byte)0x02);
int i;
byte[] serBytes = this.Value.ByteValue;
List<byte> usedBytes = new List<byte>();
// first we name the used Segments (0 based)
for (i = 0; i < serBytes.Length; i++)
{
if (serBytes[i] != 0x00)
{
usedBytes.Add((byte)i);
}
}
// number of used Segments
resultBytes.Add((byte)usedBytes.Count);
// used segments (the number only)
for (i = 0; i < usedBytes.Count; i++)
{
resultBytes.Add(usedBytes[i]);
}
// now the segments themselves
for (i = 0; i < serBytes.Length; i++)
{
if (serBytes[i] != 0x00)
{
resultBytes.Add(serBytes[i]);
}
}
}
return resultBytes.ToArray();
}
#endregion
#region Setter
set
{
byte[] serBytes = value;
if (serBytes[0] == 0x01)
{
Int32 decValue = 0x00;
decValue += serBytes[4];
decValue = decValue << 8;
decValue += serBytes[3];
decValue = decValue << 8;
decValue += serBytes[2];
decValue = decValue << 8;
decValue += serBytes[1];
this.Value = InitEnumType(EnumOperator.DecValue, decValue);
}
else
{
int i;
List<bool> usedBytes = new List<bool>(new bool[s_SegmentCount]);
List<byte> resultBytes = new List<byte>(new byte[s_SegmentCount]);
// number of used Segments
int byteCount = serBytes[1];
byte segment = 0;
// used segments (the number only)
for (i = 0; i < byteCount; i++)
{
// read with offset 2 since first is identifier + count
segment = serBytes[(i+2)];
usedBytes[segment] = true;
}
// now the data
for (i = 0; i < s_SegmentCount; i++)
{
resultBytes[i] = 0x00;
if (usedBytes[i])
{
// read with offset
resultBytes[i] = serBytes[(i+2+byteCount)];
}
}
this.Value = InitEnumType(EnumOperator.Bytes, resultBytes.ToArray());
}
}
#endregion
}
#endregion
#region Methods
internal static EnumContext<TT> InitEnumType(EnumOperator searchMode, object searchValue)
{
return InitEnumType(searchMode, searchValue, null);
}
internal static EnumContext<TT> InitEnumType(EnumOperator searchMode, object searchValue1, object searchValue2)
{
bool itemfound = false;
if (searchValue1 != null)
{
EnumContext<TT> itemValue = null;
switch (searchMode)
{
case EnumOperator.DecValue:
int dec = (int)searchValue1;
if (dec>0)
{
dec--;
int pos = s_constantArray[dec];
itemValue = ((EnumBase<TC, TT>)s_constantEnums[pos]).Value;
}
else
{
itemValue = new EnumContext<TT>(s_flagEnumSize, 0, null);
}
break;
case EnumOperator.BitFlags:
itemValue = new EnumContext<TT>(s_flagEnumSize, 0, (bool[])searchValue1);
break;
case EnumOperator.BitFlagsAdd:
itemValue = new EnumContext<TT>(s_flagEnumSize, 0, (bool[])searchValue1);
itemValue.AddBitFlag((bool[])searchValue2);
itemValue.CalcDecValue();
break;
case EnumOperator.BitFlagsSub:
itemValue = new EnumContext<TT>(s_flagEnumSize, 0, (bool[])searchValue1);
itemValue.SubBitFlag((bool[])searchValue2);
itemValue.CalcDecValue();
break;
case EnumOperator.Bytes:
itemValue = new EnumContext<TT>(s_flagEnumSize, 0, null);
if (typeof(byte[]).IsAssignableFrom(searchValue1.GetType()))
{
itemValue.ByteValue = (byte[])searchValue1;
}
itemValue.CalcDecValue();
break;
case EnumOperator.EnumValue:
case EnumOperator.EnumName:
// check if we have a corresponding item
foreach (EnumBase<TC, TT> constantItem in s_constantEnums)
{
itemValue = ((EnumBase<TC, TT>)constantItem).Value;
if (searchMode == EnumOperator.EnumValue) itemfound = object.Equals(itemValue.EnumValue,(TT) searchValue1);
if (searchMode == EnumOperator.EnumName ) itemfound = object.Equals(itemValue.EnumName, (string)searchValue1);
if (!itemfound)
{
itemValue = null;
}
else
{
break;
}
}
break;
}
return itemValue;
}
return null;
}
#endregion
#region IEnumBase Members
bool IEnumBase.InitValue(int decValue)
{
this.Value = InitEnumType(EnumOperator.DecValue, decValue);
return this.Value.DecValue > 0;
}
#endregion
internal object CmpValue
{
get { return this.Value.CmpValue; }
}
public Int32 DecValue
{
get { return this.Value.DecValue; }
}
public TT EnumValue
{
get { return this.Value.EnumValue; }
}
public string EnumName
{
get
{
return this.Value.EnumName;
}
}
public string Description
{
get { return this.Value.Description; }
}
#region Operators
public static implicit operator TT (EnumBase<TC, TT> operatorValue) { return operatorValue.Value.EnumValue; }
public static implicit operator Int32 (EnumBase<TC, TT> operatorValue) { return operatorValue.Value.DecValue; }
public static implicit operator string (EnumBase<TC, TT> operatorValue) { return operatorValue.Value.EnumName; }
public static implicit operator byte[] (EnumBase<TC, TT> operatorValue) { return operatorValue.RawData; }
public static implicit operator bool[] (EnumBase<TC, TT> operatorValue) { return operatorValue.Value.BitFlags; }
public static implicit operator EnumBase<TC, TT> (TT operatorValue) { return new EnumBase<TC, TT>(operatorValue); }
public static implicit operator EnumBase<TC, TT> (Int32 operatorValue) { return new EnumBase<TC, TT>(operatorValue); }
public static implicit operator EnumBase<TC, TT> (string operatorValue) { return new EnumBase<TC, TT>(operatorValue); }
public static implicit operator EnumBase<TC, TT> (byte[] operatorValue) { return new EnumBase<TC, TT>(operatorValue); }
public static implicit operator EnumBase<TC, TT> (bool[] operatorValue) { return new EnumBase<TC, TT>(operatorValue); }
public static EnumBase<TC, TT> operator + (EnumBase<TC, TT> value1, EnumBase<TC, TT> value2) { return new EnumBase<TC, TT>(true, value1.CmpValue, value2.CmpValue); }
public static EnumBase<TC, TT> operator + (EnumBase<TC, TT> value1, TT value2) { return new EnumBase<TC, TT>(true, value1.CmpValue, new EnumBase<TC, TT>(value2).CmpValue); }
public static EnumBase<TC, TT> operator + (EnumBase<TC, TT> value1, Int32 value2) { return new EnumBase<TC, TT>(true, value1.CmpValue, new EnumBase<TC, TT>(value2).CmpValue); }
public static EnumBase<TC, TT> operator + (EnumBase<TC, TT> value1, string value2) { return new EnumBase<TC, TT>(true, value1.CmpValue, new EnumBase<TC, TT>(value2).CmpValue); }
public static EnumBase<TC, TT> operator - (EnumBase<TC, TT> value1, EnumBase<TC, TT> value2) { return new EnumBase<TC, TT>(false, value1.CmpValue, value2.CmpValue); }
public static EnumBase<TC, TT> operator - (EnumBase<TC, TT> value1, TT value2) { return new EnumBase<TC, TT>(false, value1.CmpValue, new EnumBase<TC, TT>(value2).CmpValue); }
public static EnumBase<TC, TT> operator - (EnumBase<TC, TT> value1, Int32 value2) { return new EnumBase<TC, TT>(false, value1.CmpValue, new EnumBase<TC, TT>(value2).CmpValue); }
public static EnumBase<TC, TT> operator - (EnumBase<TC, TT> value1, string value2) { return new EnumBase<TC, TT>(false, value1.CmpValue, new EnumBase<TC, TT>(value2).CmpValue); }
public static bool operator ==(EnumBase<TC, TT> a, EnumBase<TC, TT> b)
{
// both of them are null, so equal
if (object.Equals(a, null) && object.Equals(b, null))
{
return true;
}
// one of them is null, so not equal
if (object.Equals(a, null) || object.Equals(b, null))
{
return false;
}
return (object.Equals(a.CmpValue.ToString(), b.CmpValue.ToString()));
}
public static bool operator !=(EnumBase<TC, TT> a, EnumBase<TC, TT> b)
{
// both of them is null, so equal
if (object.Equals(a, null) && object.Equals(b, null))
{
return false;
}
// one of them is null, so not equal
if (object.Equals(a, null) || object.Equals(b, null))
{
return true;
}
return (!object.Equals(a.CmpValue.ToString(), b.CmpValue.ToString()));
}
#endregion
#region Overrides
public override int GetHashCode()
{
return this.Value.CmpValue.GetHashCode();
}
public override string ToString()
{
return this.EnumName.ToString();
}
public override bool Equals(object obj)
{
if (obj is EnumBase<TC, TT>)
{
return (object.Equals(this.Value.CmpValue, ((EnumBase<TC, TT>)obj).CmpValue));
}
return false;
}
#endregion
public bool Contains(EnumBase<TC, TT> enumConst)
{
return this.Value.IsFlagSet(enumConst.DecValue);
}
public void MarkAll()
{
this.Value = InitEnumType(EnumOperator.DecValue, 0);
this.Value.InvertFlags();
this.Value.CalcDecValue();
}
public void Invert()
{
this.Value.InvertFlags();
this.Value.CalcDecValue();
}
}
}