// **********************************************************************************************************
//    coeMessageFormatted.cs
//    6/1/2022
//    NGI - Next Generation Interceptor
//    
//    Contract No. HQ0856-21-C-0003/1022000209
//    
//    THIS DOCUMENT DOES NOT CONTAIN TECHNOLOGY OR TECHNICAL DATA CONTROLLED UNDER EITHER THE U.S. 
//    INTERNATIONAL TRAFFIC IN ARMS REGULATIONS OR THE U.S. EXPORT ADMINISTRATION REGULATIONS.
//    
//    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.
//    
//    UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//    
//    DESTRUCTION NOTICE: FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN DOD 5220.22-M, 
//    NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL, FEBRUARY 2006, 
//    INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5, SECTION 7, OR DODM 5200.01-VOLUME 3, 
//    DOD INFORMATION SECURITY PROGRAM: PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3, 
//    SECTION 17. FOR CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 5200.01-VOLUME 4, 
//    INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED INFORMATION.
//    
//    CONTROLLED BY: MISSILE DEFENSE AGENCY
//    CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE
//    CUI CATEGORY: CTI 
//    DISTRIBUTION/DISSEMINATION CONTROL: F 
//    POC: Alex Kravchenko (1118268)
// **********************************************************************************************************

//\\<Unclassified>
//----------------------------------------------------------------------------//
//                                 UNCLASSIFIED                               //
//----------------------------------------------------------------------------//
//\\<\Unclassified>

//\\<UnlimitedRights>
//----------------------------------------------------------------------------//
// Copyright %(copyright)s Raytheon Company.                                  //
// This software was developed pursuant to Contract Number %(contractNumber)s //
// with the U.S. government. The U.S. government's rights in and to this      //
// copyrighted software are as specified in DFARS 252.227-7014 which was made //
// part of the above contract.                                                //
//----------------------------------------------------------------------------//
//\\<\UnlimitedRights>

//\\<EximUndetermined>
//----------------------------------------------------------------------------//
// WARNING - This document contains technical data and / or technology whose  //
// export or disclosure to Non-U.S. Persons, wherever located, is restricted  //
// by the International Traffic in Arms Regulations (ITAR) (22 C.F.R.         //
// Section 120-130) or the Export Administration Regulations (EAR) (15 C.F.R. //
// Section 730-774). This document CANNOT be exported (e.g., provided to a    //
// supplier outside of the United States) or disclosed to a Non-U.S. Person,  //
// wherever located, until a final jurisdiction and classification            //
// determination has been completed and approved by Raytheon, and any         //
// required U.S. Government approvals have been obtained. Violations are      //
// subject to severe criminal penalties.                                      //
//----------------------------------------------------------------------------//
//\\<\EximUndetermined>

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Raytheon.Instruments.coeCSharp
{
    //
    //
    //
    // Message: formatted option; This class provides automatic serialization
    //          of all defined public members with an attribute describing the order and
    //          placement in the binary buffer in which the message fields will be serialized. 
    //          All members not defined as public or without a MessageOffset attribute will be 
    //          ignored during serialization.
    //
    //          Types currently supported include all scalar types and arrays of scalar types.
    //          Structures are also supported, which can contain single dimension arrays of scalar types.
    //          Structures can also be nested. The only restriction on all these elements is that arrays
    //          cannot contain structures, however, structures can contain arrays of scalar elements.
    //
    //          Specifying a 0 size will cause the constructor to try to automatically size the
    //          message buffer, however since fields are individually specified, this may cause
    //          difficulties in assuming what is actually needed. It is recommended that this
    //          class be manually specified as to its internal buffer size.
    //                    
    //          The same provision for arrays of classes that was described for the serialized option
    //          holds for the formatted option. All arrays of classes must have all objects in the array
    //          created with a new before sizing or serialization can be successfully done.
    //                    
    // Example:
    // 
    //  public class exampleMessage : coeMessageFormatted
    //  {
    //     [MessageOffset(0)] 
    //     public uint field1;
    //     [MessageOffset(4)]
    //     public ushort field2;
    //     [MessageOffset(6)]
    //     public ushort field3;
    //     [MessageOffset(8)]
    //     public uint field4;
    //     [MessageOffset(12)]
    //     public uint field5;
    //     [MessageOffset(16)]
    //     public uint field6;
    //     public exampleMessage(uint size) : base(size) { }
    //  }
    //
    //
    //
    public abstract class coeMessageFormatted : coeMessage, IDisposable
    {
        protected coeMessageFormatted(uint size) : this(size, 0) { }
        protected coeMessageFormatted(uint size, uint label) : this(size, label, 0) { }
        protected coeMessageFormatted(uint size, uint label, int priority) : base((int)size, label, priority) { }

        ~coeMessageFormatted()
        {
            Dispose(false);
        }

        new public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        new protected void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        private bool SerializeGetOffset(FieldInfo field, out int dataIndex)
        {
            MessageOffset offsetAttribute = null;
            dataIndex = 0;

            //
            //    The following line is for .NET 4.5 or later
            //
            // MessageOffset offsetAttribute = (MessageOffset)field.GetCustomAttribute(typeof(MessageOffset));
            //
            //    The following lines are for earlier versions of .NET
            var attributes = field.GetCustomAttributes(typeof(MessageOffset), true);
            if (attributes.Length > 0)
            {
                offsetAttribute = (MessageOffset)attributes[0];
            }
            //
            //
            if (offsetAttribute != null)
            {
                dataIndex = (int)offsetAttribute.Offset;
                return true;
            }
            else
            {
                return false;
            }
        }

        override public void Serialize()
        {
            uint dataSize = 0;
            int dataIndex = 0;
            FieldInfo[] fields = GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                if (SerializeGetOffset(field, out dataIndex))
                {
                    serializationSupport.serializeField(field, m_Buffer, ref dataIndex, this);
                    if (dataIndex > dataSize) dataSize = (uint)dataIndex;
                }
            }
            Size = dataSize;
            if (dataSize > 0)
            {
                Marshal.Copy(m_Buffer, 0, m_UnmanagedBuffer, (int)dataSize);
            }
        }

        override public void Deserialize()
        {
            byte[] data = copyFromMessageBuffer();
            int dataIndex = 0;
            FieldInfo[] fields = GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                if (SerializeGetOffset(field, out dataIndex))
                {
                    serializationSupport.deserializeField(field, data, ref dataIndex, this);
                }
            }
        }
    }
}

//\\<Unclassified>
//----------------------------------------------------------------------------//
//                                 UNCLASSIFIED                               //
//----------------------------------------------------------------------------//
//\\<\Unclassified>
