//                           UNCLASSIFIED
/*-------------------------------------------------------------------------
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
COMPANY.

THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
GOVERNMENT.

UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
-------------------------------------------------------------------------*/

using Raytheon.Common;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace BitMeasurementManagerLib
{
   /// <summary>
   /// This class implements a message that can be put on a communication interface
   /// </summary>
   public class BitConfigurableMessage
   {
      #region PublicClassMembers
      public enum DataItemType
      {
         FLOAT,
         UINT,
         UINT_HEX,
         USHORT_HEX,
         USHORT,
         BYTE_HEX,
         BYTE_ARRAY_HEX,
         DOUBLE,
         ULONG,
         ULONG_HEX,
         BITS
      }
      #endregion

      #region PrivateClassMembers  
      public List<IConfigurableDataItem> _dataItems;
      public Dictionary<string, int> _byteArrayCount;
      public Dictionary<string, int> _bitCount;
      private string _messageName;
      private uint _entireMsgLen;
      private uint _messageId;
      private uint _rspMessageId;
      #endregion

      #region PublicFuctions

      /// <summary>
      /// Copy constructor
      /// </summary>
      /// <param name="rhs">The object to copy</param>
      public BitConfigurableMessage(BitConfigurableMessage rhs)
      {
         // copy over the basic types
         _messageId = rhs._messageId;
         _rspMessageId = rhs._rspMessageId;
         _messageName = String.Copy(rhs._messageName);

         // _entireMsgLen will get set when we add the data items
         _entireMsgLen = 0;

         // initialize the objects
         _dataItems = new List<IConfigurableDataItem>();
         _byteArrayCount = new Dictionary<string, int>();
         _bitCount = new Dictionary<string, int>();

         // copy the data items over
         foreach (IConfigurableDataItem dataItem in rhs._dataItems)
         {
            AddDataItem(dataItem.GetDataItemName(), dataItem.GetDataItemType(), dataItem.GetNumDataItems(), dataItem.GetDefaultValueStr());
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="messageId"></param>
      /// <param name="rspMessageId"></param>
      /// <param name="messageName"></param>
      public BitConfigurableMessage(uint messageId, uint rspMessageId, string messageName)
      {
         _messageId = messageId;

         _rspMessageId = rspMessageId;

         _messageName = messageName;

         _entireMsgLen = 0;

         _dataItems = new List<IConfigurableDataItem>();

         _byteArrayCount = new Dictionary<string, int>();

         _bitCount = new Dictionary<string, int>();
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public uint GetMessageId()
      {
         return _messageId;
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public uint GetMessageRspId()
      {
         return _rspMessageId;
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="dataItemName"></param>
      /// <param name="dataItemType"></param>
      /// <param name="numItems"></param>
      /// <param name="defaultValue"></param>
      public void AddDataItem(string dataItemName, DataItemType dataItemType, int numItems, string defaultValue)
      {
         if (numItems < 1)
         {
            throw new Exception("BitConfigurableMessage::AddDataItem() - numItems is not valid: " + numItems + ", data item name is: " + dataItemName);
         }

         if (numItems > 1 && (dataItemType != DataItemType.BYTE_ARRAY_HEX && dataItemType != DataItemType.BITS))
         {
            throw new Exception("BitConfigurableMessage::AddDataItem() - numItems greater than one only allowed for hex byte arrays and BITs: " + numItems + ", data item name is: " + dataItemName);
         }

         if (dataItemType == DataItemType.UINT)
         {
            uint value = Convert.ToUInt32(defaultValue);
            BitConfigurableMessageDataItem<uint> dataItem = new BitConfigurableMessageDataItem<uint>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(4 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.UINT_HEX)
         {
            uint value = Convert.ToUInt32(defaultValue, 16);
            BitConfigurableMessageDataItem<uint> dataItem = new BitConfigurableMessageDataItem<uint>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(4 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.FLOAT)
         {
            float value = (float)Convert.ToDouble(defaultValue);
            BitConfigurableMessageDataItem<float> dataItem = new BitConfigurableMessageDataItem<float>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(4 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.USHORT)
         {
            ushort value = Convert.ToUInt16(defaultValue);
            BitConfigurableMessageDataItem<ushort> dataItem = new BitConfigurableMessageDataItem<ushort>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(2 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.USHORT_HEX)
         {
            ushort value = Convert.ToUInt16(defaultValue, 16);
            BitConfigurableMessageDataItem<ushort> dataItem = new BitConfigurableMessageDataItem<ushort>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(2 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.DOUBLE)
         {
            double value = Convert.ToDouble(defaultValue);
            BitConfigurableMessageDataItem<double> dataItem = new BitConfigurableMessageDataItem<double>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(8 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.ULONG)
         {
            ulong value = Convert.ToUInt64(defaultValue);
            BitConfigurableMessageDataItem<ulong> dataItem = new BitConfigurableMessageDataItem<ulong>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(8 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.ULONG_HEX)
         {
            ulong value = Convert.ToUInt64(defaultValue, 16);
            BitConfigurableMessageDataItem<ulong> dataItem = new BitConfigurableMessageDataItem<ulong>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(8 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.BYTE_HEX)
         {
            byte value = Convert.ToByte(defaultValue, 16);
            BitConfigurableMessageDataItem<byte> dataItem = new BitConfigurableMessageDataItem<byte>(dataItemName, dataItemType, value, defaultValue, numItems);
            _entireMsgLen += (uint)(1 * numItems);
            _dataItems.Add(dataItem);
         }
         else if (dataItemType == DataItemType.BITS)
         {
            if (numItems > 8)
            {
               throw new Exception("BitConfigurableMessage::AddDataItem() - trying to add bit field: " + dataItemName + " that has more than 8 bits, bit fields are required to be less than 8 bits at this time");
            }

            // query how many bit fields have been added
            // use this later when updating the number of bytes in the message
            int totalBitPrevCount = 0;
            foreach (KeyValuePair<string, int> entry in _bitCount)
            {
               totalBitPrevCount += entry.Value;
            }


            //intention integer division
            uint numBytesPrevAdded = (uint)(totalBitPrevCount / 8);

            int totalBitPrevCountRemander = totalBitPrevCount % 8;

            // if remander is not 0, bump up the byte count by 1
            if (totalBitPrevCountRemander != 0)
            {
               numBytesPrevAdded++;
            }

            // convert value to a byte and create the data item
            defaultValue = defaultValue.Replace("0b", "");
            defaultValue = defaultValue.Replace("0B", "");
            byte value = Convert.ToByte(defaultValue, 2);
            BitConfigurableMessageDataItem<byte> dataItem = new BitConfigurableMessageDataItem<byte>(dataItemName, dataItemType, value, defaultValue, numItems);
            _dataItems.Add(dataItem);

            // store the number of bits for this items
            _bitCount[dataItemName.ToUpper()] = numItems;

            // now that we updated the bit fields, query how many bit fields there are
            int totalBitCount = 0;
            foreach (KeyValuePair<string, int> entry in _bitCount)
            {
               totalBitCount += entry.Value;
            }

            // intentional integer division
            uint numBytesToAdd = (uint)(totalBitCount / 8);
            int totalBitCountRemander = totalBitCount % 8;

            // if remander is not 0, bump up the byte count by 1
            if (totalBitCountRemander != 0)
            {
               numBytesToAdd++;
            }

            // increment the message length we crossed a byte boundary with the total number of bits
            _entireMsgLen += numBytesToAdd - numBytesPrevAdded;
         }
         else if (dataItemType == DataItemType.BYTE_ARRAY_HEX)
         {
            byte value = Convert.ToByte(defaultValue, 16);

            byte[] data = new byte[numItems];

            for (int i = 0; i < numItems; i++)
            {
               data[i] = value;
            }

            BitConfigurableMessageDataItem<Array> dataItem = new BitConfigurableMessageDataItem<Array>(dataItemName, dataItemType, data, defaultValue, numItems);

            _dataItems.Add(dataItem);

            _entireMsgLen += (uint)(1 * numItems);

            _byteArrayCount[dataItemName.ToUpper()] = numItems;
         }
         else
         {
            throw new Exception("BitConfigurableMessage::AddDataItem() - Unsupported data item type: " + dataItemType.ToString());
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="pData"></param>
      public void Format(IntPtr pData)
      {
         IntPtr pDataLocation = pData;

         // should we byte swap
         bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();

         // format the data
         List<IConfigurableDataItem> formattedData = _dataItems;

         for (int i = 0; i < formattedData.Count; i++)
         {
            IConfigurableDataItem dataItem = _dataItems[i];
            DataItemType itemType = dataItem.GetDataItemType();
            string itemName = dataItem.GetDataItemName();
            object itemValue = dataItem.Data;

            int dataItemSize = 0;

            if (itemValue is float)// if (itemType == DataItemType.FLOAT)
            {
               float data = (float)itemValue;

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(data);
               }
               else
               {
                  itemValue = data;
               }

               dataItemSize = 4;

               //copy data from our data items, info the buffer
               Marshal.StructureToPtr(itemValue, pDataLocation, true);
            }
            else if (itemValue is uint)
            {
               uint data = (uint)itemValue;

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(data);
               }
               else
               {
                  itemValue = data;
               }

               dataItemSize = 4;

               //copy data from our data items, info the buffer
               Marshal.StructureToPtr(itemValue, pDataLocation, true);
            }
            else if (itemValue is ushort)
            {
               ushort data = (ushort)itemValue;

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(data);
               }
               else
               {
                  itemValue = data;
               }

               dataItemSize = 2;

               //copy data from our data items, info the buffer
               Marshal.StructureToPtr(itemValue, pDataLocation, true);
            }
            else if (itemValue is byte)
            {
               // handle the case where we stored an array of BITS as a byte
               if (itemType == DataItemType.BITS)
               {
                  // grab the value of the first bit item
                  byte totalBitItemValue = (byte)itemValue;

                  // queue up the rest of the BITs to the next byte boundary
                  int totalBitsProcessed = dataItem.GetNumDataItems();

                  for (int j = i + 1; totalBitsProcessed < 8; j++)
                  {
                     // grab the next data items
                     IConfigurableDataItem bitDataItem = _dataItems[j];
                     DataItemType bitItemType = bitDataItem.GetDataItemType();

                     // the next item should be BITS
                     if (bitItemType != DataItemType.BITS)
                     {
                        throw new Exception("BitConfigurableMessage::Format() - Bit fields not consecutive out to byte boundary for msg ID: " + _messageId.ToString("X8"));
                     }

                     int bitItemNumBites = bitDataItem.GetNumDataItems();
                     byte bitItemValue = (byte)bitDataItem.Data;
                     uint mask = (uint)((1 << bitItemNumBites) - 1) << totalBitsProcessed;

                     // mask in the next bit value
                     byte valueToMaskIn = (byte)((bitItemValue << totalBitsProcessed) & mask);
                     totalBitItemValue = (byte)(totalBitItemValue | valueToMaskIn);

                     // increment the bit counter
                     totalBitsProcessed += bitItemNumBites;

                     // increment the outer loop counter since we just processed it
                     i++;
                  }

                  // double check that we are on a byte boundary
                  //int byteBoundaryRemainder = totalBitsProcessed % 8;
                  if (totalBitsProcessed != 8)
                  {
                     throw new Exception("BitConfigurableMessage::Format() - Bit fields not equal to 8 for msg ID: " + _messageId.ToString("X8"));
                  }

                  dataItemSize = 1;

                  // hold onto the total bit item value
                  itemValue = (byte)totalBitItemValue;

                  //copy data from our data items, info the buffer
                  Marshal.StructureToPtr(itemValue, pDataLocation, true);
               }
               else
               {
                  itemValue = (byte)itemValue;

                  dataItemSize = 1;

                  //copy data from our data items, info the buffer
                  Marshal.StructureToPtr(itemValue, pDataLocation, true);
               }
            }
            else if (itemValue is double)
            {
               itemValue = (double)itemValue;

               dataItemSize = 8;

               //copy data from our data items, info the buffer
               Marshal.StructureToPtr(itemValue, pDataLocation, true);
            }
            else if (itemValue is ulong)
            {
               itemValue = (ulong)itemValue;

               dataItemSize = 8;

               //copy data from our data items, info the buffer
               Marshal.StructureToPtr(itemValue, pDataLocation, true);
            }
            else if (itemValue is Array)
            {
               IEnumerable en = (IEnumerable)itemValue;
               byte[] arrayTemp = en.OfType<byte>().ToArray();
               dataItemSize = arrayTemp.Length;
               Marshal.Copy(arrayTemp, 0, pDataLocation, dataItemSize);
            }
            else
            {
               throw new Exception("BitConfigurableMessage::Format() - Unsupported data item type: " + itemType.ToString());
            }

            // increment the pointer
            pDataLocation = IntPtr.Add(pDataLocation, dataItemSize);
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="dataItemName"></param>
      /// <returns></returns>
      public byte[] GetDataItemByName_ByteArray(string dataItemName)
      {
         for (int i = 0; i < _dataItems.Count; i++)
         {
            if (_dataItems[i].GetDataItemName().ToUpper() == dataItemName.ToUpper())
            {
               if (_dataItems[i].GetDataItemType() != DataItemType.BYTE_ARRAY_HEX)
               {
                  throw new Exception("BitConfigurableMessage::GetDataItemByName_ByteArray() - item was not a byte array: " + dataItemName);
               }

               IEnumerable en = (IEnumerable)_dataItems[i].Data;
               byte[] dataToReturn = en.OfType<byte>().ToArray();
               return dataToReturn;
            }
         }

         throw new Exception("BitConfigurableMessage::GetDataItemByName_ByteArray() - Could not find data item: " + dataItemName);
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="dataItemName"></param>
      /// <returns></returns>
      public T GetDataItemByName<T>(string dataItemName)
      {
         for (int i = 0; i < _dataItems.Count; i++)
         {
            if (_dataItems[i].GetDataItemName().ToUpper() == dataItemName.ToUpper())
            {
               T value = (T)Convert.ChangeType(_dataItems[i].Data, typeof(T));
               return value;
            }
         }

         throw new Exception("BitConfigurableMessage::GetDataItemByName() - Could not find data item: " + dataItemName);
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public uint GetEntireMsgLength()
      {
         return _entireMsgLen;
      }


      /// <summary>
      /// 
      /// </summary>
      /// <param name="pData"></param>
      public void Parse(IntPtr pData)
      {
         // should we byte swap
         bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();

         IntPtr pMsgDataPtr = pData;

         for (int i = 0; i < _dataItems.Count; i++)
         {
            IConfigurableDataItem item = _dataItems[i];

            object itemData = item.Data;

            if (itemData is float)
            {
               float itemValue = 0;

               unsafe
               {
                  float* pFloatItem = (float*)pMsgDataPtr;

                  itemValue = *pFloatItem;
               }

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(itemValue);
               }

               item.Data = itemValue;

               _dataItems[i] = item;

               pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 4);
            }
            else if (itemData is uint)
            {
               uint itemValue = 0;

               unsafe
               {
                  uint* pUInt32Item = (uint*)pMsgDataPtr;

                  itemValue = *pUInt32Item;
               }

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(itemValue);
               }

               item.Data = itemValue;

               _dataItems[i] = item;

               pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 4);
            }
            else if (itemData is ushort)
            {
               ushort itemValue = 0;

               unsafe
               {
                  ushort* pUInt16Item = (ushort*)pMsgDataPtr;

                  itemValue = *pUInt16Item;
               }

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(itemValue);
               }

               item.Data = itemValue;

               _dataItems[i] = item;

               pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 2);
            }
            else if (itemData is double)
            {
               double itemValue = 0;

               unsafe
               {
                  double* pDoubleItem = (double*)pMsgDataPtr;

                  itemValue = *pDoubleItem;
               }

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(itemValue);
               }

               item.Data = itemValue;

               _dataItems[i] = item;

               pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 8);
            }
            else if (itemData is ulong)
            {
               ulong itemValue = 0;

               unsafe
               {
                  ulong* pUlongItem = (ulong*)pMsgDataPtr;

                  itemValue = *pUlongItem;
               }

               if (shallWeSwap == true)
               {
                  itemValue = Util.Swap(itemValue);
               }

               item.Data = itemValue;

               _dataItems[i] = item;

               pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 8);
            }
            else if (itemData is byte)
            {
               // handle the case where we are storing bit arrays as a byte
               if (item.GetDataItemType() == DataItemType.BITS)
               {
                  // grab the value of the first bit item
                  byte rawDataValue = 0;

                  // Grab the byte from the msg pointer
                  unsafe
                  {
                     byte* pUInt8Item = (byte*)pMsgDataPtr;

                     rawDataValue = *pUInt8Item;
                  }

                  // set the first data item
                  uint mask = (uint)((1 << item.GetNumDataItems()) - 1);
                  item.Data = (byte)(rawDataValue & mask);
                  _dataItems[i] = item;
                  int totalBitsProcessed = item.GetNumDataItems();

                  // set the rest of the data items
                  for (int j = i + 1; totalBitsProcessed < 8; j++)
                  {
                     IConfigurableDataItem bitDataItem = _dataItems[j];

                     DataItemType bitItemType = bitDataItem.GetDataItemType();

                     // the next item should be BITS
                     if (bitItemType != DataItemType.BITS)
                     {
                        throw new Exception("BitConfigurableMessage::Parse() - Bit fields not consecutive out to byte boundary for msg ID: " + _messageId.ToString("X8"));
                     }

                     // shift the data into the beggining of the byte and mask out the other bits
                     mask = (uint)((1 << bitDataItem.GetNumDataItems()) - 1);
                     bitDataItem.Data = (byte)((rawDataValue >> totalBitsProcessed) & mask);
                     _dataItems[j] = bitDataItem;

                     // increment the bit counter
                     totalBitsProcessed += bitDataItem.GetNumDataItems();

                     // increment the outer loop counter since we just processed it
                     i++;
                  }

                  // double check that we are on a byte boundary
                  //int byteBoundaryRemainder = totalBitsProcessed % 8;
                  if (totalBitsProcessed != 8)
                  {
                     throw new Exception("BitConfigurableMessage::Parse() - Bit fields not on byte boundary forequal to 8 msg ID: " + _messageId.ToString("X8"));
                  }

                  pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 1);
               }
               else
               {
                  byte itemValue = 0;

                  unsafe
                  {
                     byte* pUInt8Item = (byte*)pMsgDataPtr;

                     itemValue = *pUInt8Item;
                  }

                  item.Data = itemValue;

                  _dataItems[i] = item;

                  pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 1);
               }
            }
            else if (itemData is Array)
            {
               int numBytes = _byteArrayCount[item.GetDataItemName().ToUpper()];
               byte[] data = new byte[numBytes];

               unsafe
               {
                  for (int byteCounter = 0; byteCounter < numBytes; byteCounter++)
                  {
                     byte* pUInt8Item = (byte*)pMsgDataPtr;
                     data[byteCounter] = *pUInt8Item;
                     pMsgDataPtr = IntPtr.Add(pMsgDataPtr, 1);
                  }
               }

               item.Data = data;

               _dataItems[i] = item;
            }
            else
            {
               throw new Exception("BitConfigurableMessage::Parse() - Unsupported data item type: " + item.GetDataItemType().ToString());
            }
         }
      }

      /// <summary>
      /// Set the params of the message. 
      /// This function will iterate over the list of params passed in and sequentially set the data items in the message starting at the data item at index 0
      /// </summary>
      /// <param name="messageParams">an array of params</param>
      public void SetParams(params object[] messageParams)
      {
         if (messageParams.Length > _dataItems.Count)
         {
            throw new Exception("BitConfigurableMessage::SetParams() - number of supplied parameters: " + messageParams.Length.ToString() + ", is larger than the number of parameters in the definition file: " + _dataItems.Count.ToString());
         }

         for (int i = 0; i < messageParams.Length; i++)
         {
            IConfigurableDataItem item = _dataItems[i];

            object itemData = item.Data;

            if (itemData is uint)
            {
               item.Data = Convert.ToUInt32(messageParams[i]);
               _dataItems[i] = item;
            }
            else if (itemData is float)
            {
               item.Data = Convert.ToDouble(messageParams[i]);
               _dataItems[i] = item;
            }
            else if (itemData is ushort)
            {
               item.Data = Convert.ToUInt16(messageParams[i]);
               _dataItems[i] = item;
            }
            else if (itemData is double)
            {
               item.Data = Convert.ToDouble(messageParams[i]);
               _dataItems[i] = item;
            }
            else if (itemData is ulong)
            {
               item.Data = Convert.ToUInt64(messageParams[i]);
               _dataItems[i] = item;
            }
            else if (itemData is byte)
            {
               item.Data = Convert.ToByte(messageParams[i]);
               _dataItems[i] = item;

               // doesnt matter if it is of types BITs or not, the configurable data item already knows
               /*if (item.GetDataItemType() == DataItemType.BITS)
               {
                  item.Data = Convert.ToByte(messageParams[i]);
                  _dataItems[i] = item;
               }
               else
               {
                  item.Data = Convert.ToByte(messageParams[i]);
                  _dataItems[i] = item;
               }*/
            }
            else if (itemData is Array)
            {
               // convert object to byte array
               IEnumerable en = (IEnumerable)messageParams[i];
               byte[] data = en.OfType<byte>().ToArray();
               item.Data = data;
               _dataItems[i] = item;
            }
            else
            {
               throw new Exception("BitConfigurableMessage::SetParams() - unknown type");
            }
         }
      }

      /// <summary>
      /// 
      /// </summary>
      /// <returns></returns>
      public override string ToString()
      {
         string dataToReturn = "Description: " + _messageName + "\r\n";
         dataToReturn += "Payload Data:\r\n";

         for (int i = 0; i < _dataItems.Count; i++)
         {
            IConfigurableDataItem dataItem = _dataItems[i];
            DataItemType itemType = dataItem.GetDataItemType();
            string itemName = dataItem.GetDataItemName();
            object itemValue = dataItem.Data;

            if (itemValue is uint)
            {
               if (itemValue == null)
               {
                  dataToReturn += "   " + itemName + ":Not Set\r\n";
               }
               else
               {
                  uint data = (uint)itemValue;

                  dataToReturn += "   " + itemName + ":" + "0x" + data.ToString("X8") + "\r\n";
               }
            }
            else if (itemValue is ushort)
            {
               if (itemValue == null)
               {
                  dataToReturn += "   " + itemName + ":Not Set\r\n";
               }
               else
               {
                  ushort data = (ushort)itemValue;

                  dataToReturn += "   " + itemName + ":" + "0x" + data.ToString("X4") + "\r\n";
               }
            }
            else if (itemValue is double)
            {
               if (itemValue == null)
               {
                  dataToReturn += "   " + itemName + ":Not Set\r\n";
               }
               else
               {
                  double data = (double)itemValue;

                  dataToReturn += "   " + itemName + ":" + data + "\r\n";
               }
            }
            else if (itemValue is ulong)
            {
               if (itemValue == null)
               {
                  dataToReturn += "   " + itemName + ":Not Set\r\n";
               }
               else
               {
                  ulong data = (ulong)itemValue;

                  dataToReturn += "   " + itemName + ":" + data + "\r\n";
               }
            }
            else if (itemValue is byte)
            {
               if (itemValue == null)
               {
                  dataToReturn += "   " + itemName + ":Not Set\r\n";
               }
               else
               {
                  if (itemType == DataItemType.BITS)
                  {
                     byte data = (byte)itemValue;

                     string binString = Convert.ToString(data, 2).PadLeft(dataItem.GetNumDataItems(), '0');

                     dataToReturn += "   " + itemName + ":" + "0b" + binString + "\r\n";
                  }
                  else
                  {
                     byte data = (byte)itemValue;

                     dataToReturn += "   " + itemName + ":" + "0x" + data.ToString("X2") + "\r\n";
                  }
               }
            }
            else if (itemValue is Array)
            {
               string arrayDataStr = "";

               if (itemValue == null)
               {
                  arrayDataStr += "   " + itemName + ":Not Set" + "\r\n";
               }
               else
               {
                  IEnumerable en = (IEnumerable)itemValue;
                  byte[] arrayTemp = en.OfType<byte>().ToArray();
                  StringBuilder hex = new StringBuilder(arrayTemp.Length * 2);
                  foreach (byte b in arrayTemp)
                     hex.AppendFormat("{0:x2}", b);

                  arrayDataStr += "   " + itemName + ":" + hex.ToString() + "\r\n";
               }

               dataToReturn += arrayDataStr;
            }
            else if (itemValue is float)
            {
               if (itemValue == null)
               {
                  dataToReturn += "   " + itemName + ":Not Set\r\n";
               }
               else
               {
                  float data = (float)itemValue;

                  dataToReturn += "   " + itemName + ":" + data + "\r\n";
               }
            }
            else
            {
               dataToReturn += "   " + itemName + ":" + "UNKNOWN TYPE:" + itemType + "\r\n";
            }
         }

         return dataToReturn + "\r\n";

      }
      #endregion
   }
}