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

namespace FpgaMeasurementInstrumentsLib
{
   /// <summary>
   /// An abstract base class for FPGARspMessages that go between the client and server
   /// </summary>
   internal abstract class FPGARspMessage : ICloneable
   {
      #region PrivateClassMembers
      protected FPGARspMessageHeader m_header;
      private readonly string m_description;
      #endregion

      #region PrivateFunctions

      /// <summary>
      /// The constructor that the children will call
      /// </summary>
      /// <param name="commandType">The message id</param>
      /// <param name="description">The message description</param>
      protected FPGARspMessage(FPGARspMsgIds commandType, string description)
      {
         try
         {
            m_description = description;
            m_header = new FPGARspMessageHeader(commandType);
         }
         catch (Exception)
         {
            throw;
         }
      }

      /// <summary>
      /// Copy Constructor
      /// </summary>
      /// <param name="FPGARspMessage">The FPGARspMessage to copy from</param>
      protected FPGARspMessage(FPGARspMessage FPGARspMessage)
      {
         try
         {
            m_header = new FPGARspMessageHeader(FPGARspMessage.m_header);
            m_description = FPGARspMessage.m_description;
         }
         catch (Exception)
         {
            throw;
         }
      }

      /// <summary>
      /// A function to create a copy of the object for all children to implement
      /// </summary>
      /// <returns></returns>
      protected abstract object CloneSelf();

      /// <summary>
      /// A function to encode data for sending
      /// </summary>
      /// <param name="pData">A pointer to the spot to put the encoded data</param>
      protected abstract void FormatData(IntPtr pData);

      /// <summary>
      /// Get the size of the payload
      /// </summary>
      /// <returns>The size of the message payload</returns>
      protected abstract int GetPayloadSize();

      /// <summary>
      /// A function to decode data that was received
      /// </summary>
      /// <param name="pData">A pointer to the data to decode</param>
      protected abstract void ParseData(IntPtr pData);
      #endregion

      #region PublicFunctions

      /// <summary>
      /// Get a copy of the FPGARspMessage object
      /// </summary>
      /// <returns></returns>
      public object Clone()
      {
         // tell the child to clone itself
         return this.CloneSelf();
      }

      /// <summary>
      /// Encode the FPGARspMessage into a byte array for sending
      /// </summary>
      /// <param name="pData">The buffer to put the FPGARspMessage items</param>
      public void Format(IntPtr pData)
      {
         try
         {
            m_header.Format(pData);

            IntPtr pPayload = IntPtr.Add(pData, (int)GetHeaderLength());

            // ask child class to format its data
            FormatData(pPayload);
         }
         catch (Exception)
         {
            throw;
         }
      }

      /// <summary>
      /// A getter function for the children to implement
      /// </summary>
      /// <returns>The address that was read</returns>
      public abstract uint GetAddress();

      /// <summary>
      /// A getter function for the children to implement
      /// </summary>
      /// <returns>The data that was read</returns>
      public abstract uint GetData();

      /// <summary>
      /// Getter for this message description
      /// </summary>
      /// <returns>The description</returns>
      public string GetDescription()
      {
         return m_description;
      }

      /// <summary>
      /// Getter for the number of bytes in the entire message
      /// </summary>
      /// <returns>The number of bytes in the FPGARspMessage, including header</returns>
      public uint GetEntireMsgLength()
      {
         return GetHeaderLength() + (uint)GetPayloadSize();
      }

      /// <summary>
      /// getter for the number of bytes in the header
      /// </summary>
      /// <returns>The number of bytes in the head</returns>
      public uint GetHeaderLength()
      {
         return m_header.GetHeaderLength();
      }

      /// <summary>
      /// Takes an array of bytes and populates the FPGARspMessage object
      /// </summary>
      /// <param name="pData">The FPGARspMessage in byte form</param>
      public void Parse(IntPtr pData)
      {
         try
         {
            m_header.Parse(pData);

            IntPtr pPayLoad = IntPtr.Add(pData, (int)GetHeaderLength());

            ParseData(pPayLoad);
         }
         catch (Exception)
         {
            throw;
         }
      }

      /// <summary>
      /// Convert this FPGARspMessage into string form
      /// </summary>
      /// <returns>The FPGARspMessage in string form</returns>
      public override string ToString()
      {
         return "Description: " + GetDescription() + "\n" + m_header.ToString();
      }
      #endregion

   }
}
