//                           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;

namespace BitMeasurementManagerLib
{
   /// <summary>
   /// This class implements a message header that is used by the BitConfigurableMessage
   /// </summary>
   public static class BitConfigurableMessageHeader
   {
      #region PrivateClassMembers

      #endregion

      #region PublicFuctions

      /// <summary>
      /// 
      /// </summary>
      /// <param name="pData"></param>
      /// <returns></returns>
      public static uint GetMessageId(IntPtr pData, uint numBytesInPdata)
      {
         return GetCmdMessageId(pData, numBytesInPdata);
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="pData"></param>
      /// <param name="isSecondaryIdUsed"></param>
      /// <returns></returns>
      public static uint GetSecondaryMessageId(IntPtr pData, uint numBytesInPdata, out bool isSecondaryIdUsed)
      {
         return GetSecondaryCmdMessageId(pData, numBytesInPdata, out isSecondaryIdUsed);
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="pData"></param>
      /// <param name="isSecondaryIdUsed"></param>
      /// <returns></returns>
      private static uint GetSecondaryCmdMessageId(IntPtr pData, uint numBytesInPdata, out bool isSecondaryIdUsed)
      {
         unsafe
         {
            isSecondaryIdUsed = false;

            bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();

            BitMsgEndianControl.HeaderDef headerDef = BitMsgEndianControl.Instance().GetHeaderDef();

            // is there enough data?
            if (numBytesInPdata <= headerDef.secondaryMsgIdByteLocation + headerDef.secondaryMsgIdDataLen)
            {
               ErrorLogger.Instance().Write("BitConfigurableMessageHeader::GetSecondaryCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.secondaryMsgIdByteLocation + headerDef.secondaryMsgIdDataLen).ToString() + " for a header", ErrorLogger.LogLevel.INFO);
               throw new Exception("BitConfigurableMessageHeader::GetSecondaryCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.secondaryMsgIdByteLocation + headerDef.secondaryMsgIdDataLen).ToString() + " for a header");
            }

            if (headerDef.secondaryMsgIdByteLocation == 0)
            {
               isSecondaryIdUsed = false;
               return 0;
            }
            else
            {
               isSecondaryIdUsed = true;

               uint cmdId = 0;

               if (headerDef.secondaryMsgIdDataLen == 1)
               {
                  byte* pCmdIdBytePtr = (byte*)pData.ToPointer() + headerDef.secondaryMsgIdByteLocation;

                  cmdId = pCmdIdBytePtr[0];
               }
               else if (headerDef.secondaryMsgIdDataLen == 2)
               {
                  ushort* pCmdIdUshortPtr = (ushort*)pData.ToPointer() + headerDef.secondaryMsgIdByteLocation;

                  ushort cmdIdTemp = (ushort)pCmdIdUshortPtr[0];

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

                  cmdId = cmdIdTemp;
               }
               else if (headerDef.secondaryMsgIdDataLen == 4)
               {
                  uint* pCmdIdUInttPtr = (uint*)pData.ToPointer() + headerDef.secondaryMsgIdByteLocation;

                  cmdId = (uint)pCmdIdUInttPtr[0];

                  if (shallWeSwap == true)
                  {
                     cmdId = Util.Swap(cmdId);
                  }
               }
               else
               {
                  throw new Exception("BitConfigurableMessageHeader::GetSecondaryCmdMessageId() - unhandled Cmd ID data length: " + headerDef.msgIdDataLen);
               }

               return cmdId;
            }
         }
      }

      /// <summary>
      /// getter for the message id
      /// </summary>
      /// <returns>The id</returns>
      private static uint GetCmdMessageId(IntPtr pData, uint numBytesInPdata)
      {
         unsafe
         {
            bool shallWeSwap = BitMsgEndianControl.Instance().ShallWeSwap();

            BitMsgEndianControl.HeaderDef headerDef = BitMsgEndianControl.Instance().GetHeaderDef();

            // is there enough data?
            if (numBytesInPdata <= headerDef.msgIdByteLocation + headerDef.msgIdDataLen)
            {
               ErrorLogger.Instance().Write("BitConfigurableMessageHeader::GetCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.msgIdByteLocation + headerDef.msgIdDataLen).ToString() + " for a header", ErrorLogger.LogLevel.INFO);
               throw new Exception("BitConfigurableMessageHeader::GetCmdMessageId() - not enough data form a header. Buffer contained " + Convert.ToString(numBytesInPdata) + " bytes, needed " + (headerDef.msgIdByteLocation + headerDef.msgIdDataLen).ToString() + " for a header");
            }

            uint cmdId = 0;

            if (headerDef.msgIdDataLen == 1)
            {
               byte* pCmdIdBytePtr = (byte*)pData.ToPointer() + headerDef.msgIdByteLocation;

               cmdId = pCmdIdBytePtr[0];
            }
            else if (headerDef.msgIdDataLen == 2)
            {
               ushort* pCmdIdUshortPtr = (ushort*)pData.ToPointer() + headerDef.msgIdByteLocation;

               ushort cmdIdTemp = (ushort)pCmdIdUshortPtr[0];

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

               cmdId = cmdIdTemp;
            }
            else if (headerDef.msgIdDataLen == 4)
            {
               uint* pCmdIdUInttPtr = (uint*)pData.ToPointer() + headerDef.msgIdByteLocation;

               cmdId = (uint)pCmdIdUInttPtr[0];

               if (shallWeSwap == true)
               {
                  cmdId = Util.Swap(cmdId);
               }
            }
            else
            {
               throw new Exception("BitConfigurableMessageHeader::GetCmdMessageId() - unhandled Cmd ID data length: " + headerDef.msgIdDataLen);
            }

            return cmdId;
         }
      }

      /// <summary>
      /// Getter for the header length
      /// The Header is considered to be all of the data up to the message ID
      /// </summary>
      /// <returns>The header length in bytes. The head Length is the number of bytes from the beginning of the message through the message ID</returns>
      public static uint GetHeaderSize()
      {
         BitMsgEndianControl.HeaderDef headerDef = BitMsgEndianControl.Instance().GetHeaderDef();

         int idSize = headerDef.msgIdByteLocation + headerDef.msgIdDataLen;

         return (uint)idSize;
      }

      #endregion
   }
}
