//                           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 Raytheon.Instruments;
using Raytheon.Units;
using Raytheon.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace MeasurementManagerLib
{
   /// <summary>
   /// This class manages RF instruments and provides an abstraction
   /// </summary>
   public class RfMeasurementManager : IDisposable
	{
		#region PrivateClassMembers
		private struct SpecAnMeasurementFields
		{
			public List<string> _relays;
			public SpecAnAveragingType _avgType;
			public int _numAverages;
			public int _rbw;
			public int _vbw;
			public int _centerFreq;
			public int _span;
			//public int _referanceLevel;
			public int _attenuation;
			public int _delay;

			public SpecAnMeasurementFields(List<string> relays, SpecAnAveragingType avgType, int numAverages, int rbw, int vbw, int centerFreq, int span, /*int referanceLevel,*/ int attenuation, int delay)
			{
				_relays = relays;
				_avgType = avgType;
				_numAverages = numAverages;
				_rbw = rbw;
				_vbw = vbw;
				_centerFreq = centerFreq;
				_span = span;
				//_referanceLevel = referanceLevel;
				_attenuation = attenuation;
				_delay = delay;
			}
		}

		private struct PowerMeterPowerMeasurementFields
		{
			public List<string> _relays;
			public readonly int _channel;
			public readonly int _freq;
			public readonly int _delay;

			public PowerMeterPowerMeasurementFields(List<string> relays, int channel, int frequency, int delay)
			{
				_relays = relays;
				_channel = channel;
				_freq = frequency;
				_delay = delay;
			}
		}

		private struct SignalGeneratorMeasurementFields
		{
			public List<string> _relays;
			public readonly int _powerLevel;
			public readonly int _freq;
			public readonly int _delay;

			public SignalGeneratorMeasurementFields(List<string> relays, int powerLevel, int frequency, int delay)
			{
				_relays = relays;
				_powerLevel = powerLevel;
				_freq = frequency;
				_delay = delay;
			}
		}

		private static object _syncObj = new Object();
		private Dictionary<string, Raytheon.Instruments.ISwitch> _switchCards;
		private IPowerMeter _powerMeter;
		private ISignalGenerator _sigGen;
		private ISpecAnalyzer _specAn;
		private Dictionary<string, PowerMeterPowerMeasurementFields> _powerMeterPowerMeasurements;
		private Dictionary<string, SignalGeneratorMeasurementFields> _signalGeneratorMeasurements;
		private Dictionary<string, SpecAnMeasurementFields> _specAnMeasurements;

      private static NLog.ILogger _logger;
      #endregion

      #region PrivateClassFunctions

      /// <summary>
      /// The Finalizer
      /// </summary>
      ~RfMeasurementManager()
		{
			Dispose(false);
		}

		/// <summary>
		/// Confirm each relay entry in the measurement file refers back to a card in the instrument file
		/// </summary>
		private void CheckForValidRelayFormat()
		{
			foreach (KeyValuePair<string, PowerMeterPowerMeasurementFields> entry in _powerMeterPowerMeasurements)
			{
				List<string> relays = entry.Value._relays;

				foreach (string relayDef in relays)
				{
					string[] relayInfo = relayDef.Split('-');
					if (relayInfo.Length != 2)
					{
						throw new Exception("Power Meter measurement relay format is not correct: " + relayDef);
					}

					if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
					{
						throw new Exception("Power Meter measurement relay card field does not exist: " + relayInfo[0]);
					}
				}
			}

			foreach (KeyValuePair<string, SignalGeneratorMeasurementFields> entry in _signalGeneratorMeasurements)
			{
				List<string> relays = entry.Value._relays;

				foreach (string relayDef in relays)
				{
					string[] relayInfo = relayDef.Split('-');
					if (relayInfo.Length != 2)
					{
						throw new Exception("Sig Gen measurement relay format is not correct: " + relayDef);
					}

					if (_switchCards.ContainsKey(relayInfo[0].ToUpper()) == false)
					{
						throw new Exception("Sig Gen  measurement relay card field does not exist: " + relayInfo[0]);
					}
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="disposing"></param>
		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (_powerMeter != null)
				{
					try
					{
						_powerMeter.Shutdown();
					}
					catch (Exception err)
					{
						_logger?.Error(err.Message + "\r\n" + err.StackTrace);
					}
				}

				if (_sigGen != null)
				{
					try
					{
						_sigGen.Shutdown();
					}
					catch (Exception err)
					{
						_logger?.Error(err.Message + "\r\n" + err.StackTrace);
					}
				}

				if (_specAn != null)
				{
					try
					{
						_specAn.Shutdown();
					}
					catch (Exception err)
					{
						_logger?.Error(err.Message + "\r\n" + err.StackTrace);
					}
				}

				foreach (KeyValuePair<string, ISwitch> switchCard in _switchCards)
				{
					if (_switchCards[switchCard.Key] != null)
					{
						try
						{
							_switchCards[switchCard.Key].Shutdown();
						}
						catch (Exception err)
						{
							_logger?.Error(err.Message + "\r\n" + err.StackTrace);
						}
					}
				}
			}
		}

		/// <summary>
		/// Parses the ini file for measurement definitions
		/// Populates the Dictionaries with the enum names and ini file data
		/// </summary>
		private void ParseMeasurementDef(ConfigurationFile configurationFile)
		{
			const string POWER_METER_MEASUREMENT = "PowerMeterReadPower";
			const string SIG_GEN_MEASUREMENT = "SignalGeneratorEnable";
			const string SPEC_AN_PEAK_AMP_MEASUREMENT = "SpecAnMeasurePeakAmplitude";
			const string SPEC_AN_PEAK_FREQ_MEASUREMENT = "SpecAnMeasurePeakFrequency";

			const char COMMA_DELIM = ',';

			const int INI_POWER_METER_RELAY_INDEX = 0;
			const int INI_POWER_METER_CHANNEL_NUM_INDEX = 1;
			const int INI_POWER_METER_FREQ_INDEX = 2;
			const int INI_POWER_METER_DELAY_INDEX = 3;

			const int INI_SIG_GEN_RELAY_INDEX = 0;
			const int INI_SIG_GEN_POWER_LEVEL_INDEX = 1;
			const int INI_SIG_GEN_FREQ_INDEX = 2;
			const int INI_SIG_GEN_DELAY_INDEX = 3;

			const int INI_SPEC_AN_RELAY_INDEX = 0;
			const int INI_SPEC_AN_AVG_TYPE_INDEX = 1;
			const int INI_SPEC_AN_NUM_AVG_TYPE_INDEX = 2;
			const int INI_SPEC_AN_RBW_INDEX = 3;
			const int INI_SPEC_AN_VBW_INDEX = 4;
			const int INI_SPEC_AN_CENTER_FREQ_INDEX = 5;
			const int INI_SPEC_AN_SPAN_INDEX = 6;
			//const int INI_SPEC_AN_REF_POWER_INDEX = 7;
			const int INI_SPEC_AN_ATTENUATION_INDEX = 7;
			const int INI_SPEC_AN_DELAY_INDEX = 8;

			// read in all of the sections
			List<string> sections = configurationFile.ReadAllSections();

			foreach (string section in sections)
			{
				if (section.ToUpper().Contains(POWER_METER_MEASUREMENT.ToUpper()))
				{
					List<string> keys = configurationFile.ReadAllKeys(section);
					foreach (string key in keys)
					{
						List<string> valueList = configurationFile.ReadList<string>(section, key);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_POWER_METER_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_POWER_METER_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}
						int channel = Convert.ToInt32(valueList[INI_POWER_METER_CHANNEL_NUM_INDEX]);
						int freq = Convert.ToInt32(valueList[INI_POWER_METER_FREQ_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_POWER_METER_DELAY_INDEX]);
						_powerMeterPowerMeasurements.Add(key.ToUpper(), new PowerMeterPowerMeasurementFields(relayList, channel, freq, delay));
					}
				}
				else if (section.ToUpper().Contains(SIG_GEN_MEASUREMENT.ToUpper()))
				{
					List<string> keys = configurationFile.ReadAllKeys(section);
					foreach (string key in keys)
					{
						List<string> valueList = configurationFile.ReadList<string>(section, key);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_SIG_GEN_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_SIG_GEN_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}
						int powLevel = Convert.ToInt32(valueList[INI_SIG_GEN_POWER_LEVEL_INDEX]);
						int freq = Convert.ToInt32(valueList[INI_SIG_GEN_FREQ_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_SIG_GEN_DELAY_INDEX]);
						_signalGeneratorMeasurements.Add(key.ToUpper(), new SignalGeneratorMeasurementFields(relayList, powLevel, freq, delay));
					}
				}
				else if (section.ToUpper().Contains(SPEC_AN_PEAK_AMP_MEASUREMENT.ToUpper()))
				{
					List<string> keys = configurationFile.ReadAllKeys(section);
					foreach (string key in keys)
					{
						List<string> valueList = configurationFile.ReadList<string>(section, key);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_SPEC_AN_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_SPEC_AN_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}

						SpecAnAveragingType avgType = (SpecAnAveragingType)Enum.Parse(typeof(SpecAnAveragingType), valueList[INI_SPEC_AN_AVG_TYPE_INDEX], true);
						int numAverages = Convert.ToInt32(valueList[INI_SPEC_AN_NUM_AVG_TYPE_INDEX]);
						int rbw = Convert.ToInt32(valueList[INI_SPEC_AN_RBW_INDEX]);
						int vbw = Convert.ToInt32(valueList[INI_SPEC_AN_VBW_INDEX]);
						int centerFreq = Convert.ToInt32(valueList[INI_SPEC_AN_CENTER_FREQ_INDEX]);
						int span = Convert.ToInt32(valueList[INI_SPEC_AN_SPAN_INDEX]);
						//int refPower = Convert.ToInt32(valueList[INI_SPEC_AN_REF_POWER_INDEX]);
						int attenuation = Convert.ToInt32(valueList[INI_SPEC_AN_ATTENUATION_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_SPEC_AN_DELAY_INDEX]);
						_specAnMeasurements.Add(key.ToUpper(), new SpecAnMeasurementFields(relayList, avgType, numAverages, rbw, vbw, centerFreq, span, /*refPower,*/ attenuation, delay));
					}
				}
				else if (section.ToUpper().Contains(SPEC_AN_PEAK_FREQ_MEASUREMENT.ToUpper()))
				{
					List<string> keys = configurationFile.ReadAllKeys(section);
					foreach (string key in keys)
					{
						List<string> valueList = configurationFile.ReadList<string>(section, key);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_SPEC_AN_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_SPEC_AN_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}

						SpecAnAveragingType avgType = (SpecAnAveragingType)Enum.Parse(typeof(SpecAnAveragingType), valueList[INI_SPEC_AN_AVG_TYPE_INDEX], true);
						int numAverages = Convert.ToInt32(valueList[INI_SPEC_AN_NUM_AVG_TYPE_INDEX]);
						int rbw = Convert.ToInt32(valueList[INI_SPEC_AN_RBW_INDEX]);
						int vbw = Convert.ToInt32(valueList[INI_SPEC_AN_VBW_INDEX]);
						int centerFreq = Convert.ToInt32(valueList[INI_SPEC_AN_CENTER_FREQ_INDEX]);
						int span = Convert.ToInt32(valueList[INI_SPEC_AN_SPAN_INDEX]);
						//int refPower = Convert.ToInt32(valueList[INI_SPEC_AN_REF_POWER_INDEX]);
						int attenuation = Convert.ToInt32(valueList[INI_SPEC_AN_ATTENUATION_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_SPEC_AN_DELAY_INDEX]);
						_specAnMeasurements.Add(key.ToUpper(), new SpecAnMeasurementFields(relayList, avgType, numAverages, rbw, vbw, centerFreq, span, /*refPower,*/ attenuation, delay));
					}
				}
			}
		}


		/// <summary>
		/// Parses the ini file for measurement definitions
		/// Populates the Dictionaries with the enum names and ini file data
		/// </summary>
		private void ParseMeasurementDef(string defFile)
		{
			const string POWER_METER_MEASUREMENT = "PowerMeterReadPower";
			const string SIG_GEN_MEASUREMENT = "SignalGeneratorEnable";
			const string SPEC_AN_PEAK_AMP_MEASUREMENT = "SpecAnMeasurePeakAmplitude";
			const string SPEC_AN_PEAK_FREQ_MEASUREMENT = "SpecAnMeasurePeakFrequency";

			const char BAR_DELIM = '|';
			const char COMMA_DELIM = ',';

			const int INI_POWER_METER_RELAY_INDEX = 0;
			const int INI_POWER_METER_CHANNEL_NUM_INDEX = 1;
			const int INI_POWER_METER_FREQ_INDEX = 2;
			const int INI_POWER_METER_DELAY_INDEX = 3;

			const int INI_SIG_GEN_RELAY_INDEX = 0;
			const int INI_SIG_GEN_POWER_LEVEL_INDEX = 1;
			const int INI_SIG_GEN_FREQ_INDEX = 2;
			const int INI_SIG_GEN_DELAY_INDEX = 3;

			const int INI_SPEC_AN_RELAY_INDEX = 0;
			const int INI_SPEC_AN_AVG_TYPE_INDEX = 1;
			const int INI_SPEC_AN_NUM_AVG_TYPE_INDEX = 2;
			const int INI_SPEC_AN_RBW_INDEX = 3;
			const int INI_SPEC_AN_VBW_INDEX = 4;
			const int INI_SPEC_AN_CENTER_FREQ_INDEX = 5;
			const int INI_SPEC_AN_SPAN_INDEX = 6;
			//const int INI_SPEC_AN_REF_POWER_INDEX = 7;
			const int INI_SPEC_AN_ATTENUATION_INDEX = 7;
			const int INI_SPEC_AN_DELAY_INDEX = 8;

			IniFile iniReader = new IniFile(defFile);

			// read in all of the sections
			List<string> sections = iniReader.ReadAllSections();

			foreach (string section in sections)
			{
				if (section.ToUpper().Contains(POWER_METER_MEASUREMENT.ToUpper()))
				{
					List<string> keys = iniReader.ReadAllKeys(section);
					foreach (string key in keys)
					{
						string value = iniReader.ReadValue(section, key);
						string[] valueList = value.Split(BAR_DELIM);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_POWER_METER_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_POWER_METER_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}
						int channel = Convert.ToInt32(valueList[INI_POWER_METER_CHANNEL_NUM_INDEX]);
						int freq = Convert.ToInt32(valueList[INI_POWER_METER_FREQ_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_POWER_METER_DELAY_INDEX]);
						_powerMeterPowerMeasurements.Add(key.ToUpper(), new PowerMeterPowerMeasurementFields(relayList, channel, freq, delay));
					}
				}
				else if (section.ToUpper().Contains(SIG_GEN_MEASUREMENT.ToUpper()))
				{
					List<string> keys = iniReader.ReadAllKeys(section);
					foreach (string key in keys)
					{
						string value = iniReader.ReadValue(section, key);
						string[] valueList = value.Split(BAR_DELIM);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_SIG_GEN_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_SIG_GEN_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}
						int powLevel = Convert.ToInt32(valueList[INI_SIG_GEN_POWER_LEVEL_INDEX]);
						int freq = Convert.ToInt32(valueList[INI_SIG_GEN_FREQ_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_SIG_GEN_DELAY_INDEX]);
						_signalGeneratorMeasurements.Add(key.ToUpper(), new SignalGeneratorMeasurementFields(relayList, powLevel, freq, delay));
					}
				}
				else if (section.ToUpper().Contains(SPEC_AN_PEAK_AMP_MEASUREMENT.ToUpper()))
				{
					List<string> keys = iniReader.ReadAllKeys(section);
					foreach (string key in keys)
					{
						string value = iniReader.ReadValue(section, key);
						string[] valueList = value.Split(BAR_DELIM);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_SPEC_AN_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_SPEC_AN_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}

						SpecAnAveragingType avgType = (SpecAnAveragingType)Enum.Parse(typeof(SpecAnAveragingType), valueList[INI_SPEC_AN_AVG_TYPE_INDEX], true);
						int numAverages = Convert.ToInt32(valueList[INI_SPEC_AN_NUM_AVG_TYPE_INDEX]);
						int rbw = Convert.ToInt32(valueList[INI_SPEC_AN_RBW_INDEX]);
						int vbw = Convert.ToInt32(valueList[INI_SPEC_AN_VBW_INDEX]);
						int centerFreq = Convert.ToInt32(valueList[INI_SPEC_AN_CENTER_FREQ_INDEX]);
						int span = Convert.ToInt32(valueList[INI_SPEC_AN_SPAN_INDEX]);
						//int refPower = Convert.ToInt32(valueList[INI_SPEC_AN_REF_POWER_INDEX]);
						int attenuation = Convert.ToInt32(valueList[INI_SPEC_AN_ATTENUATION_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_SPEC_AN_DELAY_INDEX]);
						_specAnMeasurements.Add(key.ToUpper(), new SpecAnMeasurementFields(relayList, avgType, numAverages, rbw, vbw, centerFreq, span, /*refPower,*/ attenuation, delay));
					}
				}
				else if (section.ToUpper().Contains(SPEC_AN_PEAK_FREQ_MEASUREMENT.ToUpper()))
				{
					List<string> keys = iniReader.ReadAllKeys(section);
					foreach (string key in keys)
					{
						string value = iniReader.ReadValue(section, key);
						string[] valueList = value.Split(BAR_DELIM);

						// support for no  relays (direct connect to scope)
						List<string> relayList = new List<string>();
						if (valueList[INI_SPEC_AN_RELAY_INDEX].Trim() == "")
						{
							// no relays, nothing to do
						}
						else
						{
							relayList = valueList[INI_SPEC_AN_RELAY_INDEX].Split(COMMA_DELIM).ToList();
						}

						for (int i = 0; i < relayList.Count; ++i)
						{
							relayList[i] = relayList[i].Trim();
						}

						SpecAnAveragingType avgType = (SpecAnAveragingType)Enum.Parse(typeof(SpecAnAveragingType), valueList[INI_SPEC_AN_AVG_TYPE_INDEX], true);
						int numAverages = Convert.ToInt32(valueList[INI_SPEC_AN_NUM_AVG_TYPE_INDEX]);
						int rbw = Convert.ToInt32(valueList[INI_SPEC_AN_RBW_INDEX]);
						int vbw = Convert.ToInt32(valueList[INI_SPEC_AN_VBW_INDEX]);
						int centerFreq = Convert.ToInt32(valueList[INI_SPEC_AN_CENTER_FREQ_INDEX]);
						int span = Convert.ToInt32(valueList[INI_SPEC_AN_SPAN_INDEX]);
						//int refPower = Convert.ToInt32(valueList[INI_SPEC_AN_REF_POWER_INDEX]);
						int attenuation = Convert.ToInt32(valueList[INI_SPEC_AN_ATTENUATION_INDEX]);
						int delay = Convert.ToInt32(valueList[INI_SPEC_AN_DELAY_INDEX]);
						_specAnMeasurements.Add(key.ToUpper(), new SpecAnMeasurementFields(relayList, avgType, numAverages, rbw, vbw, centerFreq, span, /*refPower,*/ attenuation, delay));
					}
				}
			}
		}

		/// <summary>
		/// Will command the switch cards close a specified list of relays
		/// </summary>
		/// <param name="relayList"></param>
		private void SwitchRelayClose(List<string> relayList)
		{
			foreach (string combo in relayList)
			{
				//break out the card and relay
				string[] cardRelay = combo.Split('-');
				string cardObject = cardRelay[0].Trim();
				string relay = cardRelay[1].Trim();

				//open the relays
				_switchCards[cardObject.ToUpper()].Connect(relay);
			}
		}

		/// <summary>
		/// Will command the switch card open all relays or the specified list of relays
		/// </summary>
		/// <param name="relayList">Optional list of relays to open</param>
		private void SwitchRelayOpen(List<string> relayList)
		{
			foreach (string combo in relayList)
			{
				//break out the card and relay
				string[] cardRelay = combo.Split('-');
				string cardObject = cardRelay[0].Trim();
				string relay = cardRelay[1].Trim();

				//open the relays
				_switchCards[cardObject.ToUpper()].Disconnect(relay);
			}
		}

		#endregion

		#region PublicClassFunctions

		public RfMeasurementManager(IInstrumentManager instrumentManager,
									List<string> switchInstrumentNames,
									string powerMeeterName,
									string signalGeneratorName,
									string specAnalyzerName,
									string configFileName = "")
		{

         _logger = LogManager.GetCurrentClassLogger();

			// initialize class members
			_powerMeterPowerMeasurements = new Dictionary<string, PowerMeterPowerMeasurementFields>(StringComparer.InvariantCultureIgnoreCase);
			_signalGeneratorMeasurements = new Dictionary<string, SignalGeneratorMeasurementFields>(StringComparer.InvariantCultureIgnoreCase);
			_specAnMeasurements = new Dictionary<string, SpecAnMeasurementFields>(StringComparer.InvariantCultureIgnoreCase);
			_switchCards = new Dictionary<string, ISwitch>();

			if(string.IsNullOrEmpty(configFileName))
			{
				configFileName = "RfMeasurementManager.xml";
			}

			ParseMeasurementDef(new ConfigurationFile(configFileName));

			foreach (string name in switchInstrumentNames)
			{
				_switchCards[name] = instrumentManager.GetInstrument<ISwitch>(name);
				_switchCards[name]?.Initialize();
			}

			if (!string.IsNullOrEmpty(powerMeeterName))
			{
				_powerMeter = instrumentManager.GetInstrument<IPowerMeter>(powerMeeterName);
				_powerMeter?.Initialize();
			}

			if (!string.IsNullOrEmpty(signalGeneratorName))
			{
				_sigGen = instrumentManager.GetInstrument<ISignalGenerator>(signalGeneratorName);
				_sigGen?.Initialize();
			}

			if (!string.IsNullOrEmpty(specAnalyzerName))
			{
				_specAn = instrumentManager.GetInstrument<ISpecAnalyzer>(specAnalyzerName);
				_specAn?.Initialize();
			}

			CheckForValidRelayFormat();
		}

		/// <summary>
		/// Dispose of this objects resources
		/// </summary>
		public void Dispose()
		{
			try
			{
				Dispose(true);

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

		/// <summary>
		/// A getter for the list of power measurements (as defined in the input def file)
		/// </summary>
		/// <returns>A list of power measurements</returns>
		public List<string> PowerMeterGetPowerMeasurementList()
		{
			lock (_syncObj)
			{
				List<string> measurements = new List<string>();

				foreach (KeyValuePair<string, PowerMeterPowerMeasurementFields> entry in _powerMeterPowerMeasurements)
				{
					measurements.Add(entry.Key);
				}

				return measurements;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="measurementName"></param>
		/// <returns></returns>
		public double PowerMeterReadPower(string measurementName)
		{
			// hold onto the relays for the catch
			List<string> measurementRelays = null;

			try
			{
				lock (_syncObj)
				{
					if (_powerMeterPowerMeasurements.ContainsKey(measurementName.ToUpper()) == false)
					{
						throw new Exception("could not find measurement: " + measurementName);
					}

					// grab the measurement params
					PowerMeterPowerMeasurementFields measurement = _powerMeterPowerMeasurements[measurementName.ToUpper()];

					measurementRelays = measurement._relays;

					// close the relays
					SwitchRelayClose(measurementRelays);

					bool ret = _powerMeter.SetFrequency(measurement._channel, Frequency.FromHertz(measurement._freq));

					if (ret == false)
					{
						throw new Exception("set frequency failed for measurement: " + measurementName);
					}

					// wait a bit
					Thread.Sleep(measurement._delay);

					// make the measurement
					double returnValue = _powerMeter.GetMeasurement(measurement._channel).Watts;

					return returnValue;
				}
			}
			catch (Exception)
			{
				throw;
			}
			finally
			{
				// open the relays
				if (measurementRelays != null)
				{
					SwitchRelayOpen(measurementRelays);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public void PowerMeterSelfTest()
		{

			lock (_syncObj)
			{
				SelfTestResult res = _powerMeter.PerformSelfTest();

				if (res != SelfTestResult.Pass)
				{
					throw new Exception("did not pass, the result was: " + res.ToString());
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="measurementName"></param>
		/// <returns></returns>
		public void SignalGeneratorDisable(string measurementName)
		{
			try
			{
				lock (_syncObj)
				{
					if (_signalGeneratorMeasurements.ContainsKey(measurementName.ToUpper()) == false)
					{
						throw new Exception("could not find measurement: " + measurementName);
					}

					// grab the measurement params
					SignalGeneratorMeasurementFields measurement = _signalGeneratorMeasurements[measurementName.ToUpper()];

					List<string> measurementRelays = measurement._relays;

					_sigGen.Enable(false);

					// wait a bit
					Thread.Sleep(measurement._delay);

					// close the relays
					SwitchRelayOpen(measurementRelays);
				}
			}
			catch (Exception)
			{
				throw;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="measurementName"></param>
		/// <returns></returns>
		public void SignalGeneratorEnable(string measurementName)
		{
			try
			{
				lock (_syncObj)
				{
					if (_signalGeneratorMeasurements.ContainsKey(measurementName.ToUpper()) == false)
					{
						throw new Exception("could not find measurement: " + measurementName);
					}

					// grab the measurement params
					SignalGeneratorMeasurementFields measurement = _signalGeneratorMeasurements[measurementName.ToUpper()];

					List<string> measurementRelays = measurement._relays;

					// close the relays
					SwitchRelayClose(measurementRelays);

					_sigGen.SetFrequency(new UnitizedValue(measurement._freq));

					_sigGen.SetPowerLevel(new UnitizedValue(measurement._powerLevel));

					// wait a bit
					Thread.Sleep(measurement._delay);

					_sigGen.Enable(true);
				}
			}
			catch (Exception)
			{
				throw;
			}
		}


		/// <summary>
		/// Sends a SCPI command to the Sig Gen and reads the response
		/// </summary>
		/// <param name="command">The SCPI command to send</param>
		/// <returns></returns>
		public string SignalGeneratorIOQuery(string command)
		{
			lock (_syncObj)
			{
				lock (_syncObj)
				{
					return _sigGen.IOQuery(command);
				}
			}
		}

		/// <summary>
		/// Sends a SCPI command to the Sig Gen
		/// </summary>
		/// <param name="command">The SCPI command to send</param>
		public void SignalGeneratorIOWrite(string command)
		{
			lock (_syncObj)
			{
				lock (_syncObj)
				{
					_sigGen.IOWrite(command);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public void SignalGeneratorSelfTest()
		{
			lock (_syncObj)
			{
				SelfTestResult res = _sigGen.PerformSelfTest();

				if (res != SelfTestResult.Pass)
				{
					throw new Exception("did not pass, the result was: " + res.ToString());
				}
			}
		}

		/// <summary>
		/// Sends a SCPI command to the Spec An and reads the response
		/// </summary>
		/// <param name="command">The SCPI command to send</param>
		/// <returns></returns>
		public string SpecAnIOQuery(string command, int timeout = 10000)
		{
			lock (_syncObj)
			{
				lock (_syncObj)
				{
					return _specAn.IOQuery(command, timeout);
				}
			}
		}

		/// <summary>
		/// Sends a SCPI command to the Spec An
		/// </summary>
		/// <param name="command">The SCPI command to send</param>
		public void SpecAnIOWrite(string command)
		{
			lock (_syncObj)
			{
				lock (_syncObj)
				{
					_specAn.IOWrite(command);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="measurementName"></param>
		/// <returns></returns>
		public double SpecAnMeasurePeakAmplitude(string measurementName)
		{
			// hold onto the relays for the catch
			List<string> measurementRelays = null;

			try
			{
				lock (_syncObj)
				{
					if (_specAnMeasurements.ContainsKey(measurementName.ToUpper()) == false)
					{
						throw new Exception("could not find measurement: " + measurementName);
					}

					// grab the measurement params
					SpecAnMeasurementFields measurement = _specAnMeasurements[measurementName.ToUpper()];

					measurementRelays = measurement._relays;

					// close the relays
					SwitchRelayClose(measurementRelays);

					_specAn.ConfigureAveraging(measurement._avgType, measurement._numAverages);

					_specAn.ConfigureBandwidth(measurement._rbw, measurement._vbw);

					_specAn.ConfigureFrequency(measurement._centerFreq, measurement._span);

					_specAn.ConfigurePowerLevel(/*measurement._referanceLevel,*/ measurement._attenuation);

					// wait a bit
					Thread.Sleep(measurement._delay);

					double amp = _specAn.MeasurePeakAmplitude();

					return amp;
				}
			}
			catch (Exception)
			{
				throw;
			}
			finally
			{
				// open the relays
				if (measurementRelays != null)
				{
					SwitchRelayOpen(measurementRelays);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="measurementName"></param>
		/// <returns></returns>
		public double SpecAnMeasurePeakFrequency(string measurementName)
		{
			// hold onto the relays for the catch
			List<string> measurementRelays = null;

			try
			{
				lock (_syncObj)
				{
					if (_specAnMeasurements.ContainsKey(measurementName.ToUpper()) == false)
					{
						throw new Exception("could not find measurement: " + measurementName);
					}

					// grab the measurement params
					SpecAnMeasurementFields measurement = _specAnMeasurements[measurementName.ToUpper()];

					measurementRelays = measurement._relays;

					// close the relays
					SwitchRelayClose(measurementRelays);

					_specAn.ConfigureAveraging(measurement._avgType, measurement._numAverages);

					_specAn.ConfigureBandwidth(measurement._rbw, measurement._vbw);

					_specAn.ConfigureFrequency(measurement._centerFreq, measurement._span);

					_specAn.ConfigurePowerLevel(/*measurement._referanceLevel,*/ measurement._attenuation);

					// wait a bit
					Thread.Sleep(measurement._delay);

					double freq = _specAn.MeasurePeakFrequency();

					return freq;
				}
			}
			catch (Exception)
			{
				throw;
			}
			finally
			{
				// open the relays
				if (measurementRelays != null)
				{
					SwitchRelayOpen(measurementRelays);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public void SpecAnSelfTest()
		{
			lock (_syncObj)
			{
				SelfTestResult res = _specAn.PerformSelfTest();

				if (res != SelfTestResult.Pass)
				{
					throw new Exception("did not pass, the result was: " + res.ToString());
				}
			}
		}

		#endregion
	}
}
