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

namespace Raytheon.Instruments
{
	/// <summary>
	/// A class that implements the Teradyne HSS Sub System Chassis
	/// </summary>
	public unsafe class CommFpgaHssubChassisSs : IFpgaComm
	{
		#region PrivateClassMembers
#pragma warning disable CS0649
		public struct CardInfo
		{
			internal string cardName;
			internal string cardAddress;
			internal int startingOffset;
			internal string cardFirmwareFile;
			internal string memMap;
		}
#pragma warning restore

		private static object _syncObj = new Object();

		private SortedDictionary<string, CommFpgaHssubCardSs> _hssCardNameMap;
		private List<CardInfo> _cardList;
		private SelfTestResult _selfTestResult;
		private State _state;
		private string _name;

		/// <summary>
		/// NLog logger
		/// </summary>
		private readonly ILogger _logger;
		/// <summary>
		/// Raytheon configuration
		/// </summary>
		private readonly IConfigurationManager _configurationManager;
		private readonly IConfiguration _configuration;

		#endregion

		#region PrivateFuctions

		/// <summary>
		/// The finalizer.
		/// </summary>
		~CommFpgaHssubChassisSs()
		{
			Dispose(false);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="cardName"></param>
		/// <param name="cardAddress"></param>
		/// <param name="cardOffset"></param>
		/// <param name="cardFirmwareFile"></param>
		private void CreateCard(string cardName, string cardAddress, int startingOffset, string cardFirmwareFile, string memMap)
		{
			lock (_syncObj)
			{
				// create the card
				CommFpgaHssubCardSs card = new CommFpgaHssubCardSs(cardName, cardAddress, startingOffset, cardFirmwareFile, memMap);

				// hold onto the card
				_hssCardNameMap[cardName] = card;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpgaName"></param>
		public void LoadFirmware(string fpgaName)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				_hssCardNameMap[fpgaName].LoadFirmware();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		private void SelfTest()
		{
			// loop through each card and command self test

			/*short testResults = -1;

			StringBuilder errorStrTemp = new StringBuilder(512);

			int ret = HssubNativeMethods.terHss_self_test(_chassisHandle, ref testResults, errorStrTemp);

			if (ret != 0)
			{
			   string errorStr = HssUtilTs.BuildErrorString(_chassisHandle, ret, _chassisLogicalName);

			   throw new Exception("terHss_self_test returned an error(" + ret + ")" + ": " + errorStr);
			}
			else if (testResults != 0)
			{
			   throw new Exception("HSSub Self Test returned an error: " + testResults.ToString() + ": " + errorStrTemp.ToString());
			}*/
		}

		/// <summary>
		/// Dispose of this object's resources.
		/// </summary>
		/// <param name="disposing">True = currently disposing, False = not disposing.</param>
		protected virtual void Dispose(bool disposing)
		{
			try
			{
				if (disposing)
				{
					lock (_syncObj)
					{
						if (_state == State.Ready)
						{
							foreach (KeyValuePair<string, CommFpgaHssubCardSs> entry in _hssCardNameMap)
							{
								entry.Value.Dispose();
							}

							_state = State.Uninitialized;
						}
					}
				}
			}
			catch (Exception err)
			{
				try
				{
					ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
				}
				catch (Exception)
				{
					//Do not rethrow. Exception from error logger that has already been garbage collected
				}
			}
		}
		#endregion

		#region PublicFuctions

		/// <summary>
		/// CommFpgaHssubChassisSs factory constructor
		/// </summary>
		/// <param name="deviceName"></param>
		/// <param name="configurationManager"></param>
		public CommFpgaHssubChassisSs(string deviceName, IConfigurationManager configurationManager, ILogger logger)
		{
			Name = deviceName;

			_logger = logger;

			_configurationManager = configurationManager;
			_configuration = _configurationManager.GetConfiguration(Name);

			_cardList = new List<CardInfo>();

			// hold onto the card objects
			_hssCardNameMap = new SortedDictionary<string, CommFpgaHssubCardSs>();

			_selfTestResult = SelfTestResult.Unknown;

			_state = State.Uninitialized;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="name"></param>
		public CommFpgaHssubChassisSs(string name)
		{
			_name = name;
			_logger = LogManager.GetCurrentClassLogger();
			_cardList = new List<CardInfo>();

			// hold onto the card objects
			_hssCardNameMap = new SortedDictionary<string, CommFpgaHssubCardSs>();

			_selfTestResult = SelfTestResult.Unknown;

			_state = State.Uninitialized;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="cardInfo"></param>
		public void AddCard(CardInfo cardInfo)
		{
			_cardList.Add(cardInfo);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public bool ClearErrors()
		{
			return false;
		}

		/// <summary>
		/// 
		/// </summary>
		public string DetailedStatus
		{
			get
			{
				return "This is a FPGA HSS Chassis SS " + _name;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool DisplayEnabled
		{
			get
			{
				return false;
			}

			set
			{
				throw new NotImplementedException();
			}
		}

		/// <summary>
		/// Dispose of this object's resources.
		/// </summary>
		public void Dispose()
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				try
				{
					Dispose(true);

					GC.SuppressFinalize(this);
				}
				catch (Exception err)
				{
					try
					{
						ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
					}
					catch (Exception)
					{
						//Do not rethrow. Exception from error logger that has already been garbage collected
					}
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool FrontPanelEnabled
		{
			get
			{
				return false;
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpga"></param>
		/// <returns></returns>
		public string GetMemMap(string fpga)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				return _hssCardNameMap[fpga].GetMemMap();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public InstrumentMetadata Info
		{
			get
			{
				throw new NotImplementedException();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void Initialize()
		{
			Initialize(string.Empty);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpga"></param>
		public void Initialize(string fpga)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				if (_state == State.Uninitialized)
				{
					// init each card
					for (int i = 0; i < _cardList.Count; i++)
					{
						CreateCard(_cardList[i].cardName, _cardList[i].cardAddress, _cardList[i].startingOffset, _cardList[i].cardFirmwareFile, _cardList[i].memMap);
					}

					_state = State.Ready;
				}
				else
				{
					throw new Exception("expected the state to be Uninitialized, state was: " + _state.ToString() + " on card " + _name);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string Name
		{
			get
			{
				return _name;
			}
			set { _name = value; }
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public SelfTestResult PerformSelfTest()
		{
			_selfTestResult = SelfTestResult.Unknown;
			return _selfTestResult;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpgaName"></param>
		/// <param name="address"></param>
		/// <returns></returns>
		public uint Read(string fpgaName, uint address)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				return _hssCardNameMap[fpgaName].Read(fpgaName, address);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpgaName"></param>
		/// <param name="address"></param>
		/// <param name="numberOfWordsToRead"></param>
		/// <param name="dataRead"></param>
		public void ReadBlock(string fpgaName, uint address, uint numberOfWordsToRead, bool shallWeIncrementAddress, ref uint[] dataRead)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				_hssCardNameMap[fpgaName].ReadBlock(fpgaName, address, numberOfWordsToRead, shallWeIncrementAddress, ref dataRead);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void Reset()
		{
			lock (_syncObj)
			{
				throw new NotImplementedException();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public SelfTestResult SelfTestResult
		{
			get
			{
				return _selfTestResult;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void Shutdown()
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				if (_state == State.Ready)
				{
					foreach (KeyValuePair<string, CommFpgaHssubCardSs> entry in _hssCardNameMap)
					{
						entry.Value.Dispose();
					}

					_state = State.Uninitialized;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public State Status
		{
			get
			{
				return _state;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpgaName"></param>
		/// <param name="address"></param>
		/// <param name="value"></param>
		public void Write(string fpgaName, uint address, uint value)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				_hssCardNameMap[fpgaName].Write(fpgaName, address, value);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fpgaName"></param>
		/// <param name="address"></param>
		/// <param name="numberOfWordsToWrite"></param>
		/// <param name="data"></param>
		/// <param name="shallWeIncrementAddress"></param>
		public void WriteBlock(string fpgaName, uint address, uint numberOfWordsToWrite, uint[] data, bool shallWeIncrementAddress)
		{
			// lock up the FPGA resource
			lock (_syncObj)
			{
				_hssCardNameMap[fpgaName].WriteBlock(fpgaName, address, numberOfWordsToWrite, data, shallWeIncrementAddress);
			}
		}

		#endregion

	}
}
