// **********************************************************************************************************
//    coeEndpoint.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.Runtime.InteropServices;

namespace Raytheon.Instruments.coeCSharp
{
    //
    //
    //
    // Endpoint
    //
    //
    //
    public class coeEndpoint : IDisposable
    {
        #region DLLImports
        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Create_Dynamic_With_Domain")]
        private static extern IntPtr OE_Endpoint_Create_Dynamic_With_Domain(IntPtr Name,
                                                                            coe.ScopeType Scope,
                                                                            IntPtr Router,
                                                                            uint Domain,
                                                                            uint MaximumTransmitMessages,
                                                                            uint MaximumReceiveMessages,
                                                                            uint MaximumTransmitMessageSize,
                                                                            uint MaximumReceiveMessageSize,
                                                                            IntPtr ApplicationContext,
                                                                            out coe.Status Status);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Delete")]
        private static extern coe.Status OE_Endpoint_Delete(IntPtr _obj);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Associate")]
        private static extern coe.Status OE_Endpoint_Associate(IntPtr _obj,
                                                               IntPtr Event,
                                                               TriggerType Trigger);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Send_Labeled")]
        private static extern coe.Status OE_Endpoint_Send_Labeled(IntPtr _obj,
                                                                  IntPtr Message,
                                                                  uint Options,
                                                                  uint Handling_Policy);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Peek")]
        private static extern coe.Status OE_Endpoint_Peek(IntPtr _obj,
                                                          out uint Message_Label,
                                                          out uint Message_Size,
                                                          out int Message_Priority);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Wait")]
        private static extern coe.Status OE_Endpoint_Wait(IntPtr _obj,
                                                          int Timeout);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Receive")]
        private static extern coe.Status OE_Endpoint_Receive(IntPtr _obj,
                                                             ref IntPtr Message,
                                                             uint Handling_Policy,
                                                             int Timeout,
                                                             IntPtr Source);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Register_Ex2")]
        private static extern coe.Status OE_Endpoint_Register_Ex2(IntPtr _obj,
                                                                  uint Label,
                                                        [MarshalAs(UnmanagedType.FunctionPtr)]
                                                                coe.CallBackDelegate callbackD);


        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Deregister")]
        private static extern coe.Status OE_Endpoint_Deregister(IntPtr _obj,
                                                               uint Label);

        [DllImport(coe.coeDLL, CallingConvention = CallingConvention.Cdecl, EntryPoint = "OE_Endpoint_Empty")]
        private static extern coe.Status OE_Endpoint_Empty(IntPtr _obj);

        #endregion

        public enum TriggerType : int
        {
            DATA_RECEIVED = 0,
            BUFFER_EMPTY = 1,
            DATA_DISCARDED = 2
        };

        private bool _disposed;
        private IntPtr _handle;
        private readonly coeEvent[] _events;
        private const int MaximumNumberOfEvents = 4;
        private int _numberOfEvents;

        // Constant to be used for a non-queued endpoint
        public const uint NON_QUEUED_SIZE = 0;

        public coeEndpoint(uint maxMessageSize, IntPtr router = default) : this(0, maxMessageSize, 0, router) { }
        public coeEndpoint(uint maxMessageSize, uint maxBufferMessages, IntPtr router = default)
           : this(0, maxMessageSize, maxBufferMessages, router) { }
        public coeEndpoint(uint domain, uint maxMessageSize, uint maxBufferMessages, IntPtr router = default)
        {
            _handle = OE_Endpoint_Create_Dynamic_With_Domain(IntPtr.Zero, coe.ScopeType.OE_Local, router, domain,
                                           maxBufferMessages, maxBufferMessages, maxMessageSize, maxMessageSize, IntPtr.Zero, out coe.Status oe_status);
            if (oe_status != coe.Status.SUCCESS)
            {
                _handle = IntPtr.Zero;
                throw new Exception("Unable to create OE_Endpoint.  Error = " + oe_status);
            }
            else
            {
                _numberOfEvents = 0;
                _events = new coeEvent[MaximumNumberOfEvents];
            }
        }

        ~coeEndpoint()
        {
            Dispose(false);
        }

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

        protected void Dispose(bool disposing)
        {
            if (_disposed) 
                return;

            if (disposing)
            {
            }
            if (_handle != IntPtr.Zero)
            {
                for (int index = 0; index < _numberOfEvents; index++)
                {
                    _events[index].Disable();
                }
                OE_Endpoint_Delete(_handle);
                _handle = IntPtr.Zero;
            }
            _disposed = true;
        }

        public IntPtr Handle
        {
            get { return _handle; }
        }

        public coe.Status Register(uint label)
        {
            coe.Status status = OE_Endpoint_Register_Ex2(_handle, label, null);
            return status;
        }

        public coe.Status Register(uint label, coeDataInterchange.FormatPacketType packet)
        {

            coe._dataInterchangePackets.Add(label, packet);
            coe.Status status = OE_Endpoint_Register_Ex2(_handle, label, coe._dataInterchangePackets._delegate);
            return status;
        }

        public coe.Status Deregister(uint label)
        {
            coe.Status status = OE_Endpoint_Deregister(_handle, label);
            return status;
        }

        public coe.Status Send(coeMessage message)
        {
            return Send(message, 0);
        }

        public coe.Status Send(coeMessage message, uint options)
        {
            message.Serialize();
            return OE_Endpoint_Send_Labeled(_handle, message.Handle, options, 0);
        }

        public coe.Status Peek(out uint message_Label,
                               out uint message_Size,
                               out int message_Priority)
        {
            coe.Status status;
            status = OE_Endpoint_Peek(_handle, out uint messageLabel, out uint messageSize, out int messagePriority);
            message_Label = messageLabel;
            message_Size = messageSize;
            message_Priority = messagePriority;
            return status;
        }

        public coe.Status Wait(int timeout)
        {
            return OE_Endpoint_Wait(_handle, timeout);
        }

        public coe.Status Clear()
        {
            return OE_Endpoint_Empty(_handle);
        }

        public coe.Status Receive(coeMessage message, int timeout)
        {
            coe.Status Status;
            IntPtr coeMessageHandle = message != null ? message.Handle : IntPtr.Zero;
            Status = OE_Endpoint_Receive(_handle, ref coeMessageHandle, 0, timeout, IntPtr.Zero);
            if (Status == coe.Status.SUCCESS)
            {
                message.Deserialize();
            }
            return Status;
        }

        public coe.Status Receive(coeMessage message)
        {
            return Receive(message, coe.OE_Wait_Forever);
        }

        public coe.Status Associate(coeEventFlag eventFlag, uint mask, TriggerType trigger)
        {
            coe.Status status;

            if (_numberOfEvents >= MaximumNumberOfEvents)
            {
                status = coe.Status.FAILED_INSUFFICIENT_RESOURCES;
            }
            else
            {
                _events[_numberOfEvents] = new coeEvent();
                _events[_numberOfEvents].SetNotification(eventFlag, mask);
                status = OE_Endpoint_Associate(_handle, _events[_numberOfEvents].Handle, trigger);
                if (status == coe.Status.SUCCESS)
                {
                    status = _events[_numberOfEvents].Enable();
                    _numberOfEvents++;
                }
            }
            return status;
        }
    }
}

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

