using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IACommService4CSharp
{
    public static class DType
    {
        public const UInt32 Undefined  = 0u;   /* undefined type */
        public const UInt32 Boolean    = 1u;   /* boolean */
        public const UInt32 SByte      = 2u;   /* signed byte */
        public const UInt32 Byte       = 3u;   /* unsigned byte */
        public const UInt32 Int16      = 4u;   /* signed 16 bit integer */
        public const UInt32 UInt16     = 5u;   /* unsigned 16 bit integer */
        public const UInt32 Int32      = 6u;   /* signed 32 bit integer */
        public const UInt32 UInt32     = 7u;   /* unsigned 32 bit integer */
        public const UInt32 Int64      = 8u;   /* signed 64 bit integer */
        public const UInt32 UInt64     = 9u;   /* unsigned 64 bit integer */
        public const UInt32 Float      = 10u;  /* 32 bit single precision floating point */
        public const UInt32 Double     = 11u;  /* 64 bit double precision floating point */
        public const UInt32 String     = 12u;  /* UTF-8 string */
        public const UInt32 Complex    = 100u; /* complex type, such as Structure */
        public const UInt32 Custom     = 200u; /* custom type */
    };

    public class DataValue_t : IDisposable
    {
        private static Dictionary<uint, Type> m_dataTypeDic = new Dictionary<uint, Type>()
        {
            { DType.Boolean,   typeof(bool)    },
            { DType.SByte,     typeof(sbyte)   },
            { DType.Byte,      typeof(byte)    },
            { DType.Int16,     typeof(short)   },
            { DType.UInt16,    typeof(ushort)  },
            { DType.Int32,     typeof(int)     },
            { DType.UInt32,    typeof(uint)    },
            { DType.Int64,     typeof(long)    },
            { DType.UInt64,    typeof(ulong)   },
            { DType.Float,     typeof(float)   },
            { DType.Double,    typeof(double)  },
            { DType.String,    typeof(string)  },
            { DType.Custom,    typeof(sbyte[]) },
            { DType.Undefined, null            }
        };
        private IDataValue4CSharp m_value;
        private bool m_disposed = false;
        private bool m_isReference = false;

        public DataValue_t(uint dataType = DType.Undefined, uint[] dimensions = null)
        {
            m_value = DataValueFactory4CSharp.Create(dataType, dimensions);
            if (m_value is null)
                throw new IACommServiceException(ErrorCode.InvalidArgument);
        }
        public DataValue_t(object value)
        {
            if (value is null)
                throw new IACommServiceException(ErrorCode.InvalidArgument);

            if (value is DataValue_t)
            {
                m_value = DataValueFactory4CSharp.Create(DType.Undefined, null);
                if (m_value is null)
                    throw new IACommServiceException(ErrorCode.InternalError);

                CopyFrom((DataValue_t)value);
                return;
            }

            Type valueType = value.GetType();
            uint[] dimensions = null;
            if (value is Array)
            {
                var arrayValue = value as Array;
                dimensions = new uint[arrayValue.Rank];
                for (int index = 0; index < arrayValue.Rank; index++)
                {
                    dimensions[index] = (uint)arrayValue.GetLength(index);
                }
                valueType = valueType.GetElementType();
            }

            uint dataType = DType.Undefined;
            if (m_dataTypeDic.ContainsValue(valueType))
            {
                dataType = m_dataTypeDic.First(q => q.Value == valueType).Key;
            }
            else if (valueType.IsValueType && !valueType.IsPrimitive && !valueType.IsEnum)
            {
                dataType = DType.Complex;
            }
            else if (valueType.IsEnum)
            {
                dataType = DType.Int16;
            }
            else
            {
                throw new IACommServiceException(ErrorCode.InvalidArgument);
            }

            m_value = DataValueFactory4CSharp.Create(dataType, dimensions);
            Value = value;
        }
        //Internal use
        public DataValue_t(IDataValue4CSharp value)
        {
            m_value = value;
            if (null == m_value)
                throw new IACommServiceException(ErrorCode.InvalidArgument);
            m_isReference = true;
        }
        ~DataValue_t()
        {
            Dispose(false);
        }
        public uint CopyFrom(DataValue_t value)
        {
            if(value is null)
                return ErrorCode.InvalidArgument;

            return m_value.CopyFrom(value.m_value);
        }
        public uint CopyTo(ref DataValue_t value)
        {
            if (value is null)
                value = new DataValue_t();

            return m_value.CopyTo(value.m_value);
        }
        public uint GetArrayValue(ref uint[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref long[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref ulong[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref bool[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref sbyte[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref byte[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref short[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref ushort[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref int[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref float[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref string[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetArrayValue(ref double[] value)
        {
            return m_value.GetArrayValue(ref value);
        }
        public uint GetElement(uint[] indexes, ref DataValue_t value)
        {
            if (value is null)
                value = new DataValue_t();

            return m_value.GetElement(indexes, value.m_value);
        }
        public uint GetElement(uint index, ref DataValue_t value)
        {
            if (value is null)
                value = new DataValue_t();

            return m_value.GetElement(index, value.m_value);
        }
        public uint GetValue(ref bool value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref sbyte value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref byte value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref short value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref uint value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref int value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref long value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref ulong value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref float value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref double value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref string value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(ref sbyte[] value)
        {
            return m_value.GetValue(ref value);
        }
        public uint GetValue(string field, ref DataValue_t value)
        {
            if (value is null)
                value = new DataValue_t();

            return m_value.GetValue(field, value.m_value);
        }
        public uint GetValue(ref ushort value)
        {
            return m_value.GetValue(ref value);
        }
        public uint Reset(uint dataType = DType.Undefined, uint[] dimensions = null)
        {
            return m_value.Reset(dataType, dimensions);
        }
        public uint SetArrayValue(byte[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(bool[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(sbyte[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(short[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(float[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(int[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(uint[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(long[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(ulong[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(double[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(string[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetArrayValue(ushort[] value)
        {
            return m_value.SetArrayValue(value);
        }
        public uint SetElement(uint index, DataValue_t value)
        {
            if (value is null)
                return ErrorCode.InvalidArgument;

            return m_value.SetElement(index, value.m_value);
        }
        public uint SetElement(uint[] indexes, DataValue_t value)
        {
            if (value is null)
                return ErrorCode.InvalidArgument;

            return m_value.SetElement(indexes, value.m_value);
        }
        public uint SetValue(string field, DataValue_t value)
        {
            if (value is null)
                return ErrorCode.InvalidArgument;

            return m_value.SetValue(field, value.m_value);
        }
        public uint SetValue(sbyte[] value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(ulong value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(long value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(uint value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(short value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(ushort value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(byte value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(sbyte value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(bool value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(string value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(double value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(int value)
        {
            return m_value.SetValue(value);
        }
        public uint SetValue(float value)
        {
            return m_value.SetValue(value);
        }
        public object Get(Type valueType = null)
        {
            if (valueType is null && DataType == DType.Complex)
            {
                throw new IACommServiceException(ErrorCode.InvalidArgument);
            }

            if (valueType != null)
            {
                if (valueType == typeof(DataValue_t) || valueType.IsSubclassOf(typeof(DataValue_t)))
                {
                    object value = null;
                    if (valueType.Name == typeof(ArrayBase_t<>).Name)
                    {
                        if (!IsArray)
                            throw new IACommServiceException(ErrorCode.DataTypeMismatch);

                        value = Activator.CreateInstance(valueType, new object[] { new uint[] { 0 } });
                    }
                    else if (valueType.IsSubclassOf(typeof(ComplexBase_t)))
                    {
                        if (DataType != DType.Complex)
                            throw new IACommServiceException(ErrorCode.DataTypeMismatch);

                        value = Activator.CreateInstance(valueType);
                    }
                    else
                    {
                        value = Activator.CreateInstance(valueType, new object[] { DType.Undefined, null });
                    }

                    ((DataValue_t)value).CopyFrom(this);
                    return value;
                }

                if (IsArray)
                {
                    if (!valueType.IsArray || valueType.GetArrayRank() != Dimensions.Length)
                        throw new IACommServiceException(ErrorCode.DataTypeMismatch);

                    valueType = valueType.GetElementType();
                }

                if (valueType.IsEnum)
                {
                    if (DataType != DType.Int16)
                        throw new IACommServiceException(ErrorCode.DataTypeMismatch);
                }
                else if (valueType.IsValueType && !valueType.IsPrimitive)
                {
                    if (DataType != DType.Complex)
                        throw new IACommServiceException(ErrorCode.DataTypeMismatch);
                }
                else if (DataType == DType.Complex || m_dataTypeDic[DataType] != valueType)
                {
                    throw new IACommServiceException(ErrorCode.DataTypeMismatch);
                }
            }

            if (IsArray)
            {
                int[] tempDimensions = Array.ConvertAll<uint, int>(Dimensions, z => (int)z);

                Array arrayValue = null;
                switch (DataType)
                {
                    case DType.Boolean:
                        {
                            bool[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.SByte:
                        {
                            sbyte[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Byte:
                        {
                            byte[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Int16:
                        {
                            short[] tempArray = null;
                            GetArrayValue(ref tempArray);

                            if (valueType != null && valueType.IsEnum)
                            {
                                arrayValue = Array.CreateInstance(valueType, tempDimensions);

                                for (int index = 0; index < tempArray.Length; index++)
                                {
                                    int[] indexes = null;
                                    ConvertIndex(index, tempDimensions, ref indexes);
                                    arrayValue.SetValue(Enum.ToObject(valueType, tempArray[index]), indexes);
                                }
                            }
                            else
                            {
                                Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            }

                            break;
                        }
                    case DType.UInt16:
                        {
                            ushort[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Int32:
                        {
                            int[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.UInt32:
                        {
                            uint[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Int64:
                        {
                            long[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.UInt64:
                        {
                            ulong[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Float:
                        {
                            float[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Double:
                        {
                            double[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.String:
                        {
                            string[] tempArray = null;
                            GetArrayValue(ref tempArray);
                            Convert2MultiDimensionsArray(tempArray, tempDimensions, ref arrayValue);
                            break;
                        }
                    case DType.Complex:
                        {
                            arrayValue = Array.CreateInstance(valueType, tempDimensions);

                            DataValue_t elementValue = new DataValue_t();
                            for (uint index = 0; index < ArraySize; index++)
                            {
                                if (GetElement(index, ref elementValue) != ErrorCode.Good)
                                {
                                    elementValue.Dispose();
                                    throw new IACommServiceException(ErrorCode.InternalError);
                                }

                                var element = Convert2Struct(elementValue, valueType);
                                if (element is null)
                                {
                                    elementValue.Dispose();
                                    throw new IACommServiceException(ErrorCode.InvalidArgument);
                                }

                                int[] indexes = null;
                                ConvertIndex((int)index, tempDimensions, ref indexes);
                                arrayValue.SetValue(element, indexes);
                            }
                            elementValue.Dispose();

                            break;
                        }
                    default:
                        {
                            return null;
                        }
                }

                return arrayValue;
            }
            else
            {
                switch (DataType)
                {
                    case DType.Boolean:
                        {
                            bool value = false;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.SByte:
                        {
                            sbyte value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Byte:
                        {
                            byte value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Int16:
                        {
                            short value = 0;
                            GetValue(ref value);
                            if (valueType != null && valueType.IsEnum)
                            {
                                return Enum.ToObject(valueType, value);
                            }
                            else
                            {
                                return value;
                            }
                        }
                    case DType.UInt16:
                        {
                            ushort value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Int32:
                        {
                            int value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.UInt32:
                        {
                            uint value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Int64:
                        {
                            long value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.UInt64:
                        {
                            ulong value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Float:
                        {
                            float value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Double:
                        {
                            double value = 0;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.String:
                        {
                            string value = null;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Custom:
                        {
                            sbyte[] value = null;
                            GetValue(ref value);
                            return value;
                        }
                    case DType.Complex:
                        {
                            var value = Convert2Struct(this, valueType);
                            if (value is null)
                                throw new IACommServiceException(ErrorCode.DataTypeMismatch);

                            return value;
                        }
                    default:
                        {
                            return null;
                        }
                }
            }
        }
        public uint Set(object value)
        {
            if (value is null)
                return ErrorCode.InvalidArgument;

            if (value is DataValue_t)
            {
                if (DataType != ((DataValue_t)value).DataType ||
                    Dimensions.ToString() != ((DataValue_t)value).Dimensions.ToString())
                    return ErrorCode.DataTypeMismatch;

                CopyFrom((DataValue_t)value);
                return ErrorCode.Good;
            }

            Type valueType = value.GetType();
            if (IsArray)
            {
                if (!valueType.IsArray)
                    return ErrorCode.DataTypeMismatch;

                valueType = valueType.GetElementType();
            }

            if (valueType.IsEnum)
            {
                if (DataType != DType.Int16)
                    return ErrorCode.DataTypeMismatch;
            }
            else if (valueType.IsValueType && !valueType.IsPrimitive)
            {
                if (DataType != DType.Complex)
                    return ErrorCode.DataTypeMismatch;
            }
            else if (DataType == DType.Complex || m_dataTypeDic[DataType] != valueType)
            {
                return ErrorCode.DataTypeMismatch;
            }

            if (IsArray)
            {
                var tempValue = value as Array;
                int[] tempDimensions = Array.ConvertAll<uint, int>(Dimensions, z => (int)z);

                if (tempValue.Rank != tempDimensions.Length)
                    return ErrorCode.DataTypeMismatch;

                for (int index = 0; index < tempValue.Rank; index++)
                {
                    if (tempValue.GetLength(index) != tempDimensions[index])
                        return ErrorCode.DataTypeMismatch;
                }

                if (valueType.IsEnum)
                {
                    short[] arrayValue = new short[tempValue.Length];
                    for (int index = 0; index < arrayValue.Length; index++)
                    {
                        int[] indexes = null;
                        ConvertIndex(index, tempDimensions, ref indexes);
                        arrayValue[index] = Convert.ToInt16(tempValue.GetValue(indexes));
                    }

                    return SetArrayValue(arrayValue);
                }
                else if (DataType == DType.Complex)
                {
                    for (uint index = 0; index < ArraySize; index++)
                    {
                        int[] indexes = null;
                        ConvertIndex((int)index, tempDimensions, ref indexes);

                        DataValue_t element = new DataValue_t(DType.Complex);
                        var structElement = tempValue.GetValue(indexes);

                        var status = Convert2DataValue(structElement, element);
                        if (ErrorCode.Good == status)
                            status = SetElement(index, element);

                        element.Dispose();
                        if (status != ErrorCode.Good)
                            return status;
                    }

                    return ErrorCode.Good;
                }
                else
                {
                    switch (DataType)
                    {
                        case DType.Boolean:
                            {
                                bool[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.SByte:
                            {
                                sbyte[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.Byte:
                            {
                                byte[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.Int16:
                            {
                                short[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.UInt16:
                            {
                                ushort[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.Int32:
                            {
                                int[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.UInt32:
                            {
                                uint[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.Int64:
                            {
                                long[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.UInt64:
                            {
                                ulong[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.Float:
                            {
                                float[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.Double:
                            {
                                double[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        case DType.String:
                            {
                                string[] arrayValue = null;
                                Convert2SingleDimensionArray(value as Array, tempDimensions, ref arrayValue);
                                return SetArrayValue(arrayValue);
                            }
                        default:
                            {
                                return ErrorCode.DataTypeMismatch;
                            }
                    }
                }
            }
            else
            {
                if (valueType.IsEnum)
                {
                    return SetValue(Convert.ToInt16(value));
                }
                else if (DataType == DType.Complex)
                {
                    Reset(DType.Complex);
                    return Convert2DataValue(value, this);
                }
                else
                { 
                    switch (DataType)
                    {
                        case DType.Boolean:
                            return SetValue((bool)value);
                        case DType.SByte:
                            return SetValue((sbyte)value);
                        case DType.Byte:
                            return SetValue((byte)value);
                        case DType.Int16:
                            return SetValue((short)value);
                        case DType.UInt16:
                            return SetValue((ushort)value);
                        case DType.Int32:
                            return SetValue((int)value);
                        case DType.UInt32:
                            return SetValue((uint)value);
                        case DType.Int64:
                            return SetValue((long)value);
                        case DType.UInt64:
                            return SetValue((ulong)value);
                        case DType.Float:
                            return SetValue((float)value);
                        case DType.Double:
                            return SetValue((double)value);
                        case DType.String:
                            return SetValue((string)value);
                        case DType.Custom:
                            return SetValue((sbyte[])value);
                        default:
                            return ErrorCode.DataTypeMismatch;
                    }
                }
            }
        }
        public uint DataType
        {
            get
            {
                return m_value.DataType();
            }
        }
        public bool IsArray
        {
            get
            {
                return m_value.IsArray();
            }
        }
        public uint ArraySize
        {
            get
            {
                return m_value.ArraySize();
            }

        }
        public uint[] Dimensions
        {
            get
            {
                uint[] dimensions = null;
                m_value.GetDimensions(ref dimensions);
                return dimensions;
            }
        }
        public object Value
        {
            get
            {
                if (DataType == DType.Complex)
                    throw new IACommServiceException(ErrorCode.NotSupported);

                return Get();
            }

            set
            {
                Set(value);
            }
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposeManaged)
        {
            if (!m_disposed)
            {
                if (disposeManaged)
                {
                    //do nothing
                }

                if (!m_isReference)
                    DataValueFactory4CSharp.Destroy(m_value);

                m_value = null;

                m_disposed = true;
            }
        }
        //Internal use
        public IDataValue4CSharp Internal
        {
            get
            {
                return m_value;
            }
        }
        private uint Convert2SingleDimensionArray<T>(Array sourceArray, int[] dimensions, ref T[] targetArray)
        {
            if (null == sourceArray)
                return ErrorCode.InvalidArgument;

            targetArray = new T[sourceArray.Length];
            for (int index = 0; index < targetArray.Length; index++)
            {
                int[] indexes = null;
                ConvertIndex(index, dimensions, ref indexes);

                targetArray[index] = (T)sourceArray.GetValue(indexes);
            }

            return ErrorCode.Good;
        }
        private uint Convert2MultiDimensionsArray<T>(T[] sourceArray, int[] dimensions, ref Array targetArray)
        {
            if (null == sourceArray)
                return ErrorCode.InvalidArgument;

            targetArray = Array.CreateInstance(typeof(T), dimensions);

            for (int index = 0; index < sourceArray.Length; index++)
            {
                int[] indexes = null;
                ConvertIndex(index, dimensions, ref indexes);
                targetArray.SetValue(sourceArray[index], indexes);
            }

            return ErrorCode.Good;
        }
        private uint ConvertIndex(int index, int[] dimensions, ref int[] indexes)
        {
            if (null == dimensions)
                return ErrorCode.InvalidArgument;

            indexes = new int[dimensions.Length];
            for (int n = 0; n < indexes.Length; n++)
            {
                int curLength = (int)dimensions[n];
                int lengths = 1;
                for (int m = n + 1; m < indexes.Length; m++)
                {
                    lengths *= (int)dimensions[m];
                }

                indexes[n] = (index / lengths) % curLength;
            }

            return ErrorCode.Good;
        }
        private object Convert2Struct(DataValue_t value, Type structType)
        {
            object retValue = null;
            if (structType.IsValueType && !structType.IsPrimitive && !structType.IsEnum)
            {
                retValue = Activator.CreateInstance(structType);

                DataValue_t fieldValue = new DataValue_t();
                var fieldInfos = structType.GetFields();
                foreach (var fieldInfo in fieldInfos)
                {
                    var status = value.GetValue(fieldInfo.Name, ref fieldValue);
                    if (status != ErrorCode.Good)
                    {
                        fieldValue.Dispose();
                        throw new IACommServiceException(ErrorCode.InvalidArgument);
                    }

                    object field = null;
                    try
                    {
                        field = fieldValue.Get(fieldInfo.FieldType);
                    }
                    catch
                    {
                        field = null;
                    }

                    fieldInfo.SetValue(retValue, field);
                }
                fieldValue.Dispose();
            }

            return retValue;
        }
        private uint Convert2DataValue(object structValue, DataValue_t value)
        {
            var structType = structValue.GetType();

            if (structType.IsValueType && !structType.IsPrimitive && !structType.IsEnum)
            {
                var fieldInfos = structType.GetFields();
                foreach (var fieldInfo in fieldInfos)
                {
                    object field = fieldInfo.GetValue(structValue);
                    DataValue_t fieldValue = new DataValue_t(field);

                    var status = value.SetValue(fieldInfo.Name, fieldValue);

                    fieldValue.Dispose();

                    if (status != ErrorCode.Good)
                        return ErrorCode.InvalidArgument;
                }

                return ErrorCode.Good;
            }
            else
            {
                return ErrorCode.DataTypeMismatch;
            }
        }
    }
}
