//                           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;
using System.Threading;
using System.Collections.Generic;
using Raytheon.Common;

namespace BitMeasurementManagerLib
{
   /// <summary>
   /// Singleton for holding onto message objects
   /// </summary>
   internal class BitMsgRxBuffer
   {
      #region PrivateClassMembers
      // class variables
      private static BitMsgRxBuffer _msgBufferInstance;
      private static object _syncObj = new Object();
      private BitMessageIDs _messageIds;
      private Dictionary<uint, List<BitConfigurableMessage>> _msgList;
      private Dictionary<uint, AutoResetEvent> _receivedMsgEvents;
      #endregion

      #region PrivateFuctions

      /// <summary>
      /// The constructor
      /// </summary>
      private BitMsgRxBuffer(BitMessageIDs messageIds)
      {
         _messageIds = messageIds;

         _msgList = new Dictionary<uint, List<BitConfigurableMessage>>();

         // create an event for each msg.
         _receivedMsgEvents = new Dictionary<uint, AutoResetEvent>();

         List<uint> msgIds = _messageIds.GetAllIds();

         foreach (uint id in msgIds)
         {
            _receivedMsgEvents[id] = new AutoResetEvent(false);
         }
      }
      #endregion

      #region PublicFuctions

      /// <summary>
      /// The way to get access to this singleton
      /// </summary>
      /// <returns>the instance to this class</returns>
      internal static BitMsgRxBuffer Instance(BitMessageIDs messageIds = null)
      {
         if (_msgBufferInstance == null)
         {
            _msgBufferInstance = new BitMsgRxBuffer(messageIds);
         }

         return _msgBufferInstance;
      }

      /// <summary>
      /// Add a message to this buffer
      /// </summary>
      /// <param name="msg">The message to add</param>
      /// <param name="shouldWeDeleteOthers">flag for if the other messages of this type should be deleted from the buffer</param>
      internal void AddMsg(BitConfigurableMessage msg, bool shouldWeDeleteOthers = true)
      {
         lock (_syncObj)
         {
            uint msgId = msg.GetMessageId();

            if (shouldWeDeleteOthers == true)
            {
               ErrorLogger.Instance().Write("BitMsgRxBuffer::AddMsg() - clearing list for  " + msgId.ToString(), ErrorLogger.LogLevel.INFO);
               ClearList(msgId);
            }

            if (_msgList.ContainsKey(msgId) == false)
            {
               ErrorLogger.Instance().Write("BitMsgRxBuffer::AddMsg() - creating new list for  " + msgId.ToString(), ErrorLogger.LogLevel.INFO);
               _msgList[msgId] = new List<BitConfigurableMessage>();
            }

            ErrorLogger.Instance().Write("BitMsgRxBuffer::AddMsg() - Adding " + msgId.ToString() + " to the list", ErrorLogger.LogLevel.INFO);
            _msgList[msgId].Add(msg);

            _receivedMsgEvents[msgId].Set();
         }
      }

      /// <summary>
      /// Remove all messages from the buffer
      /// </summary>
      internal void ClearAllMsgs()
      {
         lock (_syncObj)
         {
            foreach (uint id in _msgList.Keys)
            {
               ClearList(id);
            }
         }
      }

      /// <summary>
      /// Remove all messages of the command type from the buffer
      /// </summary>
      /// <param name="id">The message id to remove</param>
      internal void ClearList(uint id)
      {
         lock (_syncObj)
         {
            if (_msgList.ContainsKey(id) == true)
            {
               _msgList[id].Clear();

               _msgList.Remove(id);

               _receivedMsgEvents[id].Reset();
            }
         }
      }

      /// <summary>
      /// Gets the oldest message in the buffer
      /// </summary>
      /// <param name="id">The id of the message to get</param>
      /// <returns>The oldest message in the buffer</returns>
      internal BitConfigurableMessage GetOldestMessage(uint id)
      {
         lock (_syncObj)
         {
            if (_msgList.ContainsKey(id))
            {
               List<BitConfigurableMessage> list = _msgList[id];

               if (list.Count == 0)
               {
                  throw new Exception("BitMsgRxBuffer::GetOldestMessage() - there are no messges in the queue for id: " + id.ToString());
               }

               BitConfigurableMessage oldestMsg = list[0];

               list.RemoveAt(0);

               return oldestMsg;
            }
            else
            {
               throw new Exception("BitMsgRxBuffer::GetOldestMessage() - no message exists with id: " + id.ToString());
            }
         }
      }

      /// <summary>
      /// Gets the most recent message from the buffer
      /// </summary>
      /// <param name="id">The id of the message to get</param>
      /// <param name="shouldWeDeleteOthers">flag controlling if the other messages of this type should be deleted</param>
      /// <returns>The message</returns>
      internal BitConfigurableMessage GetNewestMessage(uint id, bool shouldWeDeleteOthers = true)
      {
         lock (_syncObj)
         {
            if (_msgList.ContainsKey(id))
            {
               List<BitConfigurableMessage> list = _msgList[id];

               BitConfigurableMessage newestMsg = list[list.Count - 1];

               list.RemoveAt(list.Count - 1);

               if (shouldWeDeleteOthers == true)
               {
                  ClearList(id);
               }

               return newestMsg;
            }
            else
            {
               throw new Exception("BitMsgRxBuffer::GetNewestMessage() - no message exists with id: " + id.ToString("X"));
            }
         }
      }

      /// <summary>
      /// Get the number of messages of this type in the buffer
      /// </summary>
      /// <param name="id">The id of the message to get</param>
      /// <returns>the number of messages of this type in the buffer</returns>
      internal int GetNumMsgsInQueue(uint id)
      {
         lock (_syncObj)
         {
            if (_msgList.ContainsKey(id) == true)
            {
               return _msgList[id].Count;
            }
            else
            {
               return 0;
            }
         }
      }

      /// <summary>
      /// 
      /// </summary>
      internal void ResetReceiveEvent(uint id)
      {
         lock (_syncObj)
         {
            _receivedMsgEvents[id].Reset();
         }
      }

      /// <summary>
      /// Wait for a message to get added to the buffer
      /// </summary>
      /// <param name="id">The message id to wait for</param>
      /// <param name="timeoutMs">The amount of time in ms to wait</param>
      /// <returns>true if the message arrived, false if it did not</returns>
      internal bool WaitForRspMsg(uint id, uint timeoutMs)
      {
         return _receivedMsgEvents[id].WaitOne((int)timeoutMs);
      }
      #endregion

   }
}
