//>>***************************************************************************
//                              UNCLASSIFIED
//
//                COPYRIGHT 2017 RAYTHEON MISSILE SYSTEMS 
//                         ALL RIGHTS RESERVED
//   This data was developed pursuant to Contract Number HQ0147-12-C-0004/1088370
//     with the US Government. The US Government's rights in and to this 
//        copyrighted data are as specified in DFAR 252.227-7013 
//               which was made part of the above contract.
//
//    Distribution Statement: D -Distribution authorized to the DoD and DoD 
//       contractors only based on Critical Technology Requirements, May 2001.
//       Other requests shall be referred to PEO THEATER AIR DEFENSE (PMS 422).
//    Warning: - This document contains technical data whose export is restricted
//       by the Arms Export Control Act (Title 22, U.S.C.) or Export 
//       Administration Act of 1979, as amended (Title 50, U.S.C.). Violations 
//       of these laws are subject to severe criminal penalties. Disseminate in 
//       accordance with provisions of DoD 5230.25.
//    Destruction Notice: - For unclassified, limited distribution information, 
//       destroy by any method that will prevent disclosure of contents or 
//       reconstruction of the document. Classified information, destroy in 
//       accordance with DoD-5220.22-M or OPNAVINST 5510.1h.
//>>***************************************************************************

using System;
using VTI.VTEXSwitch.Interop;
using NLog;
using Raytheon.Common;

namespace Raytheon.Instruments
{
	/// <summary>
	/// This is a class for controlling a VTI EX1200-3001, 5002, 4264 switch card.
	/// It only supports individual relay mode at this time.
	/// </summary>
	public class SwitchVTI : ISwitch
	{
		#region PrivateMemberVariables
		private VTEXSwitch _switch;
		private string _name;
		private readonly string _address;
		private readonly string _options;
		private State _state;
		private SelfTestResult _selfTestResult;

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

		#endregion

		#region PrivateFunctions
		/// <summary>
		/// Finalizer.
		/// </summary>
		~SwitchVTI()
		{
			Dispose(false);
		}

		/// <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)
				{
					if (_state == State.Ready)
					{
						Reset();

						_switch.Close();

						_state = State.Uninitialized;
					}
				}
			}
			catch (Exception)
			{
				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>
		/// Perform self-test.
		/// </summary>
		private string SelfTest()
		{
			int testResult = 0;

			string selfTestMessage = "";

			_switch.Utility.SelfTest(ref testResult, ref selfTestMessage);

			if (testResult != 0)
			{
				throw new Exception("Self test returned an error code of: " + testResult.ToString() + ", and an error string of: " + selfTestMessage);
			}

			return selfTestMessage;
		}
		#endregion

		#region PublicFunctions

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

			_logger = logger;

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

			_address = _configuration.GetConfigurationValue("SwitchVTI", "Address", "");
			_options = _configuration.GetConfigurationValue("SwitchVTI", "Options", "");

			_state = State.Uninitialized;
			_selfTestResult = SelfTestResult.Unknown;
		}

		/// <summary>
		/// Constructor for RelaySwitch card.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="address">The address of the RelaySwitch.</param>
		/// <param name="options">The options used for setting up the instrument.</param>
		public SwitchVTI(string name, string address, string options)
		{
			_name = name;
			_logger = LogManager.GetCurrentClassLogger();
			_address = address;
			_options = options;

			// created in initialized
			_switch = null;

			_state = State.Uninitialized;
			_selfTestResult = SelfTestResult.Unknown;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public bool ClearErrors()
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// Close a single relay.
		/// The COTS library works on string inputs:
		///    - Ex Relay: "2!K1" Means card 2 relay 1.
		/// </summary>
		/// <param name="relay">The relay to close.</param>
		public void Connect(string path)
		{
			_switch.InstrumentSpecific.CloseRelays(path);
		}

		/// <summary>
		/// Open a single relay.
		/// The COTS library works on string inputs:
		///    - Ex Relay: "2!K1" Means card 2 relay 1.
		/// </summary>
		/// <param name="relay">The relay to open.</param>
		public void Disconnect(string path)
		{
			_switch.InstrumentSpecific.OpenRelays(path);
		}

		/// <summary>
		/// 
		/// </summary>
		public void DisconnectAll()
		{
			string relayList = _switch.InstrumentSpecific.ListOfRelays;

			_switch.InstrumentSpecific.OpenRelays(relayList);
		}

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

				GC.SuppressFinalize(this);
			}
			catch (Exception)
			{
				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 string DetailedStatus
		{
			get
			{
				return "This is a VTI Switch";
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool DisplayEnabled
		{
			get
			{
				throw new NotSupportedException();
			}

			set
			{
				throw new NotSupportedException();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool FrontPanelEnabled
		{
			get
			{
				throw new NotSupportedException();
			}

			set
			{
				throw new NotSupportedException();
			}
		}

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

		/// <summary>
		/// 
		/// </summary>
		public void Initialize()
		{
			if (_state == State.Uninitialized)
			{
				_switch = new VTEXSwitch();
				_switch.Initialize(_address, false, true, _options);
				_state = State.Ready;
			}
			else
			{
				throw new Exception("expected the state to be Uninitialized, state was: " + _state.ToString());
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool IsDebounced
		{
			get
			{
				throw new NotSupportedException();
			}
		}

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

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public SelfTestResult PerformSelfTest()
		{
			int testResult = 0;
			string result = "";
			_switch.Utility.SelfTest(ref testResult, ref result);

			// Set measurement input to backplane after performing self test.  Default is front panel.
			// _dmm.Measurement.In = VTEXDmmInputSelectEnum.VTEXDmmInputSelectInternal;

			if (testResult > 0)
			{
				_selfTestResult = Raytheon.Instruments.SelfTestResult.Fail;
				throw new Exception("self test failed with an Error Code: " + testResult + " and Error Message: " + result);
			}

			_selfTestResult = Raytheon.Instruments.SelfTestResult.Pass;

			return _selfTestResult;
		}

		/// <summary>
		/// 
		/// </summary>
		public void Reset()
		{
			_switch.Utility.Reset();
		}

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

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

		/// <summary>
		/// 
		/// </summary>
		public void Shutdown()
		{
			if (_state == State.Ready)
			{
				Reset();

				_switch.Close();

				_state = State.Uninitialized;
			}
		}
		#endregion
	}
}
