//                           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;
using System.Runtime.InteropServices;

namespace Raytheon.Instruments
{
	/// <summary>
	/// Singleton sending out messages
	/// </summary>
	internal class CommUtil
	{
		// class variables
		private static CommUtil _commUtilInstance;

		/// <summary>
		/// Getter for this singleton
		/// </summary>
		/// <param name="filename"></param>
		/// <returns>The instance of this class</returns>
		public static CommUtil Instance()
		{
			if (_commUtilInstance == null)
			{
				_commUtilInstance = new CommUtil();
			}
			return _commUtilInstance;
		}

		/// <summary>
		/// Sends a message and gets a response
		/// </summary>
		/// <param name="commNode">The communication interface</param>
		/// <param name="commandMsg">The message to send</param>
		/// <param name="rspMsg">The response that is received</param>
		/// <param name="timeoutInMs">The amount of time in ms to wait for the response</param>
		public void SendCommandGetResponse(ICommDevice commNode, AutomationMessage commandMsg, ref AutomationMessage rspMsg, int timeoutInMs = 5000)
		{
			// send the command
			byte[] dataToSend = new byte[commandMsg.GetEntireMsgLength()];

			// format the data
			GCHandle pinnedArray = GCHandle.Alloc(dataToSend, GCHandleType.Pinned);
			IntPtr pByte = pinnedArray.AddrOfPinnedObject();
			commandMsg.Format(pByte);
			pinnedArray.Free();

			uint numWritten = commNode.Write(dataToSend, (uint)dataToSend.Length);


			if (numWritten != (uint)dataToSend.Length)
			{
				throw new Exception("CommUtil::SendCommandGetResponse NumBytesWritten does not match: numWritten " + numWritten + " and dataToSend.Length " + dataToSend.Length);
			}

			// wait for the response
			AutomationRxMsgBuffer rxBuffer = AutomationRxMsgBuffer.Instance();
			uint respMsgId = rspMsg.GetMessageId();
			bool didWeReceiveTheResponse = rxBuffer.WaitForRspMsg(respMsgId, timeoutInMs);

			if (didWeReceiveTheResponse == false)
			{
				throw new Exception("did not receive " + rspMsg.GetDescription());
			}

			rspMsg = rxBuffer.GetNewestMessage(respMsgId);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commNode"></param>
		/// <param name="commandMsg"></param>
		public void SendCommand(ICommDevice commNode, AutomationMessage commandMsg)
		{
			// send the command
			byte[] dataToSend = new byte[commandMsg.GetEntireMsgLength()];

			// format the data
			GCHandle pinnedArray = GCHandle.Alloc(dataToSend, GCHandleType.Pinned);
			IntPtr pByte = pinnedArray.AddrOfPinnedObject();
			commandMsg.Format(pByte);
			pinnedArray.Free();
			commNode.Write(dataToSend, (uint)dataToSend.Length);
		}
	}
}
